Commit | Line | Data |
---|---|---|
e98a2d6e | 1 | /* |
0235b0db | 2 | * SPDX-License-Identifier: MIT |
e98a2d6e | 3 | * |
0235b0db | 4 | * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
e98a2d6e | 5 | * |
0235b0db | 6 | * Common Trace Format Metadata Semantic Validator. |
e98a2d6e PP |
7 | */ |
8 | ||
c802cacb | 9 | #include <errno.h> |
0f5c5d5c | 10 | #include <unistd.h> |
c802cacb | 11 | |
c802cacb | 12 | #include "logging.hpp" |
41b60475 | 13 | |
578e048b | 14 | #include "common/list.h" |
c802cacb | 15 | |
087cd0f5 | 16 | #include "ast.hpp" |
e98a2d6e | 17 | |
4164020e | 18 | #define _bt_list_first_entry(ptr, type, member) bt_list_entry((ptr)->next, type, member) |
e98a2d6e | 19 | |
4164020e | 20 | static int _ctf_visitor_semantic_check(int depth, struct ctf_node *node, |
0f5c5d5c | 21 | const bt2c::Logger& logger); |
e98a2d6e | 22 | |
0f5c5d5c | 23 | static int ctf_visitor_unary_expression(int, struct ctf_node *node, const bt2c::Logger& logger) |
e98a2d6e | 24 | { |
4164020e SM |
25 | struct ctf_node *iter; |
26 | int is_ctf_exp = 0, is_ctf_exp_left = 0; | |
27 | ||
28 | switch (node->parent->type) { | |
29 | case NODE_CTF_EXPRESSION: | |
30 | is_ctf_exp = 1; | |
31 | bt_list_for_each_entry (iter, &node->parent->u.ctf_expression.left, siblings) { | |
32 | if (iter == node) { | |
33 | is_ctf_exp_left = 1; | |
34 | /* | |
35 | * We are a left child of a ctf expression. | |
36 | * We are only allowed to be a string. | |
37 | */ | |
38 | if (node->u.unary_expression.type != UNARY_STRING) { | |
0f5c5d5c SM |
39 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
40 | logger, node->lineno, | |
4164020e SM |
41 | "Left child of a CTF expression is only allowed to be a string."); |
42 | goto errperm; | |
43 | } | |
44 | break; | |
45 | } | |
46 | } | |
47 | /* Right child of a ctf expression can be any type of unary exp. */ | |
48 | break; /* OK */ | |
49 | case NODE_TYPE_DECLARATOR: | |
50 | /* | |
51 | * We are the length of a type declarator. | |
52 | */ | |
53 | switch (node->u.unary_expression.type) { | |
54 | case UNARY_UNSIGNED_CONSTANT: | |
55 | case UNARY_STRING: | |
56 | break; | |
57 | default: | |
0f5c5d5c SM |
58 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
59 | logger, node->lineno, | |
4164020e SM |
60 | "Children of field class declarator and `enum` can only be unsigned numeric constants or references to fields (e.g., `a.b.c`)."); |
61 | goto errperm; | |
62 | } | |
63 | break; /* OK */ | |
64 | ||
65 | case NODE_STRUCT: | |
66 | /* | |
67 | * We are the size of a struct align attribute. | |
68 | */ | |
69 | switch (node->u.unary_expression.type) { | |
70 | case UNARY_UNSIGNED_CONSTANT: | |
71 | break; | |
72 | default: | |
0f5c5d5c SM |
73 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
74 | logger, node->lineno, | |
4164020e SM |
75 | "Structure alignment attribute can only be an unsigned numeric constant."); |
76 | goto errperm; | |
77 | } | |
78 | break; | |
79 | ||
80 | case NODE_ENUMERATOR: | |
81 | /* The enumerator's parent has validated its validity already. */ | |
82 | break; /* OK */ | |
83 | ||
84 | case NODE_UNARY_EXPRESSION: | |
85 | /* | |
86 | * We disallow nested unary expressions and "sbrac" unary | |
87 | * expressions. | |
88 | */ | |
0f5c5d5c SM |
89 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
90 | "Nested unary expressions not allowed (`()` and `[]`)."); | |
4164020e SM |
91 | goto errperm; |
92 | ||
93 | case NODE_ROOT: | |
94 | case NODE_EVENT: | |
95 | case NODE_STREAM: | |
96 | case NODE_ENV: | |
97 | case NODE_TRACE: | |
98 | case NODE_CLOCK: | |
99 | case NODE_CALLSITE: | |
100 | case NODE_TYPEDEF: | |
101 | case NODE_TYPEALIAS_TARGET: | |
102 | case NODE_TYPEALIAS_ALIAS: | |
103 | case NODE_TYPEALIAS: | |
104 | case NODE_TYPE_SPECIFIER: | |
105 | case NODE_POINTER: | |
106 | case NODE_FLOATING_POINT: | |
107 | case NODE_INTEGER: | |
108 | case NODE_STRING: | |
109 | case NODE_ENUM: | |
110 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
111 | case NODE_VARIANT: | |
112 | default: | |
113 | goto errinval; | |
114 | } | |
115 | ||
116 | switch (node->u.unary_expression.link) { | |
117 | case UNARY_LINK_UNKNOWN: | |
118 | /* We don't allow empty link except on the first node of the list */ | |
119 | if (is_ctf_exp && | |
120 | _bt_list_first_entry(is_ctf_exp_left ? &node->parent->u.ctf_expression.left : | |
121 | &node->parent->u.ctf_expression.right, | |
122 | struct ctf_node, siblings) != node) { | |
0f5c5d5c SM |
123 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
124 | logger, node->lineno, | |
4164020e SM |
125 | "Empty link is not allowed except on first node of unary expression (need to separate nodes with `.` or `->`)."); |
126 | goto errperm; | |
127 | } | |
128 | break; /* OK */ | |
129 | case UNARY_DOTLINK: | |
130 | case UNARY_ARROWLINK: | |
131 | /* We only allow -> and . links between children of ctf_expression. */ | |
132 | if (node->parent->type != NODE_CTF_EXPRESSION) { | |
0f5c5d5c SM |
133 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
134 | logger, node->lineno, | |
135 | "Links `.` and `->` are only allowed as children of CTF expression."); | |
4164020e SM |
136 | goto errperm; |
137 | } | |
138 | /* | |
139 | * Only strings can be separated linked by . or ->. | |
140 | * This includes "", '' and non-quoted identifiers. | |
141 | */ | |
142 | if (node->u.unary_expression.type != UNARY_STRING) { | |
0f5c5d5c SM |
143 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
144 | logger, node->lineno, | |
4164020e SM |
145 | "Links `.` and `->` are only allowed to separate strings and identifiers."); |
146 | goto errperm; | |
147 | } | |
148 | /* We don't allow link on the first node of the list */ | |
149 | if (is_ctf_exp && | |
150 | _bt_list_first_entry(is_ctf_exp_left ? &node->parent->u.ctf_expression.left : | |
151 | &node->parent->u.ctf_expression.right, | |
152 | struct ctf_node, siblings) == node) { | |
0f5c5d5c SM |
153 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
154 | logger, node->lineno, | |
4164020e SM |
155 | "Links `.` and `->` are not allowed before first node of the unary expression list."); |
156 | goto errperm; | |
157 | } | |
158 | break; | |
159 | case UNARY_DOTDOTDOT: | |
160 | /* We only allow ... link between children of enumerator. */ | |
161 | if (node->parent->type != NODE_ENUMERATOR) { | |
0f5c5d5c SM |
162 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
163 | "Link `...` is only allowed within enumerator."); | |
4164020e SM |
164 | goto errperm; |
165 | } | |
166 | /* We don't allow link on the first node of the list */ | |
167 | if (_bt_list_first_entry(&node->parent->u.enumerator.values, struct ctf_node, siblings) == | |
168 | node) { | |
0f5c5d5c SM |
169 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
170 | logger, node->lineno, | |
4164020e SM |
171 | "Link `...` is not allowed on the first node of the unary expression list."); |
172 | goto errperm; | |
173 | } | |
174 | break; | |
175 | default: | |
0f5c5d5c SM |
176 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
177 | "Unknown expression link type: type={}", | |
178 | (int) node->u.unary_expression.link); | |
4164020e SM |
179 | return -EINVAL; |
180 | } | |
181 | return 0; | |
e98a2d6e PP |
182 | |
183 | errinval: | |
0f5c5d5c SM |
184 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
185 | logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}", | |
4164020e SM |
186 | node_type(node), node_type(node->parent)); |
187 | return -EINVAL; /* Incoherent structure */ | |
e98a2d6e PP |
188 | |
189 | errperm: | |
0f5c5d5c SM |
190 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
191 | "Semantic error: node-type={}, parent-node-type={}", | |
192 | node_type(node), node_type(node->parent)); | |
4164020e | 193 | return -EPERM; /* Structure not allowed */ |
e98a2d6e PP |
194 | } |
195 | ||
ecd7492f | 196 | static int ctf_visitor_field_class_specifier_list(int, struct ctf_node *node, |
0f5c5d5c | 197 | const bt2c::Logger& logger) |
e98a2d6e | 198 | { |
4164020e SM |
199 | switch (node->parent->type) { |
200 | case NODE_CTF_EXPRESSION: | |
201 | case NODE_TYPE_DECLARATOR: | |
202 | case NODE_TYPEDEF: | |
203 | case NODE_TYPEALIAS_TARGET: | |
204 | case NODE_TYPEALIAS_ALIAS: | |
205 | case NODE_ENUM: | |
206 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
207 | case NODE_ROOT: | |
208 | break; /* OK */ | |
209 | ||
210 | case NODE_EVENT: | |
211 | case NODE_STREAM: | |
212 | case NODE_ENV: | |
213 | case NODE_TRACE: | |
214 | case NODE_CLOCK: | |
215 | case NODE_CALLSITE: | |
216 | case NODE_UNARY_EXPRESSION: | |
217 | case NODE_TYPEALIAS: | |
218 | case NODE_TYPE_SPECIFIER: | |
219 | case NODE_TYPE_SPECIFIER_LIST: | |
220 | case NODE_POINTER: | |
221 | case NODE_FLOATING_POINT: | |
222 | case NODE_INTEGER: | |
223 | case NODE_STRING: | |
224 | case NODE_ENUMERATOR: | |
225 | case NODE_VARIANT: | |
226 | case NODE_STRUCT: | |
227 | default: | |
228 | goto errinval; | |
229 | } | |
230 | return 0; | |
e98a2d6e | 231 | errinval: |
0f5c5d5c SM |
232 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
233 | logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}", | |
4164020e SM |
234 | node_type(node), node_type(node->parent)); |
235 | return -EINVAL; /* Incoherent structure */ | |
e98a2d6e PP |
236 | } |
237 | ||
0f5c5d5c | 238 | static int ctf_visitor_field_class_specifier(int, struct ctf_node *node, const bt2c::Logger& logger) |
e98a2d6e | 239 | { |
4164020e SM |
240 | switch (node->parent->type) { |
241 | case NODE_TYPE_SPECIFIER_LIST: | |
242 | break; /* OK */ | |
243 | ||
244 | case NODE_CTF_EXPRESSION: | |
245 | case NODE_TYPE_DECLARATOR: | |
246 | case NODE_TYPEDEF: | |
247 | case NODE_TYPEALIAS_TARGET: | |
248 | case NODE_TYPEALIAS_ALIAS: | |
249 | case NODE_ENUM: | |
250 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
251 | case NODE_ROOT: | |
252 | case NODE_EVENT: | |
253 | case NODE_STREAM: | |
254 | case NODE_ENV: | |
255 | case NODE_TRACE: | |
256 | case NODE_CLOCK: | |
257 | case NODE_CALLSITE: | |
258 | case NODE_UNARY_EXPRESSION: | |
259 | case NODE_TYPEALIAS: | |
260 | case NODE_TYPE_SPECIFIER: | |
261 | case NODE_POINTER: | |
262 | case NODE_FLOATING_POINT: | |
263 | case NODE_INTEGER: | |
264 | case NODE_STRING: | |
265 | case NODE_ENUMERATOR: | |
266 | case NODE_VARIANT: | |
267 | case NODE_STRUCT: | |
268 | default: | |
269 | goto errinval; | |
270 | } | |
271 | return 0; | |
e98a2d6e | 272 | errinval: |
0f5c5d5c SM |
273 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
274 | logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}", | |
4164020e SM |
275 | node_type(node), node_type(node->parent)); |
276 | return -EINVAL; /* Incoherent structure */ | |
e98a2d6e PP |
277 | } |
278 | ||
4164020e | 279 | static int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node, |
0f5c5d5c | 280 | const bt2c::Logger& logger) |
e98a2d6e | 281 | { |
4164020e SM |
282 | int ret = 0; |
283 | struct ctf_node *iter; | |
284 | ||
285 | depth++; | |
286 | ||
287 | switch (node->parent->type) { | |
288 | case NODE_TYPE_DECLARATOR: | |
289 | /* | |
290 | * A nested field class declarator is not allowed to | |
291 | * contain pointers. | |
292 | */ | |
293 | if (!bt_list_empty(&node->u.field_class_declarator.pointers)) | |
294 | goto errperm; | |
295 | break; /* OK */ | |
296 | case NODE_TYPEALIAS_TARGET: | |
297 | break; /* OK */ | |
298 | case NODE_TYPEALIAS_ALIAS: | |
299 | /* | |
300 | * Only accept alias name containing: | |
301 | * - identifier | |
302 | * - identifier * (any number of pointers) | |
303 | * NOT accepting alias names containing [] (would otherwise | |
304 | * cause semantic clash for later declarations of | |
305 | * arrays/sequences of elements, where elements could be | |
306 | * arrays/sequences themselves (if allowed in field class alias). | |
307 | * NOT accepting alias with identifier. The declarator should | |
308 | * be either empty or contain pointer(s). | |
309 | */ | |
310 | if (node->u.field_class_declarator.type == TYPEDEC_NESTED) | |
311 | goto errperm; | |
312 | bt_list_for_each_entry (iter, | |
313 | &node->parent->u.field_class_alias_name.field_class_specifier_list | |
314 | ->u.field_class_specifier_list.head, | |
315 | siblings) { | |
316 | switch (iter->u.field_class_specifier.type) { | |
317 | case TYPESPEC_FLOATING_POINT: | |
318 | case TYPESPEC_INTEGER: | |
319 | case TYPESPEC_STRING: | |
320 | case TYPESPEC_STRUCT: | |
321 | case TYPESPEC_VARIANT: | |
322 | case TYPESPEC_ENUM: | |
323 | if (bt_list_empty(&node->u.field_class_declarator.pointers)) | |
324 | goto errperm; | |
325 | break; | |
326 | default: | |
327 | break; | |
328 | } | |
329 | } | |
330 | if (node->u.field_class_declarator.type == TYPEDEC_ID && | |
331 | node->u.field_class_declarator.u.id) | |
332 | goto errperm; | |
333 | break; /* OK */ | |
334 | case NODE_TYPEDEF: | |
335 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
336 | break; /* OK */ | |
337 | ||
338 | case NODE_ROOT: | |
339 | case NODE_EVENT: | |
340 | case NODE_STREAM: | |
341 | case NODE_ENV: | |
342 | case NODE_TRACE: | |
343 | case NODE_CLOCK: | |
344 | case NODE_CALLSITE: | |
345 | case NODE_CTF_EXPRESSION: | |
346 | case NODE_UNARY_EXPRESSION: | |
347 | case NODE_TYPEALIAS: | |
348 | case NODE_TYPE_SPECIFIER: | |
349 | case NODE_POINTER: | |
350 | case NODE_FLOATING_POINT: | |
351 | case NODE_INTEGER: | |
352 | case NODE_STRING: | |
353 | case NODE_ENUMERATOR: | |
354 | case NODE_ENUM: | |
355 | case NODE_VARIANT: | |
356 | case NODE_STRUCT: | |
357 | default: | |
358 | goto errinval; | |
359 | } | |
360 | ||
361 | bt_list_for_each_entry (iter, &node->u.field_class_declarator.pointers, siblings) { | |
0f5c5d5c | 362 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
363 | if (ret) |
364 | return ret; | |
365 | } | |
366 | ||
367 | switch (node->u.field_class_declarator.type) { | |
368 | case TYPEDEC_ID: | |
369 | break; | |
370 | case TYPEDEC_NESTED: | |
371 | { | |
372 | if (node->u.field_class_declarator.u.nested.field_class_declarator) { | |
373 | ret = _ctf_visitor_semantic_check( | |
0f5c5d5c | 374 | depth + 1, node->u.field_class_declarator.u.nested.field_class_declarator, logger); |
4164020e SM |
375 | if (ret) |
376 | return ret; | |
377 | } | |
378 | if (!node->u.field_class_declarator.u.nested.abstract_array) { | |
379 | bt_list_for_each_entry (iter, &node->u.field_class_declarator.u.nested.length, | |
380 | siblings) { | |
381 | if (iter->type != NODE_UNARY_EXPRESSION) { | |
0f5c5d5c SM |
382 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
383 | logger, node->lineno, "Expecting unary expression as length: node-type={}", | |
4164020e SM |
384 | node_type(iter)); |
385 | return -EINVAL; | |
386 | } | |
0f5c5d5c | 387 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
388 | if (ret) |
389 | return ret; | |
390 | } | |
391 | } else { | |
392 | if (node->parent->type == NODE_TYPEALIAS_TARGET) { | |
0f5c5d5c SM |
393 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
394 | logger, node->lineno, | |
4164020e SM |
395 | "Abstract array declarator not permitted as target of field class alias."); |
396 | return -EINVAL; | |
397 | } | |
398 | } | |
399 | if (node->u.field_class_declarator.bitfield_len) { | |
400 | ret = _ctf_visitor_semantic_check(depth + 1, | |
0f5c5d5c | 401 | node->u.field_class_declarator.bitfield_len, logger); |
4164020e SM |
402 | if (ret) |
403 | return ret; | |
404 | } | |
405 | break; | |
406 | } | |
407 | case TYPEDEC_UNKNOWN: | |
408 | default: | |
0f5c5d5c SM |
409 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
410 | "Unknown field class declarator: type={}", | |
411 | (int) node->u.field_class_declarator.type); | |
4164020e SM |
412 | return -EINVAL; |
413 | } | |
414 | depth--; | |
415 | return 0; | |
e98a2d6e PP |
416 | |
417 | errinval: | |
0f5c5d5c SM |
418 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
419 | logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}", | |
4164020e SM |
420 | node_type(node), node_type(node->parent)); |
421 | return -EINVAL; /* Incoherent structure */ | |
e98a2d6e PP |
422 | |
423 | errperm: | |
0f5c5d5c SM |
424 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
425 | "Semantic error: node-type={}, parent-node-type={}", | |
426 | node_type(node), node_type(node->parent)); | |
4164020e | 427 | return -EPERM; /* Structure not allowed */ |
e98a2d6e PP |
428 | } |
429 | ||
0f5c5d5c | 430 | static int _ctf_visitor_semantic_check(int depth, struct ctf_node *node, const bt2c::Logger& logger) |
e98a2d6e | 431 | { |
4164020e SM |
432 | int ret = 0; |
433 | struct ctf_node *iter; | |
434 | ||
435 | if (node->visited) | |
436 | return 0; | |
437 | ||
438 | switch (node->type) { | |
439 | case NODE_ROOT: | |
440 | bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) { | |
0f5c5d5c | 441 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
442 | if (ret) |
443 | return ret; | |
444 | } | |
445 | bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { | |
0f5c5d5c | 446 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
447 | if (ret) |
448 | return ret; | |
449 | } | |
450 | bt_list_for_each_entry (iter, &node->u.root.stream, siblings) { | |
0f5c5d5c | 451 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
452 | if (ret) |
453 | return ret; | |
454 | } | |
455 | bt_list_for_each_entry (iter, &node->u.root.event, siblings) { | |
0f5c5d5c | 456 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
457 | if (ret) |
458 | return ret; | |
459 | } | |
460 | break; | |
461 | ||
462 | case NODE_EVENT: | |
463 | switch (node->parent->type) { | |
464 | case NODE_ROOT: | |
465 | break; /* OK */ | |
466 | default: | |
467 | goto errinval; | |
468 | } | |
469 | ||
470 | bt_list_for_each_entry (iter, &node->u.event.declaration_list, siblings) { | |
0f5c5d5c | 471 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
472 | if (ret) |
473 | return ret; | |
474 | } | |
475 | break; | |
476 | case NODE_STREAM: | |
477 | switch (node->parent->type) { | |
478 | case NODE_ROOT: | |
479 | break; /* OK */ | |
480 | default: | |
481 | goto errinval; | |
482 | } | |
483 | ||
484 | bt_list_for_each_entry (iter, &node->u.stream.declaration_list, siblings) { | |
0f5c5d5c | 485 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
486 | if (ret) |
487 | return ret; | |
488 | } | |
489 | break; | |
490 | case NODE_ENV: | |
491 | switch (node->parent->type) { | |
492 | case NODE_ROOT: | |
493 | break; /* OK */ | |
494 | default: | |
495 | goto errinval; | |
496 | } | |
497 | ||
498 | bt_list_for_each_entry (iter, &node->u.env.declaration_list, siblings) { | |
0f5c5d5c | 499 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
500 | if (ret) |
501 | return ret; | |
502 | } | |
503 | break; | |
504 | case NODE_TRACE: | |
505 | switch (node->parent->type) { | |
506 | case NODE_ROOT: | |
507 | break; /* OK */ | |
508 | default: | |
509 | goto errinval; | |
510 | } | |
511 | ||
512 | bt_list_for_each_entry (iter, &node->u.trace.declaration_list, siblings) { | |
0f5c5d5c | 513 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
514 | if (ret) |
515 | return ret; | |
516 | } | |
517 | break; | |
518 | case NODE_CLOCK: | |
519 | switch (node->parent->type) { | |
520 | case NODE_ROOT: | |
521 | break; /* OK */ | |
522 | default: | |
523 | goto errinval; | |
524 | } | |
525 | ||
526 | bt_list_for_each_entry (iter, &node->u.clock.declaration_list, siblings) { | |
0f5c5d5c | 527 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
528 | if (ret) |
529 | return ret; | |
530 | } | |
531 | break; | |
532 | case NODE_CALLSITE: | |
533 | switch (node->parent->type) { | |
534 | case NODE_ROOT: | |
535 | break; /* OK */ | |
536 | default: | |
537 | goto errinval; | |
538 | } | |
539 | ||
540 | bt_list_for_each_entry (iter, &node->u.callsite.declaration_list, siblings) { | |
0f5c5d5c | 541 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
542 | if (ret) |
543 | return ret; | |
544 | } | |
545 | break; | |
546 | ||
547 | case NODE_CTF_EXPRESSION: | |
548 | switch (node->parent->type) { | |
549 | case NODE_ROOT: | |
550 | case NODE_EVENT: | |
551 | case NODE_STREAM: | |
552 | case NODE_ENV: | |
553 | case NODE_TRACE: | |
554 | case NODE_CLOCK: | |
555 | case NODE_CALLSITE: | |
556 | case NODE_FLOATING_POINT: | |
557 | case NODE_INTEGER: | |
558 | case NODE_STRING: | |
559 | break; /* OK */ | |
560 | ||
561 | case NODE_CTF_EXPRESSION: | |
562 | case NODE_UNARY_EXPRESSION: | |
563 | case NODE_TYPEDEF: | |
564 | case NODE_TYPEALIAS_TARGET: | |
565 | case NODE_TYPEALIAS_ALIAS: | |
566 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
567 | case NODE_TYPEALIAS: | |
568 | case NODE_TYPE_SPECIFIER: | |
569 | case NODE_TYPE_SPECIFIER_LIST: | |
570 | case NODE_POINTER: | |
571 | case NODE_TYPE_DECLARATOR: | |
572 | case NODE_ENUMERATOR: | |
573 | case NODE_ENUM: | |
574 | case NODE_VARIANT: | |
575 | case NODE_STRUCT: | |
576 | default: | |
577 | goto errinval; | |
578 | } | |
579 | ||
580 | depth++; | |
581 | bt_list_for_each_entry (iter, &node->u.ctf_expression.left, siblings) { | |
0f5c5d5c | 582 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
583 | if (ret) |
584 | return ret; | |
585 | } | |
586 | bt_list_for_each_entry (iter, &node->u.ctf_expression.right, siblings) { | |
0f5c5d5c | 587 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
588 | if (ret) |
589 | return ret; | |
590 | } | |
591 | depth--; | |
592 | break; | |
593 | case NODE_UNARY_EXPRESSION: | |
0f5c5d5c | 594 | return ctf_visitor_unary_expression(depth, node, logger); |
4164020e SM |
595 | |
596 | case NODE_TYPEDEF: | |
597 | switch (node->parent->type) { | |
598 | case NODE_ROOT: | |
599 | case NODE_EVENT: | |
600 | case NODE_STREAM: | |
601 | case NODE_TRACE: | |
602 | case NODE_VARIANT: | |
603 | case NODE_STRUCT: | |
604 | break; /* OK */ | |
605 | ||
606 | case NODE_CTF_EXPRESSION: | |
607 | case NODE_UNARY_EXPRESSION: | |
608 | case NODE_TYPEDEF: | |
609 | case NODE_TYPEALIAS_TARGET: | |
610 | case NODE_TYPEALIAS_ALIAS: | |
611 | case NODE_TYPEALIAS: | |
612 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
613 | case NODE_TYPE_SPECIFIER: | |
614 | case NODE_TYPE_SPECIFIER_LIST: | |
615 | case NODE_POINTER: | |
616 | case NODE_TYPE_DECLARATOR: | |
617 | case NODE_FLOATING_POINT: | |
618 | case NODE_INTEGER: | |
619 | case NODE_STRING: | |
620 | case NODE_ENUMERATOR: | |
621 | case NODE_ENUM: | |
622 | case NODE_CLOCK: | |
623 | case NODE_CALLSITE: | |
624 | case NODE_ENV: | |
625 | default: | |
626 | goto errinval; | |
627 | } | |
628 | ||
629 | depth++; | |
630 | ret = _ctf_visitor_semantic_check( | |
0f5c5d5c | 631 | depth + 1, node->u.field_class_def.field_class_specifier_list, logger); |
4164020e SM |
632 | if (ret) |
633 | return ret; | |
634 | bt_list_for_each_entry (iter, &node->u.field_class_def.field_class_declarators, siblings) { | |
0f5c5d5c | 635 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
636 | if (ret) |
637 | return ret; | |
638 | } | |
639 | depth--; | |
640 | break; | |
641 | case NODE_TYPEALIAS_TARGET: | |
642 | { | |
643 | int nr_declarators; | |
644 | ||
645 | switch (node->parent->type) { | |
646 | case NODE_TYPEALIAS: | |
647 | break; /* OK */ | |
648 | default: | |
649 | goto errinval; | |
650 | } | |
651 | ||
652 | depth++; | |
653 | ret = _ctf_visitor_semantic_check( | |
0f5c5d5c | 654 | depth + 1, node->u.field_class_alias_target.field_class_specifier_list, logger); |
4164020e SM |
655 | if (ret) |
656 | return ret; | |
657 | nr_declarators = 0; | |
658 | bt_list_for_each_entry (iter, &node->u.field_class_alias_target.field_class_declarators, | |
659 | siblings) { | |
0f5c5d5c | 660 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
661 | if (ret) |
662 | return ret; | |
663 | nr_declarators++; | |
664 | } | |
665 | if (nr_declarators > 1) { | |
0f5c5d5c SM |
666 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
667 | logger, node->lineno, | |
668 | "Too many declarators in field class alias's name (maximum is 1): count={}", | |
4164020e SM |
669 | nr_declarators); |
670 | return -EINVAL; | |
671 | } | |
672 | depth--; | |
673 | break; | |
674 | } | |
675 | case NODE_TYPEALIAS_ALIAS: | |
676 | { | |
677 | int nr_declarators; | |
678 | ||
679 | switch (node->parent->type) { | |
680 | case NODE_TYPEALIAS: | |
681 | break; /* OK */ | |
682 | default: | |
683 | goto errinval; | |
684 | } | |
685 | ||
686 | depth++; | |
687 | ret = _ctf_visitor_semantic_check( | |
0f5c5d5c | 688 | depth + 1, node->u.field_class_alias_name.field_class_specifier_list, logger); |
4164020e SM |
689 | if (ret) |
690 | return ret; | |
691 | nr_declarators = 0; | |
692 | bt_list_for_each_entry (iter, &node->u.field_class_alias_name.field_class_declarators, | |
693 | siblings) { | |
0f5c5d5c | 694 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
695 | if (ret) |
696 | return ret; | |
697 | nr_declarators++; | |
698 | } | |
699 | if (nr_declarators > 1) { | |
0f5c5d5c SM |
700 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
701 | logger, node->lineno, | |
702 | "Too many declarators in field class alias's name (maximum is 1): count={}", | |
4164020e SM |
703 | nr_declarators); |
704 | return -EINVAL; | |
705 | } | |
706 | depth--; | |
707 | break; | |
708 | } | |
709 | case NODE_TYPEALIAS: | |
710 | switch (node->parent->type) { | |
711 | case NODE_ROOT: | |
712 | case NODE_EVENT: | |
713 | case NODE_STREAM: | |
714 | case NODE_TRACE: | |
715 | case NODE_VARIANT: | |
716 | case NODE_STRUCT: | |
717 | break; /* OK */ | |
718 | ||
719 | case NODE_CTF_EXPRESSION: | |
720 | case NODE_UNARY_EXPRESSION: | |
721 | case NODE_TYPEDEF: | |
722 | case NODE_TYPEALIAS_TARGET: | |
723 | case NODE_TYPEALIAS_ALIAS: | |
724 | case NODE_TYPEALIAS: | |
725 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
726 | case NODE_TYPE_SPECIFIER: | |
727 | case NODE_TYPE_SPECIFIER_LIST: | |
728 | case NODE_POINTER: | |
729 | case NODE_TYPE_DECLARATOR: | |
730 | case NODE_FLOATING_POINT: | |
731 | case NODE_INTEGER: | |
732 | case NODE_STRING: | |
733 | case NODE_ENUMERATOR: | |
734 | case NODE_ENUM: | |
735 | case NODE_CLOCK: | |
736 | case NODE_CALLSITE: | |
737 | case NODE_ENV: | |
738 | default: | |
739 | goto errinval; | |
740 | } | |
741 | ||
0f5c5d5c | 742 | ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.target, logger); |
4164020e SM |
743 | if (ret) |
744 | return ret; | |
0f5c5d5c | 745 | ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.alias, logger); |
4164020e SM |
746 | if (ret) |
747 | return ret; | |
748 | break; | |
749 | ||
750 | case NODE_TYPE_SPECIFIER_LIST: | |
0f5c5d5c | 751 | ret = ctf_visitor_field_class_specifier_list(depth, node, logger); |
4164020e SM |
752 | if (ret) |
753 | return ret; | |
754 | break; | |
755 | case NODE_TYPE_SPECIFIER: | |
0f5c5d5c | 756 | ret = ctf_visitor_field_class_specifier(depth, node, logger); |
4164020e SM |
757 | if (ret) |
758 | return ret; | |
759 | break; | |
760 | case NODE_POINTER: | |
761 | switch (node->parent->type) { | |
762 | case NODE_TYPE_DECLARATOR: | |
763 | break; /* OK */ | |
764 | default: | |
765 | goto errinval; | |
766 | } | |
767 | break; | |
768 | case NODE_TYPE_DECLARATOR: | |
0f5c5d5c | 769 | ret = ctf_visitor_field_class_declarator(depth, node, logger); |
4164020e SM |
770 | if (ret) |
771 | return ret; | |
772 | break; | |
773 | ||
774 | case NODE_FLOATING_POINT: | |
775 | switch (node->parent->type) { | |
776 | case NODE_TYPE_SPECIFIER: | |
777 | break; /* OK */ | |
778 | default: | |
779 | goto errinval; | |
780 | ||
781 | case NODE_UNARY_EXPRESSION: | |
782 | goto errperm; | |
783 | } | |
784 | bt_list_for_each_entry (iter, &node->u.floating_point.expressions, siblings) { | |
0f5c5d5c | 785 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
786 | if (ret) |
787 | return ret; | |
788 | } | |
789 | break; | |
790 | case NODE_INTEGER: | |
791 | switch (node->parent->type) { | |
792 | case NODE_TYPE_SPECIFIER: | |
793 | break; /* OK */ | |
794 | default: | |
795 | goto errinval; | |
796 | } | |
797 | ||
798 | bt_list_for_each_entry (iter, &node->u.integer.expressions, siblings) { | |
0f5c5d5c | 799 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
800 | if (ret) |
801 | return ret; | |
802 | } | |
803 | break; | |
804 | case NODE_STRING: | |
805 | switch (node->parent->type) { | |
806 | case NODE_TYPE_SPECIFIER: | |
807 | break; /* OK */ | |
808 | default: | |
809 | goto errinval; | |
810 | ||
811 | case NODE_UNARY_EXPRESSION: | |
812 | goto errperm; | |
813 | } | |
814 | ||
815 | bt_list_for_each_entry (iter, &node->u.string.expressions, siblings) { | |
0f5c5d5c | 816 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
817 | if (ret) |
818 | return ret; | |
819 | } | |
820 | break; | |
821 | case NODE_ENUMERATOR: | |
822 | switch (node->parent->type) { | |
823 | case NODE_ENUM: | |
824 | break; | |
825 | default: | |
826 | goto errinval; | |
827 | } | |
828 | /* | |
829 | * Enumerators are only allows to contain: | |
830 | * numeric unary expression | |
831 | * or num. unary exp. ... num. unary exp | |
832 | */ | |
833 | { | |
834 | int count = 0; | |
835 | ||
836 | bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { | |
837 | switch (count++) { | |
838 | case 0: | |
839 | if (iter->type != NODE_UNARY_EXPRESSION || | |
840 | (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT && | |
841 | iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) || | |
842 | iter->u.unary_expression.link != UNARY_LINK_UNKNOWN) { | |
0f5c5d5c SM |
843 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
844 | logger, iter->lineno, | |
845 | "First unary expression of enumerator is unexpected."); | |
4164020e SM |
846 | goto errperm; |
847 | } | |
848 | break; | |
849 | case 1: | |
850 | if (iter->type != NODE_UNARY_EXPRESSION || | |
851 | (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT && | |
852 | iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) || | |
853 | iter->u.unary_expression.link != UNARY_DOTDOTDOT) { | |
0f5c5d5c SM |
854 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
855 | logger, iter->lineno, | |
856 | "Second unary expression of enumerator is unexpected."); | |
4164020e SM |
857 | goto errperm; |
858 | } | |
859 | break; | |
860 | default: | |
861 | goto errperm; | |
862 | } | |
863 | } | |
864 | } | |
865 | ||
866 | bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { | |
0f5c5d5c | 867 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
868 | if (ret) |
869 | return ret; | |
870 | } | |
871 | break; | |
872 | case NODE_ENUM: | |
873 | switch (node->parent->type) { | |
874 | case NODE_TYPE_SPECIFIER: | |
875 | break; /* OK */ | |
876 | default: | |
877 | goto errinval; | |
878 | ||
879 | case NODE_UNARY_EXPRESSION: | |
880 | goto errperm; | |
881 | } | |
882 | ||
883 | depth++; | |
0f5c5d5c | 884 | ret = _ctf_visitor_semantic_check(depth + 1, node->u._enum.container_field_class, logger); |
4164020e SM |
885 | if (ret) |
886 | return ret; | |
887 | ||
888 | bt_list_for_each_entry (iter, &node->u._enum.enumerator_list, siblings) { | |
0f5c5d5c | 889 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
890 | if (ret) |
891 | return ret; | |
892 | } | |
893 | depth--; | |
894 | break; | |
895 | case NODE_STRUCT_OR_VARIANT_DECLARATION: | |
896 | switch (node->parent->type) { | |
897 | case NODE_STRUCT: | |
898 | case NODE_VARIANT: | |
899 | break; | |
900 | default: | |
901 | goto errinval; | |
902 | } | |
903 | ret = _ctf_visitor_semantic_check( | |
0f5c5d5c | 904 | depth + 1, node->u.struct_or_variant_declaration.field_class_specifier_list, logger); |
4164020e SM |
905 | if (ret) |
906 | return ret; | |
907 | bt_list_for_each_entry ( | |
908 | iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) { | |
0f5c5d5c | 909 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
910 | if (ret) |
911 | return ret; | |
912 | } | |
913 | break; | |
914 | case NODE_VARIANT: | |
915 | switch (node->parent->type) { | |
916 | case NODE_TYPE_SPECIFIER: | |
917 | break; /* OK */ | |
918 | default: | |
919 | goto errinval; | |
920 | ||
921 | case NODE_UNARY_EXPRESSION: | |
922 | goto errperm; | |
923 | } | |
924 | bt_list_for_each_entry (iter, &node->u.variant.declaration_list, siblings) { | |
0f5c5d5c | 925 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
926 | if (ret) |
927 | return ret; | |
928 | } | |
929 | break; | |
930 | ||
931 | case NODE_STRUCT: | |
932 | switch (node->parent->type) { | |
933 | case NODE_TYPE_SPECIFIER: | |
934 | break; /* OK */ | |
935 | default: | |
936 | goto errinval; | |
937 | ||
938 | case NODE_UNARY_EXPRESSION: | |
939 | goto errperm; | |
940 | } | |
941 | bt_list_for_each_entry (iter, &node->u._struct.declaration_list, siblings) { | |
0f5c5d5c | 942 | ret = _ctf_visitor_semantic_check(depth + 1, iter, logger); |
4164020e SM |
943 | if (ret) |
944 | return ret; | |
945 | } | |
946 | break; | |
947 | ||
948 | case NODE_UNKNOWN: | |
949 | default: | |
0f5c5d5c SM |
950 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, "Unknown node type: type={}", |
951 | (int) node->type); | |
4164020e SM |
952 | return -EINVAL; |
953 | } | |
954 | return ret; | |
e98a2d6e PP |
955 | |
956 | errinval: | |
0f5c5d5c SM |
957 | _BT_CPPLOGE_APPEND_CAUSE_LINENO( |
958 | logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}", | |
4164020e SM |
959 | node_type(node), node_type(node->parent)); |
960 | return -EINVAL; /* Incoherent structure */ | |
e98a2d6e PP |
961 | |
962 | errperm: | |
0f5c5d5c SM |
963 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
964 | "Semantic error: node-type={}, parent-node-type={}", | |
965 | node_type(node), node_type(node->parent)); | |
4164020e | 966 | return -EPERM; /* Structure not allowed */ |
e98a2d6e PP |
967 | } |
968 | ||
0f5c5d5c | 969 | int ctf_visitor_semantic_check(int depth, struct ctf_node *node, const bt2c::Logger& parentLogger) |
e98a2d6e | 970 | { |
4164020e | 971 | int ret = 0; |
0f5c5d5c | 972 | bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/SEMANTIC-VALIDATOR-VISITOR"}; |
4164020e SM |
973 | |
974 | /* | |
975 | * First make sure we create the parent links for all children. Let's | |
976 | * take the safe route and recreate them at each validation, just in | |
977 | * case the structure has changed. | |
978 | */ | |
0f5c5d5c | 979 | ret = ctf_visitor_parent_links(depth, node, logger); |
4164020e | 980 | if (ret) { |
0f5c5d5c SM |
981 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
982 | "Cannot create parent links in metadata's AST: " | |
983 | "ret={}", | |
984 | ret); | |
4164020e SM |
985 | goto end; |
986 | } | |
987 | ||
0f5c5d5c | 988 | ret = _ctf_visitor_semantic_check(depth, node, logger); |
4164020e | 989 | if (ret) { |
0f5c5d5c SM |
990 | _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, |
991 | "Cannot check metadata's AST semantics: " | |
992 | "ret={}", | |
993 | ret); | |
4164020e SM |
994 | goto end; |
995 | } | |
41b60475 | 996 | |
55314f2a | 997 | end: |
4164020e | 998 | return ret; |
e98a2d6e | 999 | } |