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