c1449cbf2115a49d207508e70950d9ea0d761bd7
[babeltrace.git] / src / plugins / ctf / common / src / metadata / tsdl / visitor-generate-ir.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 * Copyright 2015-2018 Philippe Proulx <philippe.proulx@efficios.com>
6 *
7 * Common Trace Format metadata visitor (generates CTF IR objects).
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12
13 #include <babeltrace2/babeltrace.h>
14
15 #include "logging.hpp"
16
17 #include "common/assert.h"
18 #include "common/common.h"
19 #include "common/uuid.h"
20 #include "compat/endian.h" /* IWYU pragma: keep */
21 #include "cpp-common/bt2c/logging.hpp"
22 #include "cpp-common/bt2s/make-unique.hpp"
23
24 #include "../normalize-clk-offset.hpp"
25 #include "ast.hpp"
26 #include "ctf-meta-visitors.hpp"
27 #include "ctf-meta.hpp"
28
29 /* Bit value (left shift) */
30 #define _BV(_val) (1 << (_val))
31
32 /* Bit is set in a set of bits */
33 #define _IS_SET(_set, _mask) (*(_set) & (_mask))
34
35 /* Set bit in a set of bits */
36 #define _SET(_set, _mask) (*(_set) |= (_mask))
37
38 /* Try to push scope, or go to the `error` label */
39 #define _TRY_PUSH_SCOPE_OR_GOTO_ERROR() \
40 do { \
41 ret = ctx_push_scope(ctx); \
42 if (ret) { \
43 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot push scope."); \
44 goto error; \
45 } \
46 } while (0)
47
48 /* Bits for verifying existing attributes in various declarations */
49 enum
50 {
51 _CLOCK_NAME_SET = _BV(0),
52 _CLOCK_UUID_SET = _BV(1),
53 _CLOCK_FREQ_SET = _BV(2),
54 _CLOCK_PRECISION_SET = _BV(3),
55 _CLOCK_OFFSET_S_SET = _BV(4),
56 _CLOCK_OFFSET_SET = _BV(5),
57 _CLOCK_ABSOLUTE_SET = _BV(6),
58 _CLOCK_DESCRIPTION_SET = _BV(7),
59 };
60
61 enum
62 {
63 _INTEGER_ALIGN_SET = _BV(0),
64 _INTEGER_SIZE_SET = _BV(1),
65 _INTEGER_BASE_SET = _BV(2),
66 _INTEGER_ENCODING_SET = _BV(3),
67 _INTEGER_BYTE_ORDER_SET = _BV(4),
68 _INTEGER_SIGNED_SET = _BV(5),
69 _INTEGER_MAP_SET = _BV(6),
70 };
71
72 enum
73 {
74 _FLOAT_ALIGN_SET = _BV(0),
75 _FLOAT_MANT_DIG_SET = _BV(1),
76 _FLOAT_EXP_DIG_SET = _BV(2),
77 _FLOAT_BYTE_ORDER_SET = _BV(3),
78 };
79
80 enum
81 {
82 _STRING_ENCODING_SET = _BV(0),
83 };
84
85 enum
86 {
87 _TRACE_MINOR_SET = _BV(0),
88 _TRACE_MAJOR_SET = _BV(1),
89 _TRACE_BYTE_ORDER_SET = _BV(2),
90 _TRACE_UUID_SET = _BV(3),
91 _TRACE_PACKET_HEADER_SET = _BV(4),
92 };
93
94 enum
95 {
96 _STREAM_ID_SET = _BV(0),
97 _STREAM_PACKET_CONTEXT_SET = _BV(1),
98 _STREAM_EVENT_HEADER_SET = _BV(2),
99 _STREAM_EVENT_CONTEXT_SET = _BV(3),
100 };
101
102 enum
103 {
104 _EVENT_NAME_SET = _BV(0),
105 _EVENT_ID_SET = _BV(1),
106 _EVENT_MODEL_EMF_URI_SET = _BV(2),
107 _EVENT_STREAM_ID_SET = _BV(3),
108 _EVENT_LOG_LEVEL_SET = _BV(4),
109 _EVENT_CONTEXT_SET = _BV(5),
110 _EVENT_FIELDS_SET = _BV(6),
111 };
112
113 enum loglevel
114 {
115 LOG_LEVEL_EMERG = 0,
116 LOG_LEVEL_ALERT = 1,
117 LOG_LEVEL_CRIT = 2,
118 LOG_LEVEL_ERR = 3,
119 LOG_LEVEL_WARNING = 4,
120 LOG_LEVEL_NOTICE = 5,
121 LOG_LEVEL_INFO = 6,
122 LOG_LEVEL_DEBUG_SYSTEM = 7,
123 LOG_LEVEL_DEBUG_PROGRAM = 8,
124 LOG_LEVEL_DEBUG_PROCESS = 9,
125 LOG_LEVEL_DEBUG_MODULE = 10,
126 LOG_LEVEL_DEBUG_UNIT = 11,
127 LOG_LEVEL_DEBUG_FUNCTION = 12,
128 LOG_LEVEL_DEBUG_LINE = 13,
129 LOG_LEVEL_DEBUG = 14,
130 _NR_LOGLEVELS = 15,
131 };
132
133 /* Prefixes of class aliases */
134 #define _PREFIX_ALIAS 'a'
135 #define _PREFIX_ENUM 'e'
136 #define _PREFIX_STRUCT 's'
137 #define _PREFIX_VARIANT 'v'
138
139 /* First entry in a BT list */
140 #define _BT_LIST_FIRST_ENTRY(_ptr, _class, _member) bt_list_entry((_ptr)->next, _class, _member)
141
142 #define _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(_node, _attr, _entity) \
143 _BT_CPPLOGE_APPEND_CAUSE_LINENO(ctx->logger, (_node)->lineno, \
144 "Duplicate attribute in {}: attr-name=\"{}\"", _entity, _attr)
145
146 #define _BT_CPPLOGE_NODE(_node, _msg, args...) \
147 _BT_CPPLOGE_LINENO(ctx->logger, (_node)->lineno, _msg, ##args)
148
149 #define _BT_CPPLOGE_APPEND_CAUSE_NODE(_node, _msg, args...) \
150 _BT_CPPLOGE_APPEND_CAUSE_LINENO(ctx->logger, (_node)->lineno, _msg, ##args)
151
152 #define _BT_CPPLOGW_NODE(_node, _msg, args...) \
153 _BT_CPPLOGW_LINENO(ctx->logger, (_node)->lineno, _msg, ##args)
154
155 #define _BT_CPPLOGT_NODE(_node, _msg, args...) \
156 _BT_CPPLOGT_LINENO(ctx->logger, (_node)->lineno, _msg, ##args)
157
158 /*
159 * Declaration scope of a visitor context. This represents a TSDL
160 * lexical scope, so that aliases and named structures, variants,
161 * and enumerations may be registered and looked up hierarchically.
162 */
163 struct ctx_decl_scope
164 {
165 /*
166 * Alias name to field class.
167 *
168 * GQuark -> struct ctf_field_class * (owned by this)
169 */
170 GHashTable *decl_map;
171
172 /* Parent scope; NULL if this is the root declaration scope */
173 struct ctx_decl_scope *parent_scope;
174 };
175
176 /**
177 * Creates a new declaration scope.
178 *
179 * @param par_scope Parent scope (NULL if creating a root scope)
180 * @returns New declaration scope, or NULL on error
181 */
182 static struct ctx_decl_scope *ctx_decl_scope_create(struct ctf_visitor_generate_ir *ctx,
183 struct ctx_decl_scope *par_scope)
184 {
185 struct ctx_decl_scope *scope;
186
187 scope = g_new(struct ctx_decl_scope, 1);
188 if (!scope) {
189 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Failed to allocate one declaration scope.");
190 goto end;
191 }
192
193 scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
194 (GDestroyNotify) ctf_field_class_destroy);
195 scope->parent_scope = par_scope;
196
197 end:
198 return scope;
199 }
200
201 /**
202 * Destroys a declaration scope.
203 *
204 * This function does not destroy the parent scope.
205 *
206 * @param scope Scope to destroy
207 */
208 static void ctx_decl_scope_destroy(struct ctx_decl_scope *scope)
209 {
210 if (!scope) {
211 goto end;
212 }
213
214 g_hash_table_destroy(scope->decl_map);
215 g_free(scope);
216
217 end:
218 return;
219 }
220
221 /**
222 * Returns the GQuark of a prefixed alias.
223 *
224 * @param prefix Prefix character
225 * @param name Name
226 * @returns Associated GQuark, or 0 on error
227 */
228 static GQuark get_prefixed_named_quark(char prefix, const char *name)
229 {
230 BT_ASSERT(name);
231 std::string prname = std::string {prefix} + name;
232 return g_quark_from_string(prname.c_str());
233 }
234
235 /**
236 * Looks up a prefixed class alias within a declaration scope.
237 *
238 * @param scope Declaration scope
239 * @param prefix Prefix character
240 * @param name Alias name
241 * @param levels Number of levels to dig into (-1 means infinite)
242 * @param copy True to return a copy
243 * @returns Declaration (owned by caller if \p copy is true),
244 * or NULL if not found
245 */
246 static struct ctf_field_class *ctx_decl_scope_lookup_prefix_alias(struct ctx_decl_scope *scope,
247 char prefix, const char *name,
248 int levels, bool copy)
249 {
250 GQuark qname = 0;
251 int cur_levels = 0;
252 struct ctf_field_class *decl = NULL;
253 struct ctx_decl_scope *cur_scope = scope;
254
255 BT_ASSERT(scope);
256 BT_ASSERT(name);
257 qname = get_prefixed_named_quark(prefix, name);
258 if (!qname) {
259 goto end;
260 }
261
262 if (levels < 0) {
263 levels = INT_MAX;
264 }
265
266 while (cur_scope && cur_levels < levels) {
267 decl = (ctf_field_class *) g_hash_table_lookup(cur_scope->decl_map,
268 (gconstpointer) GUINT_TO_POINTER(qname));
269 if (decl) {
270 /* Caller's reference */
271 if (copy) {
272 decl = ctf_field_class_copy(decl);
273 BT_ASSERT(decl);
274 }
275
276 goto end;
277 }
278
279 cur_scope = cur_scope->parent_scope;
280 cur_levels++;
281 }
282
283 end:
284 return decl;
285 }
286
287 /**
288 * Looks up a class alias within a declaration scope.
289 *
290 * @param scope Declaration scope
291 * @param name Alias name
292 * @param levels Number of levels to dig into (-1 means infinite)
293 * @param copy True to return a copy
294 * @returns Declaration (owned by caller if \p copy is true),
295 * or NULL if not found
296 */
297 static struct ctf_field_class *ctx_decl_scope_lookup_alias(struct ctx_decl_scope *scope,
298 const char *name, int levels, bool copy)
299 {
300 return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS, name, levels, copy);
301 }
302
303 /**
304 * Looks up an enumeration within a declaration scope.
305 *
306 * @param scope Declaration scope
307 * @param name Enumeration name
308 * @param levels Number of levels to dig into (-1 means infinite)
309 * @param copy True to return a copy
310 * @returns Declaration (owned by caller if \p copy is true),
311 * or NULL if not found
312 */
313 static struct ctf_field_class_enum *
314 ctx_decl_scope_lookup_enum(struct ctx_decl_scope *scope, const char *name, int levels, bool copy)
315 {
316 return ctf_field_class_as_enum(
317 ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM, name, levels, copy));
318 }
319
320 /**
321 * Looks up a structure within a declaration scope.
322 *
323 * @param scope Declaration scope
324 * @param name Structure name
325 * @param levels Number of levels to dig into (-1 means infinite)
326 * @param copy True to return a copy
327 * @returns Declaration (owned by caller if \p copy is true),
328 * or NULL if not found
329 */
330 static struct ctf_field_class_struct *
331 ctx_decl_scope_lookup_struct(struct ctx_decl_scope *scope, const char *name, int levels, bool copy)
332 {
333 return ctf_field_class_as_struct(
334 ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_STRUCT, name, levels, copy));
335 }
336
337 /**
338 * Looks up a variant within a declaration scope.
339 *
340 * @param scope Declaration scope
341 * @param name Variant name
342 * @param levels Number of levels to dig into (-1 means infinite)
343 * @param copy True to return a copy
344 * @returns Declaration (owned by caller if \p copy is true),
345 * or NULL if not found
346 */
347 static struct ctf_field_class_variant *
348 ctx_decl_scope_lookup_variant(struct ctx_decl_scope *scope, const char *name, int levels, bool copy)
349 {
350 return ctf_field_class_as_variant(
351 ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_VARIANT, name, levels, copy));
352 }
353
354 /**
355 * Registers a prefixed class alias within a declaration scope.
356 *
357 * @param scope Declaration scope
358 * @param prefix Prefix character
359 * @param name Alias name (non-NULL)
360 * @param decl Field class to register (copied)
361 * @returns 0 if registration went okay, negative value otherwise
362 */
363 static int ctx_decl_scope_register_prefix_alias(struct ctx_decl_scope *scope, char prefix,
364 const char *name, struct ctf_field_class *decl)
365 {
366 int ret = 0;
367 GQuark qname = 0;
368
369 BT_ASSERT(scope);
370 BT_ASSERT(name);
371 BT_ASSERT(decl);
372 qname = get_prefixed_named_quark(prefix, name);
373 if (!qname) {
374 ret = -ENOMEM;
375 goto end;
376 }
377
378 /* Make sure alias does not exist in local scope */
379 if (ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1, false)) {
380 ret = -EEXIST;
381 goto end;
382 }
383
384 decl = ctf_field_class_copy(decl);
385 BT_ASSERT(decl);
386 g_hash_table_insert(scope->decl_map, GUINT_TO_POINTER(qname), decl);
387
388 end:
389 return ret;
390 }
391
392 /**
393 * Registers a class alias within a declaration scope.
394 *
395 * @param scope Declaration scope
396 * @param name Alias name (non-NULL)
397 * @param decl Field class to register (copied)
398 * @returns 0 if registration went okay, negative value otherwise
399 */
400 static int ctx_decl_scope_register_alias(struct ctx_decl_scope *scope, const char *name,
401 struct ctf_field_class *decl)
402 {
403 return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ALIAS, name, decl);
404 }
405
406 /**
407 * Registers an enumeration declaration within a declaration scope.
408 *
409 * @param scope Declaration scope
410 * @param name Enumeration name (non-NULL)
411 * @param decl Enumeration field class to register (copied)
412 * @returns 0 if registration went okay, negative value otherwise
413 */
414 static int ctx_decl_scope_register_enum(struct ctx_decl_scope *scope, const char *name,
415 struct ctf_field_class_enum *decl)
416 {
417 return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM, name, &decl->base.base.base);
418 }
419
420 /**
421 * Registers a structure declaration within a declaration scope.
422 *
423 * @param scope Declaration scope
424 * @param name Structure name (non-NULL)
425 * @param decl Structure field class to register (copied)
426 * @returns 0 if registration went okay, negative value otherwise
427 */
428 static int ctx_decl_scope_register_struct(struct ctx_decl_scope *scope, const char *name,
429 struct ctf_field_class_struct *decl)
430 {
431 return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT, name, &decl->base);
432 }
433
434 /**
435 * Registers a variant declaration within a declaration scope.
436 *
437 * @param scope Declaration scope
438 * @param name Variant name (non-NULL)
439 * @param decl Variant field class to register
440 * @returns 0 if registration went okay, negative value otherwise
441 */
442 static int ctx_decl_scope_register_variant(struct ctx_decl_scope *scope, const char *name,
443 struct ctf_field_class_variant *decl)
444 {
445 return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT, name, &decl->base);
446 }
447
448 ctf_visitor_generate_ir::~ctf_visitor_generate_ir()
449 {
450 struct ctx_decl_scope *scope = this->current_scope;
451
452 /*
453 * Destroy all scopes, from current one to the root scope.
454 */
455 while (scope) {
456 struct ctx_decl_scope *parent_scope = scope->parent_scope;
457
458 ctx_decl_scope_destroy(scope);
459 scope = parent_scope;
460 }
461
462 if (this->ctf_tc) {
463 ctf_trace_class_destroy(this->ctf_tc);
464 }
465 }
466
467 ctf_visitor_generate_ir::UP ctf_visitor_generate_ir_create(const bt2c::Logger& parentLogger)
468 {
469 auto ctx = bt2s::make_unique<ctf_visitor_generate_ir>(parentLogger);
470
471 ctx->ctf_tc = ctf_trace_class_create();
472 if (!ctx->ctf_tc) {
473 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot create CTF trace class.");
474 return nullptr;
475 }
476
477 /* Root declaration scope */
478 ctx->current_scope = ctx_decl_scope_create(ctx.get(), NULL);
479 if (!ctx->current_scope) {
480 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot create declaration scope.");
481 return nullptr;
482 }
483
484 return ctx;
485 }
486
487 /**
488 * Pushes a new declaration scope on top of a visitor context's
489 * declaration scope stack.
490 *
491 * @param ctx Visitor context
492 * @returns 0 on success, or a negative value on error
493 */
494 static int ctx_push_scope(struct ctf_visitor_generate_ir *ctx)
495 {
496 int ret = 0;
497 struct ctx_decl_scope *new_scope;
498
499 BT_ASSERT(ctx);
500 new_scope = ctx_decl_scope_create(ctx, ctx->current_scope);
501 if (!new_scope) {
502 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot create declaration scope.");
503 ret = -ENOMEM;
504 goto end;
505 }
506
507 ctx->current_scope = new_scope;
508
509 end:
510 return ret;
511 }
512
513 static void ctx_pop_scope(struct ctf_visitor_generate_ir *ctx)
514 {
515 struct ctx_decl_scope *parent_scope = NULL;
516
517 BT_ASSERT(ctx);
518
519 if (!ctx->current_scope) {
520 goto end;
521 }
522
523 parent_scope = ctx->current_scope->parent_scope;
524 ctx_decl_scope_destroy(ctx->current_scope);
525 ctx->current_scope = parent_scope;
526
527 end:
528 return;
529 }
530
531 static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *ctx,
532 struct ctf_node *ts_list,
533 struct ctf_field_class **decl);
534
535 static int is_unary_string(struct bt_list_head *head)
536 {
537 int ret = TRUE;
538 struct ctf_node *node;
539
540 bt_list_for_each_entry (node, head, siblings) {
541 if (node->type != NODE_UNARY_EXPRESSION) {
542 ret = FALSE;
543 }
544
545 if (node->u.unary_expression.type != UNARY_STRING) {
546 ret = FALSE;
547 }
548 }
549
550 return ret;
551 }
552
553 static const char *get_map_clock_name_value(struct bt_list_head *head)
554 {
555 int i = 0;
556 struct ctf_node *node;
557 const char *name = NULL;
558
559 bt_list_for_each_entry (node, head, siblings) {
560 char *src_string;
561 int uexpr_type = node->u.unary_expression.type;
562 int uexpr_link = node->u.unary_expression.link;
563 int cond = node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_STRING ||
564 !((uexpr_link != UNARY_LINK_UNKNOWN) ^ (i == 0));
565 if (cond) {
566 goto error;
567 }
568
569 /* Needs to be chained with . */
570 switch (node->u.unary_expression.link) {
571 case UNARY_DOTLINK:
572 break;
573 case UNARY_ARROWLINK:
574 case UNARY_DOTDOTDOT:
575 goto error;
576 default:
577 break;
578 }
579
580 src_string = node->u.unary_expression.u.string;
581
582 switch (i) {
583 case 0:
584 if (strcmp("clock", src_string)) {
585 goto error;
586 }
587 break;
588 case 1:
589 name = src_string;
590 break;
591 case 2:
592 if (strcmp("value", src_string)) {
593 goto error;
594 }
595 break;
596 default:
597 /* Extra identifier, unknown */
598 goto error;
599 }
600
601 i++;
602 }
603
604 return name;
605
606 error:
607 return NULL;
608 }
609
610 static int is_unary_unsigned(struct bt_list_head *head)
611 {
612 int ret = TRUE;
613 struct ctf_node *node;
614
615 bt_list_for_each_entry (node, head, siblings) {
616 if (node->type != NODE_UNARY_EXPRESSION) {
617 ret = FALSE;
618 }
619
620 if (node->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
621 ret = FALSE;
622 }
623 }
624
625 return ret;
626 }
627
628 static int get_unary_unsigned(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *head,
629 uint64_t *value)
630 {
631 int i = 0;
632 int ret = 0;
633 struct ctf_node *node;
634
635 *value = 0;
636
637 if (bt_list_empty(head)) {
638 ret = -1;
639 goto end;
640 }
641
642 bt_list_for_each_entry (node, head, siblings) {
643 int uexpr_type = node->u.unary_expression.type;
644 int uexpr_link = node->u.unary_expression.link;
645 int cond = node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_UNSIGNED_CONSTANT ||
646 uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
647 if (cond) {
648 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Invalid constant unsigned integer.");
649 ret = -EINVAL;
650 goto end;
651 }
652
653 *value = node->u.unary_expression.u.unsigned_constant;
654 i++;
655 }
656
657 end:
658 return ret;
659 }
660
661 static int is_unary_signed(struct bt_list_head *head)
662 {
663 int ret = TRUE;
664 struct ctf_node *node;
665
666 bt_list_for_each_entry (node, head, siblings) {
667 if (node->type != NODE_UNARY_EXPRESSION) {
668 ret = FALSE;
669 }
670
671 if (node->u.unary_expression.type != UNARY_SIGNED_CONSTANT) {
672 ret = FALSE;
673 }
674 }
675
676 return ret;
677 }
678
679 static int get_unary_signed(struct bt_list_head *head, int64_t *value)
680 {
681 int i = 0;
682 int ret = 0;
683 struct ctf_node *node;
684
685 bt_list_for_each_entry (node, head, siblings) {
686 int uexpr_type = node->u.unary_expression.type;
687 int uexpr_link = node->u.unary_expression.link;
688 int cond = node->type != NODE_UNARY_EXPRESSION ||
689 (uexpr_type != UNARY_UNSIGNED_CONSTANT && uexpr_type != UNARY_SIGNED_CONSTANT) ||
690 uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
691 if (cond) {
692 ret = -EINVAL;
693 goto end;
694 }
695
696 switch (uexpr_type) {
697 case UNARY_UNSIGNED_CONSTANT:
698 *value = (int64_t) node->u.unary_expression.u.unsigned_constant;
699 break;
700 case UNARY_SIGNED_CONSTANT:
701 *value = node->u.unary_expression.u.signed_constant;
702 break;
703 default:
704 ret = -EINVAL;
705 goto end;
706 }
707
708 i++;
709 }
710
711 end:
712 return ret;
713 }
714
715 static int get_unary_uuid(struct bt_list_head *head, bt_uuid_t uuid, const bt2c::Logger& logger)
716 {
717 return ctf_ast_get_unary_uuid(head, uuid, logger);
718 }
719
720 static int get_boolean(struct ctf_visitor_generate_ir *ctx, struct ctf_node *unary_expr)
721 {
722 int ret = 0;
723
724 if (unary_expr->type != NODE_UNARY_EXPRESSION) {
725 _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr, "Expecting unary expression: node-type={}",
726 unary_expr->type);
727 ret = -EINVAL;
728 goto end;
729 }
730
731 switch (unary_expr->u.unary_expression.type) {
732 case UNARY_UNSIGNED_CONSTANT:
733 ret = (unary_expr->u.unary_expression.u.unsigned_constant != 0);
734 break;
735 case UNARY_SIGNED_CONSTANT:
736 ret = (unary_expr->u.unary_expression.u.signed_constant != 0);
737 break;
738 case UNARY_STRING:
739 {
740 const char *str = unary_expr->u.unary_expression.u.string;
741
742 if (strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0) {
743 ret = TRUE;
744 } else if (strcmp(str, "false") == 0 || strcmp(str, "FALSE") == 0) {
745 ret = FALSE;
746 } else {
747 _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr, "Unexpected boolean value: value=\"{}\"",
748 str);
749 ret = -EINVAL;
750 goto end;
751 }
752 break;
753 }
754 default:
755 _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr, "Unexpected unary expression type: node-type={}",
756 unary_expr->u.unary_expression.type);
757 ret = -EINVAL;
758 goto end;
759 }
760
761 end:
762 return ret;
763 }
764
765 static enum ctf_byte_order byte_order_from_unary_expr(struct ctf_visitor_generate_ir *ctx,
766 struct ctf_node *unary_expr)
767 {
768 const char *str;
769 enum ctf_byte_order bo = CTF_BYTE_ORDER_UNKNOWN;
770
771 if (unary_expr->u.unary_expression.type != UNARY_STRING) {
772 _BT_CPPLOGE_APPEND_CAUSE_NODE(
773 unary_expr, "\"byte_order\" attribute: expecting `be`, `le`, `network`, or `native`.");
774 goto end;
775 }
776
777 str = unary_expr->u.unary_expression.u.string;
778
779 if (strcmp(str, "be") == 0 || strcmp(str, "network") == 0) {
780 bo = CTF_BYTE_ORDER_BIG;
781 } else if (strcmp(str, "le") == 0) {
782 bo = CTF_BYTE_ORDER_LITTLE;
783 } else if (strcmp(str, "native") == 0) {
784 bo = CTF_BYTE_ORDER_DEFAULT;
785 } else {
786 _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr,
787 "Unexpected \"byte_order\" attribute value: "
788 "expecting `be`, `le`, `network`, or `native`: value=\"{}\"",
789 str);
790 goto end;
791 }
792
793 end:
794 return bo;
795 }
796
797 static enum ctf_byte_order get_real_byte_order(struct ctf_visitor_generate_ir *ctx,
798 struct ctf_node *uexpr)
799 {
800 enum ctf_byte_order bo = byte_order_from_unary_expr(ctx, uexpr);
801
802 if (bo == CTF_BYTE_ORDER_DEFAULT) {
803 bo = ctx->ctf_tc->default_byte_order;
804 }
805
806 return bo;
807 }
808
809 static int is_align_valid(uint64_t align)
810 {
811 return (align != 0) && !(align & (align - UINT64_C(1)));
812 }
813
814 static int get_class_specifier_name(struct ctf_visitor_generate_ir *ctx,
815 struct ctf_node *cls_specifier, GString *str)
816 {
817 int ret = 0;
818
819 if (cls_specifier->type != NODE_TYPE_SPECIFIER) {
820 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier, "Unexpected node type: node-type={}",
821 cls_specifier->type);
822 ret = -EINVAL;
823 goto end;
824 }
825
826 switch (cls_specifier->u.field_class_specifier.type) {
827 case TYPESPEC_VOID:
828 g_string_append(str, "void");
829 break;
830 case TYPESPEC_CHAR:
831 g_string_append(str, "char");
832 break;
833 case TYPESPEC_SHORT:
834 g_string_append(str, "short");
835 break;
836 case TYPESPEC_INT:
837 g_string_append(str, "int");
838 break;
839 case TYPESPEC_LONG:
840 g_string_append(str, "long");
841 break;
842 case TYPESPEC_FLOAT:
843 g_string_append(str, "float");
844 break;
845 case TYPESPEC_DOUBLE:
846 g_string_append(str, "double");
847 break;
848 case TYPESPEC_SIGNED:
849 g_string_append(str, "signed");
850 break;
851 case TYPESPEC_UNSIGNED:
852 g_string_append(str, "unsigned");
853 break;
854 case TYPESPEC_BOOL:
855 g_string_append(str, "bool");
856 break;
857 case TYPESPEC_COMPLEX:
858 g_string_append(str, "_Complex");
859 break;
860 case TYPESPEC_IMAGINARY:
861 g_string_append(str, "_Imaginary");
862 break;
863 case TYPESPEC_CONST:
864 g_string_append(str, "const");
865 break;
866 case TYPESPEC_ID_TYPE:
867 if (cls_specifier->u.field_class_specifier.id_type) {
868 g_string_append(str, cls_specifier->u.field_class_specifier.id_type);
869 }
870 break;
871 case TYPESPEC_STRUCT:
872 {
873 struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
874
875 if (!node->u._struct.name) {
876 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Unexpected empty structure field class name.");
877 ret = -EINVAL;
878 goto end;
879 }
880
881 g_string_append(str, "struct ");
882 g_string_append(str, node->u._struct.name);
883 break;
884 }
885 case TYPESPEC_VARIANT:
886 {
887 struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
888
889 if (!node->u.variant.name) {
890 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Unexpected empty variant field class name.");
891 ret = -EINVAL;
892 goto end;
893 }
894
895 g_string_append(str, "variant ");
896 g_string_append(str, node->u.variant.name);
897 break;
898 }
899 case TYPESPEC_ENUM:
900 {
901 struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
902
903 if (!node->u._enum.enum_id) {
904 _BT_CPPLOGE_APPEND_CAUSE_NODE(
905 node, "Unexpected empty enumeration field class (`enum`) name.");
906 ret = -EINVAL;
907 goto end;
908 }
909
910 g_string_append(str, "enum ");
911 g_string_append(str, node->u._enum.enum_id);
912 break;
913 }
914 case TYPESPEC_FLOATING_POINT:
915 case TYPESPEC_INTEGER:
916 case TYPESPEC_STRING:
917 default:
918 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier->u.field_class_specifier.node,
919 "Unexpected field class specifier type: {}",
920 cls_specifier->u.field_class_specifier.type);
921 ret = -EINVAL;
922 goto end;
923 }
924
925 end:
926 return ret;
927 }
928
929 static int get_class_specifier_list_name(struct ctf_visitor_generate_ir *ctx,
930 struct ctf_node *cls_specifier_list, GString *str)
931 {
932 int ret = 0;
933 struct ctf_node *iter;
934 int alias_item_nr = 0;
935 struct bt_list_head *head = &cls_specifier_list->u.field_class_specifier_list.head;
936
937 bt_list_for_each_entry (iter, head, siblings) {
938 if (alias_item_nr != 0) {
939 g_string_append(str, " ");
940 }
941
942 alias_item_nr++;
943 ret = get_class_specifier_name(ctx, iter, str);
944 if (ret) {
945 goto end;
946 }
947 }
948
949 end:
950 return ret;
951 }
952
953 static GQuark create_class_alias_identifier(struct ctf_visitor_generate_ir *ctx,
954 struct ctf_node *cls_specifier_list,
955 struct ctf_node *node_field_class_declarator)
956 {
957 int ret;
958 char *str_c;
959 GString *str;
960 GQuark qalias = 0;
961 struct ctf_node *iter;
962 struct bt_list_head *pointers = &node_field_class_declarator->u.field_class_declarator.pointers;
963
964 str = g_string_new("");
965 ret = get_class_specifier_list_name(ctx, cls_specifier_list, str);
966 if (ret) {
967 g_string_free(str, TRUE);
968 goto end;
969 }
970
971 bt_list_for_each_entry (iter, pointers, siblings) {
972 g_string_append(str, " *");
973
974 if (iter->u.pointer.const_qualifier) {
975 g_string_append(str, " const");
976 }
977 }
978
979 str_c = g_string_free(str, FALSE);
980 qalias = g_quark_from_string(str_c);
981 g_free(str_c);
982
983 end:
984 return qalias;
985 }
986
987 static int visit_field_class_declarator(struct ctf_visitor_generate_ir *ctx,
988 struct ctf_node *cls_specifier_list, GQuark *field_name,
989 struct ctf_node *node_field_class_declarator,
990 struct ctf_field_class **field_decl,
991 struct ctf_field_class *nested_decl)
992 {
993 /*
994 * During this whole function, nested_decl is always OURS,
995 * whereas field_decl is an output which we create, but
996 * belongs to the caller (it is moved).
997 */
998 int ret = 0;
999 *field_decl = NULL;
1000
1001 /* Validate field class declarator node */
1002 if (node_field_class_declarator) {
1003 if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_UNKNOWN) {
1004 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1005 node_field_class_declarator, "Unexpected field class declarator type: type={}",
1006 node_field_class_declarator->u.field_class_declarator.type);
1007 ret = -EINVAL;
1008 goto error;
1009 }
1010
1011 /* TODO: GCC bitfields not supported yet */
1012 if (node_field_class_declarator->u.field_class_declarator.bitfield_len != NULL) {
1013 _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
1014 "GCC bitfields are not supported as of this version.");
1015 ret = -EPERM;
1016 goto error;
1017 }
1018 }
1019
1020 /* Find the right nested declaration if not provided */
1021 if (!nested_decl) {
1022 if (node_field_class_declarator &&
1023 !bt_list_empty(&node_field_class_declarator->u.field_class_declarator.pointers)) {
1024 GQuark qalias;
1025
1026 /*
1027 * If we have a pointer declarator, it HAS to
1028 * be present in the field class aliases (else
1029 * fail).
1030 */
1031 qalias =
1032 create_class_alias_identifier(ctx, cls_specifier_list, node_field_class_declarator);
1033 nested_decl = ctx_decl_scope_lookup_alias(ctx->current_scope, g_quark_to_string(qalias),
1034 -1, true);
1035 if (!nested_decl) {
1036 _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
1037 "Cannot find class alias: name=\"{}\"",
1038 g_quark_to_string(qalias));
1039 ret = -EINVAL;
1040 goto error;
1041 }
1042
1043 if (nested_decl->type == CTF_FIELD_CLASS_TYPE_INT) {
1044 /* Pointer: force integer's base to 16 */
1045 struct ctf_field_class_int *int_fc = ctf_field_class_as_int(nested_decl);
1046
1047 int_fc->disp_base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
1048 }
1049 } else {
1050 ret = visit_field_class_specifier_list(ctx, cls_specifier_list, &nested_decl);
1051 if (ret) {
1052 BT_ASSERT(!nested_decl);
1053 goto error;
1054 }
1055 }
1056 }
1057
1058 BT_ASSERT(nested_decl);
1059
1060 if (!node_field_class_declarator) {
1061 *field_decl = nested_decl;
1062 nested_decl = NULL;
1063 goto end;
1064 }
1065
1066 if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_ID) {
1067 if (node_field_class_declarator->u.field_class_declarator.u.id) {
1068 const char *id = node_field_class_declarator->u.field_class_declarator.u.id;
1069
1070 *field_name = g_quark_from_string(id);
1071 } else {
1072 *field_name = 0;
1073 }
1074
1075 *field_decl = nested_decl;
1076 nested_decl = NULL;
1077 goto end;
1078 } else {
1079 struct ctf_node *first;
1080 struct ctf_field_class *decl = NULL;
1081 struct ctf_field_class *outer_field_decl = NULL;
1082 struct bt_list_head *length =
1083 &node_field_class_declarator->u.field_class_declarator.u.nested.length;
1084
1085 /* Create array/sequence, pass nested_decl as child */
1086 if (bt_list_empty(length)) {
1087 _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
1088 "Expecting length field reference or value.");
1089 ret = -EINVAL;
1090 goto error;
1091 }
1092
1093 first = _BT_LIST_FIRST_ENTRY(length, struct ctf_node, siblings);
1094 if (first->type != NODE_UNARY_EXPRESSION) {
1095 _BT_CPPLOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type={}", first->type);
1096 ret = -EINVAL;
1097 goto error;
1098 }
1099
1100 switch (first->u.unary_expression.type) {
1101 case UNARY_UNSIGNED_CONSTANT:
1102 {
1103 struct ctf_field_class_array *array_decl = NULL;
1104
1105 array_decl = ctf_field_class_array_create();
1106 BT_ASSERT(array_decl);
1107 array_decl->length = first->u.unary_expression.u.unsigned_constant;
1108 array_decl->base.elem_fc = nested_decl;
1109 nested_decl = NULL;
1110 decl = &array_decl->base.base;
1111 break;
1112 }
1113 case UNARY_STRING:
1114 {
1115 /* Lookup unsigned integer definition, create seq. */
1116 struct ctf_field_class_sequence *seq_decl = NULL;
1117 char *length_name = ctf_ast_concatenate_unary_strings(length);
1118
1119 if (!length_name) {
1120 _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
1121 "Cannot concatenate unary strings.");
1122 ret = -EINVAL;
1123 goto error;
1124 }
1125
1126 if (strncmp(length_name, "env.", 4) == 0) {
1127 /* This is, in fact, an array */
1128 const char *env_entry_name = &length_name[4];
1129 struct ctf_trace_class_env_entry *env_entry =
1130 ctf_trace_class_borrow_env_entry_by_name(ctx->ctf_tc, env_entry_name);
1131 struct ctf_field_class_array *array_decl;
1132
1133 if (!env_entry) {
1134 _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
1135 "Cannot find environment entry: "
1136 "name=\"{}\"",
1137 env_entry_name);
1138 ret = -EINVAL;
1139 goto error;
1140 }
1141
1142 if (env_entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
1143 _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
1144 "Wrong environment entry type "
1145 "(expecting integer): "
1146 "name=\"{}\"",
1147 env_entry_name);
1148 ret = -EINVAL;
1149 goto error;
1150 }
1151
1152 if (env_entry->value.i < 0) {
1153 _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
1154 "Invalid, negative array length: "
1155 "env-entry-name=\"{}\", "
1156 "value={}",
1157 env_entry_name, env_entry->value.i);
1158 ret = -EINVAL;
1159 goto error;
1160 }
1161
1162 array_decl = ctf_field_class_array_create();
1163 BT_ASSERT(array_decl);
1164 array_decl->length = (uint64_t) env_entry->value.i;
1165 array_decl->base.elem_fc = nested_decl;
1166 nested_decl = NULL;
1167 decl = &array_decl->base.base;
1168 } else {
1169 seq_decl = ctf_field_class_sequence_create();
1170 BT_ASSERT(seq_decl);
1171 seq_decl->base.elem_fc = nested_decl;
1172 nested_decl = NULL;
1173 g_string_assign(seq_decl->length_ref, length_name);
1174 decl = &seq_decl->base.base;
1175 }
1176
1177 g_free(length_name);
1178 break;
1179 }
1180 default:
1181 ret = -EINVAL;
1182 goto error;
1183 }
1184
1185 BT_ASSERT(!nested_decl);
1186 BT_ASSERT(decl);
1187 BT_ASSERT(!*field_decl);
1188
1189 /*
1190 * At this point, we found the next nested declaration.
1191 * We currently own this (and lost the ownership of
1192 * nested_decl in the meantime). Pass this next
1193 * nested declaration as the content of the outer
1194 * container, MOVING its ownership.
1195 */
1196 ret = visit_field_class_declarator(
1197 ctx, cls_specifier_list, field_name,
1198 node_field_class_declarator->u.field_class_declarator.u.nested.field_class_declarator,
1199 &outer_field_decl, decl);
1200 decl = NULL;
1201 if (ret) {
1202 BT_ASSERT(!outer_field_decl);
1203 ret = -EINVAL;
1204 goto error;
1205 }
1206
1207 BT_ASSERT(outer_field_decl);
1208 *field_decl = outer_field_decl;
1209 outer_field_decl = NULL;
1210 }
1211
1212 BT_ASSERT(*field_decl);
1213 goto end;
1214
1215 error:
1216 ctf_field_class_destroy(*field_decl);
1217 *field_decl = NULL;
1218
1219 if (ret >= 0) {
1220 ret = -1;
1221 }
1222
1223 end:
1224 ctf_field_class_destroy(nested_decl);
1225 nested_decl = NULL;
1226 return ret;
1227 }
1228
1229 static int visit_struct_decl_field(struct ctf_visitor_generate_ir *ctx,
1230 struct ctf_field_class_struct *struct_decl,
1231 struct ctf_node *cls_specifier_list,
1232 struct bt_list_head *field_class_declarators)
1233 {
1234 int ret = 0;
1235 struct ctf_node *iter;
1236 struct ctf_field_class *field_decl = NULL;
1237
1238 bt_list_for_each_entry (iter, field_class_declarators, siblings) {
1239 field_decl = NULL;
1240 GQuark qfield_name;
1241 const char *field_name;
1242
1243 ret = visit_field_class_declarator(ctx, cls_specifier_list, &qfield_name, iter, &field_decl,
1244 NULL);
1245 if (ret) {
1246 BT_ASSERT(!field_decl);
1247 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
1248 "Cannot visit field class declarator: ret={}", ret);
1249 goto error;
1250 }
1251
1252 BT_ASSERT(field_decl);
1253 field_name = g_quark_to_string(qfield_name);
1254
1255 /* Check if field with same name already exists */
1256 if (ctf_field_class_struct_borrow_member_by_name(struct_decl, field_name)) {
1257 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
1258 "Duplicate field in structure field class: "
1259 "field-name=\"{}\"",
1260 field_name);
1261 ret = -EINVAL;
1262 goto error;
1263 }
1264
1265 /* Add field to structure */
1266 ctf_field_class_struct_append_member(struct_decl, field_name, field_decl);
1267 field_decl = NULL;
1268 }
1269
1270 return 0;
1271
1272 error:
1273 ctf_field_class_destroy(field_decl);
1274 field_decl = NULL;
1275 return ret;
1276 }
1277
1278 static int visit_variant_decl_field(struct ctf_visitor_generate_ir *ctx,
1279 struct ctf_field_class_variant *variant_decl,
1280 struct ctf_node *cls_specifier_list,
1281 struct bt_list_head *field_class_declarators)
1282 {
1283 int ret = 0;
1284 struct ctf_node *iter;
1285 struct ctf_field_class *field_decl = NULL;
1286
1287 bt_list_for_each_entry (iter, field_class_declarators, siblings) {
1288 field_decl = NULL;
1289 GQuark qfield_name;
1290 const char *field_name;
1291
1292 ret = visit_field_class_declarator(ctx, cls_specifier_list, &qfield_name, iter, &field_decl,
1293 NULL);
1294 if (ret) {
1295 BT_ASSERT(!field_decl);
1296 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
1297 "Cannot visit field class declarator: ret={}", ret);
1298 goto error;
1299 }
1300
1301 BT_ASSERT(field_decl);
1302 field_name = g_quark_to_string(qfield_name);
1303
1304 /* Check if field with same name already exists */
1305 if (ctf_field_class_variant_borrow_option_by_name(variant_decl, field_name)) {
1306 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
1307 "Duplicate field in variant field class: "
1308 "field-name=\"{}\"",
1309 field_name);
1310 ret = -EINVAL;
1311 goto error;
1312 }
1313
1314 /* Add field to structure */
1315 ctf_field_class_variant_append_option(variant_decl, field_name, field_decl);
1316 field_decl = NULL;
1317 }
1318
1319 return 0;
1320
1321 error:
1322 ctf_field_class_destroy(field_decl);
1323 field_decl = NULL;
1324 return ret;
1325 }
1326
1327 static int visit_field_class_def(struct ctf_visitor_generate_ir *ctx,
1328 struct ctf_node *cls_specifier_list,
1329 struct bt_list_head *field_class_declarators)
1330 {
1331 int ret = 0;
1332 GQuark qidentifier;
1333 struct ctf_node *iter;
1334 struct ctf_field_class *class_decl = NULL;
1335
1336 bt_list_for_each_entry (iter, field_class_declarators, siblings) {
1337 ret = visit_field_class_declarator(ctx, cls_specifier_list, &qidentifier, iter, &class_decl,
1338 NULL);
1339 if (ret) {
1340 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit field class declarator: ret={}", ret);
1341 ret = -EINVAL;
1342 goto end;
1343 }
1344
1345 /* Do not allow field class def and alias of untagged variants */
1346 if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
1347 struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(class_decl);
1348
1349 if (var_fc->tag_path.path->len == 0) {
1350 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1351 iter, "Type definition of untagged variant field class is not allowed.");
1352 ret = -EPERM;
1353 goto end;
1354 }
1355 }
1356
1357 ret = ctx_decl_scope_register_alias(ctx->current_scope, g_quark_to_string(qidentifier),
1358 class_decl);
1359 if (ret) {
1360 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot register field class alias: name=\"{}\"",
1361 g_quark_to_string(qidentifier));
1362 goto end;
1363 }
1364 }
1365
1366 end:
1367 ctf_field_class_destroy(class_decl);
1368 class_decl = NULL;
1369 return ret;
1370 }
1371
1372 static int visit_field_class_alias(struct ctf_visitor_generate_ir *ctx, struct ctf_node *target,
1373 struct ctf_node *alias)
1374 {
1375 int ret = 0;
1376 GQuark qalias;
1377 struct ctf_node *node;
1378 GQuark qdummy_field_name;
1379 struct ctf_field_class *class_decl = NULL;
1380
1381 /* Create target field class */
1382 if (bt_list_empty(&target->u.field_class_alias_target.field_class_declarators)) {
1383 node = NULL;
1384 } else {
1385 node = _BT_LIST_FIRST_ENTRY(&target->u.field_class_alias_target.field_class_declarators,
1386 struct ctf_node, siblings);
1387 }
1388
1389 ret = visit_field_class_declarator(
1390 ctx, target->u.field_class_alias_target.field_class_specifier_list, &qdummy_field_name,
1391 node, &class_decl, NULL);
1392 if (ret) {
1393 BT_ASSERT(!class_decl);
1394 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot visit field class declarator: ret={}", ret);
1395 goto end;
1396 }
1397
1398 /* Do not allow field class def and alias of untagged variants */
1399 if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
1400 struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(class_decl);
1401
1402 if (var_fc->tag_path.path->len == 0) {
1403 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1404 target, "Type definition of untagged variant field class is not allowed.");
1405 ret = -EPERM;
1406 goto end;
1407 }
1408 }
1409
1410 /*
1411 * The semantic validator does not check whether the target is
1412 * abstract or not (if it has an identifier). Check it here.
1413 */
1414 if (qdummy_field_name != 0) {
1415 _BT_CPPLOGE_APPEND_CAUSE_NODE(target, "Expecting empty identifier: id=\"{}\"",
1416 g_quark_to_string(qdummy_field_name));
1417 ret = -EINVAL;
1418 goto end;
1419 }
1420
1421 /* Create alias identifier */
1422 node = _BT_LIST_FIRST_ENTRY(&alias->u.field_class_alias_name.field_class_declarators,
1423 struct ctf_node, siblings);
1424 qalias = create_class_alias_identifier(
1425 ctx, alias->u.field_class_alias_name.field_class_specifier_list, node);
1426 ret = ctx_decl_scope_register_alias(ctx->current_scope, g_quark_to_string(qalias), class_decl);
1427 if (ret) {
1428 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot register class alias: name=\"{}\"",
1429 g_quark_to_string(qalias));
1430 goto end;
1431 }
1432
1433 end:
1434 ctf_field_class_destroy(class_decl);
1435 class_decl = NULL;
1436 return ret;
1437 }
1438
1439 static int visit_struct_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *entry_node,
1440 struct ctf_field_class_struct *struct_decl)
1441 {
1442 int ret = 0;
1443
1444 switch (entry_node->type) {
1445 case NODE_TYPEDEF:
1446 ret = visit_field_class_def(ctx, entry_node->u.field_class_def.field_class_specifier_list,
1447 &entry_node->u.field_class_def.field_class_declarators);
1448 if (ret) {
1449 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1450 entry_node, "Cannot add field class found in structure field class: ret={}", ret);
1451 goto end;
1452 }
1453 break;
1454 case NODE_TYPEALIAS:
1455 ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target,
1456 entry_node->u.field_class_alias.alias);
1457 if (ret) {
1458 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1459 entry_node, "Cannot add field class alias found in structure field class: ret={}",
1460 ret);
1461 goto end;
1462 }
1463 break;
1464 case NODE_STRUCT_OR_VARIANT_DECLARATION:
1465 /* Field */
1466 ret = visit_struct_decl_field(
1467 ctx, struct_decl,
1468 entry_node->u.struct_or_variant_declaration.field_class_specifier_list,
1469 &entry_node->u.struct_or_variant_declaration.field_class_declarators);
1470 if (ret) {
1471 goto end;
1472 }
1473 break;
1474 default:
1475 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type={}",
1476 entry_node->type);
1477 ret = -EINVAL;
1478 goto end;
1479 }
1480
1481 end:
1482 return ret;
1483 }
1484
1485 static int visit_variant_decl_entry(struct ctf_visitor_generate_ir *ctx,
1486 struct ctf_node *entry_node,
1487 struct ctf_field_class_variant *variant_decl)
1488 {
1489 int ret = 0;
1490
1491 switch (entry_node->type) {
1492 case NODE_TYPEDEF:
1493 ret = visit_field_class_def(ctx, entry_node->u.field_class_def.field_class_specifier_list,
1494 &entry_node->u.field_class_def.field_class_declarators);
1495 if (ret) {
1496 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1497 entry_node, "Cannot add field class found in variant field class: ret={}", ret);
1498 goto end;
1499 }
1500 break;
1501 case NODE_TYPEALIAS:
1502 ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target,
1503 entry_node->u.field_class_alias.alias);
1504 if (ret) {
1505 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1506 entry_node, "Cannot add field class alias found in variant field class: ret={}",
1507 ret);
1508 goto end;
1509 }
1510 break;
1511 case NODE_STRUCT_OR_VARIANT_DECLARATION:
1512 /* Field */
1513 ret = visit_variant_decl_field(
1514 ctx, variant_decl,
1515 entry_node->u.struct_or_variant_declaration.field_class_specifier_list,
1516 &entry_node->u.struct_or_variant_declaration.field_class_declarators);
1517 if (ret) {
1518 goto end;
1519 }
1520 break;
1521 default:
1522 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type={}",
1523 entry_node->type);
1524 ret = -EINVAL;
1525 goto end;
1526 }
1527
1528 end:
1529 return ret;
1530 }
1531
1532 static int visit_struct_decl(struct ctf_visitor_generate_ir *ctx, const char *name,
1533 struct bt_list_head *decl_list, int has_body,
1534 struct bt_list_head *min_align,
1535 struct ctf_field_class_struct **struct_decl)
1536 {
1537 int ret = 0;
1538
1539 BT_ASSERT(struct_decl);
1540 *struct_decl = NULL;
1541
1542 /* For named struct (without body), lookup in declaration scope */
1543 if (!has_body) {
1544 if (!name) {
1545 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
1546 "Bodyless structure field class: missing name.");
1547 ret = -EPERM;
1548 goto error;
1549 }
1550
1551 *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope, name, -1, true);
1552 if (!*struct_decl) {
1553 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1554 ctx->logger, "Cannot find structure field class: name=\"struct {}\"", name);
1555 ret = -EINVAL;
1556 goto error;
1557 }
1558 } else {
1559 struct ctf_node *entry_node;
1560 uint64_t min_align_value = 0;
1561
1562 if (name) {
1563 if (ctx_decl_scope_lookup_struct(ctx->current_scope, name, 1, false)) {
1564 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1565 ctx->logger,
1566 "Structure field class already declared in local scope: "
1567 "name=\"struct {}\"",
1568 name);
1569 ret = -EINVAL;
1570 goto error;
1571 }
1572 }
1573
1574 if (!bt_list_empty(min_align)) {
1575 ret = get_unary_unsigned(ctx, min_align, &min_align_value);
1576 if (ret) {
1577 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1578 ctx->logger,
1579 "Unexpected unary expression for structure field class's `align` attribute: "
1580 "ret={}",
1581 ret);
1582 goto error;
1583 }
1584 }
1585
1586 *struct_decl = ctf_field_class_struct_create();
1587 BT_ASSERT(*struct_decl);
1588
1589 if (min_align_value != 0) {
1590 (*struct_decl)->base.alignment = min_align_value;
1591 }
1592
1593 _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
1594
1595 bt_list_for_each_entry (entry_node, decl_list, siblings) {
1596 ret = visit_struct_decl_entry(ctx, entry_node, *struct_decl);
1597 if (ret) {
1598 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node,
1599 "Cannot visit structure field class entry: "
1600 "ret={}",
1601 ret);
1602 ctx_pop_scope(ctx);
1603 goto error;
1604 }
1605 }
1606
1607 ctx_pop_scope(ctx);
1608
1609 if (name) {
1610 ret = ctx_decl_scope_register_struct(ctx->current_scope, name, *struct_decl);
1611 if (ret) {
1612 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1613 ctx->logger,
1614 "Cannot register structure field class in declaration scope: "
1615 "name=\"struct {}\", ret={}",
1616 name, ret);
1617 goto error;
1618 }
1619 }
1620 }
1621
1622 return 0;
1623
1624 error:
1625 ctf_field_class_destroy(&(*struct_decl)->base);
1626 *struct_decl = NULL;
1627 return ret;
1628 }
1629
1630 static int visit_variant_decl(struct ctf_visitor_generate_ir *ctx, const char *name,
1631 const char *tag, struct bt_list_head *decl_list, int has_body,
1632 struct ctf_field_class_variant **variant_decl)
1633 {
1634 int ret = 0;
1635 struct ctf_field_class_variant *untagged_variant_decl = NULL;
1636
1637 BT_ASSERT(variant_decl);
1638 *variant_decl = NULL;
1639
1640 /* For named variant (without body), lookup in declaration scope */
1641 if (!has_body) {
1642 if (!name) {
1643 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
1644 "Bodyless variant field class: missing name.");
1645 ret = -EPERM;
1646 goto error;
1647 }
1648
1649 untagged_variant_decl = ctx_decl_scope_lookup_variant(ctx->current_scope, name, -1, true);
1650 if (!untagged_variant_decl) {
1651 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1652 ctx->logger, "Cannot find variant field class: name=\"variant {}\"", name);
1653 ret = -EINVAL;
1654 goto error;
1655 }
1656 } else {
1657 struct ctf_node *entry_node;
1658
1659 if (name) {
1660 if (ctx_decl_scope_lookup_variant(ctx->current_scope, name, 1, false)) {
1661 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
1662 "Variant field class already declared in local scope: "
1663 "name=\"variant {}\"",
1664 name);
1665 ret = -EINVAL;
1666 goto error;
1667 }
1668 }
1669
1670 untagged_variant_decl = ctf_field_class_variant_create();
1671 BT_ASSERT(untagged_variant_decl);
1672 _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
1673
1674 bt_list_for_each_entry (entry_node, decl_list, siblings) {
1675 ret = visit_variant_decl_entry(ctx, entry_node, untagged_variant_decl);
1676 if (ret) {
1677 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node,
1678 "Cannot visit variant field class entry: "
1679 "ret={}",
1680 ret);
1681 ctx_pop_scope(ctx);
1682 goto error;
1683 }
1684 }
1685
1686 ctx_pop_scope(ctx);
1687
1688 if (name) {
1689 ret = ctx_decl_scope_register_variant(ctx->current_scope, name, untagged_variant_decl);
1690 if (ret) {
1691 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1692 ctx->logger,
1693 "Cannot register variant field class in declaration scope: "
1694 "name=\"variant {}\", ret={}",
1695 name, ret);
1696 goto error;
1697 }
1698 }
1699 }
1700
1701 /*
1702 * If tagged, create tagged variant and return; otherwise
1703 * return untagged variant.
1704 */
1705 if (!tag) {
1706 *variant_decl = untagged_variant_decl;
1707 untagged_variant_decl = NULL;
1708 } else {
1709 /*
1710 * At this point, we have a fresh untagged variant; nobody
1711 * else owns it. Set its tag now.
1712 */
1713 g_string_assign(untagged_variant_decl->tag_ref, tag);
1714 *variant_decl = untagged_variant_decl;
1715 untagged_variant_decl = NULL;
1716 }
1717
1718 BT_ASSERT(!untagged_variant_decl);
1719 BT_ASSERT(*variant_decl);
1720 return 0;
1721
1722 error:
1723 ctf_field_class_destroy(&untagged_variant_decl->base);
1724 untagged_variant_decl = NULL;
1725 ctf_field_class_destroy(&(*variant_decl)->base);
1726 *variant_decl = NULL;
1727 return ret;
1728 }
1729
1730 struct uori
1731 {
1732 bool is_signed;
1733 union
1734 {
1735 uint64_t u;
1736 uint64_t i;
1737 } value;
1738 };
1739
1740 static int visit_enum_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *enumerator,
1741 struct ctf_field_class_enum *enum_decl, struct uori *last)
1742 {
1743 int ret = 0;
1744 int nr_vals = 0;
1745 struct ctf_node *iter;
1746 struct uori start = {
1747 .is_signed = false,
1748 .value =
1749 {
1750 .u = 0,
1751 },
1752 };
1753 struct uori end = {
1754 .is_signed = false,
1755 .value =
1756 {
1757 .u = 0,
1758 },
1759 };
1760 const char *label = enumerator->u.enumerator.id;
1761 struct bt_list_head *values = &enumerator->u.enumerator.values;
1762
1763 bt_list_for_each_entry (iter, values, siblings) {
1764 struct uori *target;
1765
1766 if (iter->type != NODE_UNARY_EXPRESSION) {
1767 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
1768 "Wrong expression for enumeration field class label: "
1769 "node-type={}, label=\"{}\"",
1770 iter->type, label);
1771 ret = -EINVAL;
1772 goto error;
1773 }
1774
1775 if (nr_vals == 0) {
1776 target = &start;
1777 } else {
1778 target = &end;
1779 }
1780
1781 switch (iter->u.unary_expression.type) {
1782 case UNARY_SIGNED_CONSTANT:
1783 target->is_signed = true;
1784 target->value.i = iter->u.unary_expression.u.signed_constant;
1785 break;
1786 case UNARY_UNSIGNED_CONSTANT:
1787 target->is_signed = false;
1788 target->value.u = iter->u.unary_expression.u.unsigned_constant;
1789 break;
1790 default:
1791 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
1792 "Invalid enumeration field class entry: "
1793 "expecting constant signed or unsigned integer: "
1794 "node-type={}, label=\"{}\"",
1795 iter->u.unary_expression.type, label);
1796 ret = -EINVAL;
1797 goto error;
1798 }
1799
1800 if (nr_vals > 1) {
1801 _BT_CPPLOGE_APPEND_CAUSE_NODE(
1802 iter, "Invalid enumeration field class entry: label=\"{}\"", label);
1803 ret = -EINVAL;
1804 goto error;
1805 }
1806
1807 nr_vals++;
1808 }
1809
1810 if (nr_vals == 0) {
1811 start = *last;
1812 }
1813
1814 if (nr_vals <= 1) {
1815 end = start;
1816 }
1817
1818 if (end.is_signed) {
1819 last->value.i = end.value.i + 1;
1820 } else {
1821 last->value.u = end.value.u + 1;
1822 }
1823
1824 ctf_field_class_enum_map_range(enum_decl, label, start.value.u, end.value.u);
1825 return 0;
1826
1827 error:
1828 return ret;
1829 }
1830
1831 static int visit_enum_decl(struct ctf_visitor_generate_ir *ctx, const char *name,
1832 struct ctf_node *container_cls, struct bt_list_head *enumerator_list,
1833 int has_body, struct ctf_field_class_enum **enum_decl)
1834 {
1835 int ret = 0;
1836 GQuark qdummy_id;
1837 struct ctf_field_class_int *integer_decl = NULL;
1838
1839 BT_ASSERT(enum_decl);
1840 *enum_decl = NULL;
1841
1842 /* For named enum (without body), lookup in declaration scope */
1843 if (!has_body) {
1844 if (!name) {
1845 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
1846 "Bodyless enumeration field class: missing name.");
1847 ret = -EPERM;
1848 goto error;
1849 }
1850
1851 *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope, name, -1, true);
1852 if (!*enum_decl) {
1853 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
1854 "Cannot find enumeration field class: "
1855 "name=\"enum {}\"",
1856 name);
1857 ret = -EINVAL;
1858 goto error;
1859 }
1860 } else {
1861 struct ctf_node *iter;
1862 struct uori last_value = {
1863 .is_signed = false,
1864 .value =
1865 {
1866 .u = 0,
1867 },
1868 };
1869
1870 if (name) {
1871 if (ctx_decl_scope_lookup_enum(ctx->current_scope, name, 1, false)) {
1872 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1873 ctx->logger,
1874 "Enumeration field class already declared in local scope: "
1875 "name=\"enum {}\"",
1876 name);
1877 ret = -EINVAL;
1878 goto error;
1879 }
1880 }
1881
1882 if (!container_cls) {
1883 integer_decl = ctf_field_class_as_int(
1884 ctx_decl_scope_lookup_alias(ctx->current_scope, "int", -1, true));
1885 if (!integer_decl) {
1886 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1887 ctx->logger,
1888 "Cannot find implicit `int` field class alias for enumeration field class.");
1889 ret = -EINVAL;
1890 goto error;
1891 }
1892 } else {
1893 ctf_field_class *decl;
1894
1895 ret = visit_field_class_declarator(ctx, container_cls, &qdummy_id, NULL, &decl, NULL);
1896 if (ret) {
1897 BT_ASSERT(!decl);
1898 ret = -EINVAL;
1899 goto error;
1900 }
1901
1902 integer_decl = ctf_field_class_as_int(decl);
1903 }
1904
1905 BT_ASSERT(integer_decl);
1906
1907 if (integer_decl->base.base.type != CTF_FIELD_CLASS_TYPE_INT) {
1908 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1909 ctx->logger,
1910 "Container field class for enumeration field class is not an integer field class: "
1911 "fc-type={}",
1912 integer_decl->base.base.type);
1913 ret = -EINVAL;
1914 goto error;
1915 }
1916
1917 *enum_decl = ctf_field_class_enum_create();
1918 BT_ASSERT(*enum_decl);
1919 (*enum_decl)->base.base.base.alignment = integer_decl->base.base.alignment;
1920 ctf_field_class_int_copy_content(&(*enum_decl)->base, integer_decl);
1921 last_value.is_signed = (*enum_decl)->base.is_signed;
1922
1923 bt_list_for_each_entry (iter, enumerator_list, siblings) {
1924 ret = visit_enum_decl_entry(ctx, iter, *enum_decl, &last_value);
1925 if (ret) {
1926 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
1927 "Cannot visit enumeration field class entry: "
1928 "ret={}",
1929 ret);
1930 goto error;
1931 }
1932 }
1933
1934 if (name) {
1935 ret = ctx_decl_scope_register_enum(ctx->current_scope, name, *enum_decl);
1936 if (ret) {
1937 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1938 ctx->logger,
1939 "Cannot register enumeration field class in declaration scope: "
1940 "ret={}",
1941 ret);
1942 goto error;
1943 }
1944 }
1945 }
1946
1947 goto end;
1948
1949 error:
1950 ctf_field_class_destroy(&(*enum_decl)->base.base.base);
1951 *enum_decl = NULL;
1952
1953 end:
1954 ctf_field_class_destroy(&integer_decl->base.base);
1955 integer_decl = NULL;
1956 return ret;
1957 }
1958
1959 static int visit_field_class_specifier(struct ctf_visitor_generate_ir *ctx,
1960 struct ctf_node *cls_specifier_list,
1961 struct ctf_field_class **decl)
1962 {
1963 int ret = 0;
1964 GString *str = NULL;
1965
1966 *decl = NULL;
1967 str = g_string_new("");
1968 ret = get_class_specifier_list_name(ctx, cls_specifier_list, str);
1969 if (ret) {
1970 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
1971 "Cannot get field class specifier list's name: ret={}", ret);
1972 goto error;
1973 }
1974
1975 *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1, true);
1976 if (!*decl) {
1977 _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
1978 "Cannot find field class alias: name=\"{}\"", str->str);
1979 ret = -EINVAL;
1980 goto error;
1981 }
1982
1983 goto end;
1984
1985 error:
1986 ctf_field_class_destroy(*decl);
1987 *decl = NULL;
1988
1989 end:
1990 if (str) {
1991 g_string_free(str, TRUE);
1992 }
1993
1994 return ret;
1995 }
1996
1997 static int visit_integer_decl(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *expressions,
1998 struct ctf_field_class_int **integer_decl)
1999 {
2000 int set = 0;
2001 int ret = 0;
2002 int signedness = 0;
2003 struct ctf_node *expression;
2004 uint64_t alignment = 0, size = 0;
2005 struct ctf_clock_class *mapped_clock_class = NULL;
2006 enum ctf_encoding encoding = CTF_ENCODING_NONE;
2007 bt_field_class_integer_preferred_display_base base =
2008 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
2009 enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
2010
2011 *integer_decl = NULL;
2012
2013 bt_list_for_each_entry (expression, expressions, siblings) {
2014 struct ctf_node *left, *right;
2015
2016 left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings);
2017 right =
2018 _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings);
2019
2020 if (left->u.unary_expression.type != UNARY_STRING) {
2021 _BT_CPPLOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type={}",
2022 left->u.unary_expression.type);
2023 ret = -EINVAL;
2024 goto error;
2025 }
2026
2027 if (strcmp(left->u.unary_expression.u.string, "signed") == 0) {
2028 if (_IS_SET(&set, _INTEGER_SIGNED_SET)) {
2029 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "signed", "integer field class");
2030 ret = -EPERM;
2031 goto error;
2032 }
2033
2034 signedness = get_boolean(ctx, right);
2035 if (signedness < 0) {
2036 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2037 right,
2038 "Invalid boolean value for integer field class's `signed` attribute: "
2039 "ret={}",
2040 ret);
2041 ret = -EINVAL;
2042 goto error;
2043 }
2044
2045 _SET(&set, _INTEGER_SIGNED_SET);
2046 } else if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) {
2047 if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) {
2048 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order", "integer field class");
2049 ret = -EPERM;
2050 goto error;
2051 }
2052
2053 byte_order = get_real_byte_order(ctx, right);
2054 if (byte_order == CTF_BYTE_ORDER_UNKNOWN) {
2055 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2056 right,
2057 "Invalid `byte_order` attribute in integer field class: "
2058 "ret={}",
2059 ret);
2060 ret = -EINVAL;
2061 goto error;
2062 }
2063
2064 _SET(&set, _INTEGER_BYTE_ORDER_SET);
2065 } else if (strcmp(left->u.unary_expression.u.string, "size") == 0) {
2066 if (_IS_SET(&set, _INTEGER_SIZE_SET)) {
2067 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "size", "integer field class");
2068 ret = -EPERM;
2069 goto error;
2070 }
2071
2072 if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
2073 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2074 "Invalid `size` attribute in integer field class: "
2075 "expecting unsigned constant integer: "
2076 "node-type={}",
2077 right->u.unary_expression.type);
2078 ret = -EINVAL;
2079 goto error;
2080 }
2081
2082 size = right->u.unary_expression.u.unsigned_constant;
2083 if (size == 0) {
2084 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2085 "Invalid `size` attribute in integer field class: "
2086 "expecting positive constant integer: "
2087 "size={}",
2088 size);
2089 ret = -EINVAL;
2090 goto error;
2091 } else if (size > 64) {
2092 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2093 right,
2094 "Invalid `size` attribute in integer field class: "
2095 "integer fields over 64 bits are not supported as of this version: "
2096 "size={}",
2097 size);
2098 ret = -EINVAL;
2099 goto error;
2100 }
2101
2102 _SET(&set, _INTEGER_SIZE_SET);
2103 } else if (strcmp(left->u.unary_expression.u.string, "align") == 0) {
2104 if (_IS_SET(&set, _INTEGER_ALIGN_SET)) {
2105 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "align", "integer field class");
2106 ret = -EPERM;
2107 goto error;
2108 }
2109
2110 if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
2111 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2112 "Invalid `align` attribute in integer field class: "
2113 "expecting unsigned constant integer: "
2114 "node-type={}",
2115 right->u.unary_expression.type);
2116 ret = -EINVAL;
2117 goto error;
2118 }
2119
2120 alignment = right->u.unary_expression.u.unsigned_constant;
2121 if (!is_align_valid(alignment)) {
2122 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2123 "Invalid `align` attribute in integer field class: "
2124 "expecting power of two: "
2125 "align={}",
2126 alignment);
2127 ret = -EINVAL;
2128 goto error;
2129 }
2130
2131 _SET(&set, _INTEGER_ALIGN_SET);
2132 } else if (strcmp(left->u.unary_expression.u.string, "base") == 0) {
2133 if (_IS_SET(&set, _INTEGER_BASE_SET)) {
2134 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "base", "integer field class");
2135 ret = -EPERM;
2136 goto error;
2137 }
2138
2139 switch (right->u.unary_expression.type) {
2140 case UNARY_UNSIGNED_CONSTANT:
2141 {
2142 uint64_t constant = right->u.unary_expression.u.unsigned_constant;
2143
2144 switch (constant) {
2145 case 2:
2146 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
2147 break;
2148 case 8:
2149 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
2150 break;
2151 case 10:
2152 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
2153 break;
2154 case 16:
2155 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
2156 break;
2157 default:
2158 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2159 right,
2160 "Invalid `base` attribute in integer field class: "
2161 "base={}",
2162 right->u.unary_expression.u.unsigned_constant);
2163 ret = -EINVAL;
2164 goto error;
2165 }
2166 break;
2167 }
2168 case UNARY_STRING:
2169 {
2170 char *s_right =
2171 ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
2172 if (!s_right) {
2173 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2174 right,
2175 "Unexpected unary expression for integer field class's `base` attribute.");
2176 ret = -EINVAL;
2177 goto error;
2178 }
2179
2180 if (strcmp(s_right, "decimal") == 0 || strcmp(s_right, "dec") == 0 ||
2181 strcmp(s_right, "d") == 0 || strcmp(s_right, "i") == 0 ||
2182 strcmp(s_right, "u") == 0) {
2183 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
2184 } else if (strcmp(s_right, "hexadecimal") == 0 || strcmp(s_right, "hex") == 0 ||
2185 strcmp(s_right, "x") == 0 || strcmp(s_right, "X") == 0 ||
2186 strcmp(s_right, "p") == 0) {
2187 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
2188 } else if (strcmp(s_right, "octal") == 0 || strcmp(s_right, "oct") == 0 ||
2189 strcmp(s_right, "o") == 0) {
2190 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
2191 } else if (strcmp(s_right, "binary") == 0 || strcmp(s_right, "b") == 0) {
2192 base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
2193 } else {
2194 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2195 right,
2196 "Unexpected unary expression for integer field class's `base` attribute: "
2197 "base=\"{}\"",
2198 s_right);
2199 g_free(s_right);
2200 ret = -EINVAL;
2201 goto error;
2202 }
2203
2204 g_free(s_right);
2205 break;
2206 }
2207 default:
2208 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2209 right, "Invalid `base` attribute in integer field class: "
2210 "expecting unsigned constant integer or unary string.");
2211 ret = -EINVAL;
2212 goto error;
2213 }
2214
2215 _SET(&set, _INTEGER_BASE_SET);
2216 } else if (strcmp(left->u.unary_expression.u.string, "encoding") == 0) {
2217 char *s_right;
2218
2219 if (_IS_SET(&set, _INTEGER_ENCODING_SET)) {
2220 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "integer field class");
2221 ret = -EPERM;
2222 goto error;
2223 }
2224
2225 if (right->u.unary_expression.type != UNARY_STRING) {
2226 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2227 right, "Invalid `encoding` attribute in integer field class: "
2228 "expecting unary string.");
2229 ret = -EINVAL;
2230 goto error;
2231 }
2232
2233 s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
2234 if (!s_right) {
2235 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2236 right,
2237 "Unexpected unary expression for integer field class's `encoding` attribute.");
2238 ret = -EINVAL;
2239 goto error;
2240 }
2241
2242 if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 ||
2243 strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 ||
2244 strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) {
2245 encoding = CTF_ENCODING_UTF8;
2246 } else if (strcmp(s_right, "none") == 0) {
2247 encoding = CTF_ENCODING_NONE;
2248 } else {
2249 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2250 right,
2251 "Invalid `encoding` attribute in integer field class: "
2252 "unknown encoding: encoding=\"{}\"",
2253 s_right);
2254 g_free(s_right);
2255 ret = -EINVAL;
2256 goto error;
2257 }
2258
2259 g_free(s_right);
2260 _SET(&set, _INTEGER_ENCODING_SET);
2261 } else if (strcmp(left->u.unary_expression.u.string, "map") == 0) {
2262 const char *clock_name;
2263
2264 if (_IS_SET(&set, _INTEGER_MAP_SET)) {
2265 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "map", "integer field class");
2266 ret = -EPERM;
2267 goto error;
2268 }
2269
2270 if (right->u.unary_expression.type != UNARY_STRING) {
2271 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2272 "Invalid `map` attribute in integer field class: "
2273 "expecting unary string.");
2274 ret = -EINVAL;
2275 goto error;
2276 }
2277
2278 clock_name = get_map_clock_name_value(&expression->u.ctf_expression.right);
2279 if (!clock_name) {
2280 char *s_right =
2281 ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
2282
2283 if (!s_right) {
2284 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2285 right,
2286 "Unexpected unary expression for integer field class's `map` attribute.");
2287 ret = -EINVAL;
2288 goto error;
2289 }
2290
2291 _BT_CPPLOGE_NODE(right,
2292 "Invalid `map` attribute in integer field class: "
2293 "cannot find clock class at this point: name=\"{}\"",
2294 s_right);
2295 _SET(&set, _INTEGER_MAP_SET);
2296 g_free(s_right);
2297 continue;
2298 }
2299
2300 mapped_clock_class =
2301 ctf_trace_class_borrow_clock_class_by_name(ctx->ctf_tc, clock_name);
2302 if (!mapped_clock_class) {
2303 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2304 "Invalid `map` attribute in integer field class: "
2305 "cannot find clock class at this point: name=\"{}\"",
2306 clock_name);
2307 ret = -EINVAL;
2308 goto error;
2309 }
2310
2311 _SET(&set, _INTEGER_MAP_SET);
2312 } else {
2313 _BT_CPPLOGW_NODE(left,
2314 "Unknown attribute in integer field class: "
2315 "attr-name=\"{}\"",
2316 left->u.unary_expression.u.string);
2317 }
2318 }
2319
2320 if (!_IS_SET(&set, _INTEGER_SIZE_SET)) {
2321 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
2322 "Missing `size` attribute in integer field class.");
2323 ret = -EPERM;
2324 goto error;
2325 }
2326
2327 if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) {
2328 if (size % CHAR_BIT) {
2329 /* Bit-packed alignment */
2330 alignment = 1;
2331 } else {
2332 /* Byte-packed alignment */
2333 alignment = CHAR_BIT;
2334 }
2335 }
2336
2337 *integer_decl = ctf_field_class_int_create();
2338 BT_ASSERT(*integer_decl);
2339 (*integer_decl)->base.base.alignment = alignment;
2340 (*integer_decl)->base.byte_order = byte_order;
2341 (*integer_decl)->base.size = size;
2342 (*integer_decl)->is_signed = (signedness > 0);
2343 (*integer_decl)->disp_base = base;
2344 (*integer_decl)->encoding = encoding;
2345 (*integer_decl)->mapped_clock_class = mapped_clock_class;
2346 return 0;
2347
2348 error:
2349 ctf_field_class_destroy(&(*integer_decl)->base.base);
2350 *integer_decl = NULL;
2351 return ret;
2352 }
2353
2354 static int visit_floating_point_number_decl(struct ctf_visitor_generate_ir *ctx,
2355 struct bt_list_head *expressions,
2356 struct ctf_field_class_float **float_decl)
2357 {
2358 int set = 0;
2359 int ret = 0;
2360 struct ctf_node *expression;
2361 uint64_t alignment = 1, exp_dig = 0, mant_dig = 0;
2362 enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
2363
2364 *float_decl = NULL;
2365
2366 bt_list_for_each_entry (expression, expressions, siblings) {
2367 struct ctf_node *left, *right;
2368
2369 left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings);
2370 right =
2371 _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings);
2372
2373 if (left->u.unary_expression.type != UNARY_STRING) {
2374 _BT_CPPLOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type={}",
2375 left->u.unary_expression.type);
2376 ret = -EINVAL;
2377 goto error;
2378 }
2379
2380 if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) {
2381 if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) {
2382 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order",
2383 "floating point number field class");
2384 ret = -EPERM;
2385 goto error;
2386 }
2387
2388 byte_order = get_real_byte_order(ctx, right);
2389 if (byte_order == CTF_BYTE_ORDER_UNKNOWN) {
2390 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2391 right,
2392 "Invalid `byte_order` attribute in floating point number field class: "
2393 "ret={}",
2394 ret);
2395 ret = -EINVAL;
2396 goto error;
2397 }
2398
2399 _SET(&set, _FLOAT_BYTE_ORDER_SET);
2400 } else if (strcmp(left->u.unary_expression.u.string, "exp_dig") == 0) {
2401 if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
2402 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "exp_dig",
2403 "floating point number field class");
2404 ret = -EPERM;
2405 goto error;
2406 }
2407
2408 if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
2409 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2410 right,
2411 "Invalid `exp_dig` attribute in floating point number field class: "
2412 "expecting unsigned constant integer: "
2413 "node-type={}",
2414 right->u.unary_expression.type);
2415 ret = -EINVAL;
2416 goto error;
2417 }
2418
2419 exp_dig = right->u.unary_expression.u.unsigned_constant;
2420 _SET(&set, _FLOAT_EXP_DIG_SET);
2421 } else if (strcmp(left->u.unary_expression.u.string, "mant_dig") == 0) {
2422 if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
2423 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "mant_dig",
2424 "floating point number field class");
2425 ret = -EPERM;
2426 goto error;
2427 }
2428
2429 if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
2430 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2431 right,
2432 "Invalid `mant_dig` attribute in floating point number field class: "
2433 "expecting unsigned constant integer: "
2434 "node-type={}",
2435 right->u.unary_expression.type);
2436 ret = -EINVAL;
2437 goto error;
2438 }
2439
2440 mant_dig = right->u.unary_expression.u.unsigned_constant;
2441 _SET(&set, _FLOAT_MANT_DIG_SET);
2442 } else if (strcmp(left->u.unary_expression.u.string, "align") == 0) {
2443 if (_IS_SET(&set, _FLOAT_ALIGN_SET)) {
2444 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "align",
2445 "floating point number field class");
2446 ret = -EPERM;
2447 goto error;
2448 }
2449
2450 if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
2451 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2452 right,
2453 "Invalid `align` attribute in floating point number field class: "
2454 "expecting unsigned constant integer: "
2455 "node-type={}",
2456 right->u.unary_expression.type);
2457 ret = -EINVAL;
2458 goto error;
2459 }
2460
2461 alignment = right->u.unary_expression.u.unsigned_constant;
2462
2463 if (!is_align_valid(alignment)) {
2464 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2465 right,
2466 "Invalid `align` attribute in floating point number field class: "
2467 "expecting power of two: "
2468 "align={}",
2469 alignment);
2470 ret = -EINVAL;
2471 goto error;
2472 }
2473
2474 _SET(&set, _FLOAT_ALIGN_SET);
2475 } else {
2476 _BT_CPPLOGW_NODE(left,
2477 "Unknown attribute in floating point number field class: "
2478 "attr-name=\"{}\"",
2479 left->u.unary_expression.u.string);
2480 }
2481 }
2482
2483 if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
2484 BT_CPPLOGE_APPEND_CAUSE_SPEC(
2485 ctx->logger, "Missing `mant_dig` attribute in floating point number field class.");
2486 ret = -EPERM;
2487 goto error;
2488 }
2489
2490 if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
2491 BT_CPPLOGE_APPEND_CAUSE_SPEC(
2492 ctx->logger, "Missing `exp_dig` attribute in floating point number field class.");
2493 ret = -EPERM;
2494 goto error;
2495 }
2496
2497 if (mant_dig != 24 && mant_dig != 53) {
2498 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "`mant_dig` attribute: expecting 24 or 53.");
2499 ret = -EPERM;
2500 goto error;
2501 }
2502
2503 if (mant_dig == 24 && exp_dig != 8) {
2504 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
2505 "`exp_dig` attribute: expecting 8 because `mant_dig` is 24.");
2506 ret = -EPERM;
2507 goto error;
2508 }
2509
2510 if (mant_dig == 53 && exp_dig != 11) {
2511 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
2512 "`exp_dig` attribute: expecting 11 because `mant_dig` is 53.");
2513 ret = -EPERM;
2514 goto error;
2515 }
2516
2517 if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) {
2518 if ((mant_dig + exp_dig) % CHAR_BIT) {
2519 /* Bit-packed alignment */
2520 alignment = 1;
2521 } else {
2522 /* Byte-packed alignment */
2523 alignment = CHAR_BIT;
2524 }
2525 }
2526
2527 *float_decl = ctf_field_class_float_create();
2528 BT_ASSERT(*float_decl);
2529 (*float_decl)->base.base.alignment = alignment;
2530 (*float_decl)->base.byte_order = byte_order;
2531 (*float_decl)->base.size = mant_dig + exp_dig;
2532 return 0;
2533
2534 error:
2535 ctf_field_class_destroy(&(*float_decl)->base.base);
2536 *float_decl = NULL;
2537 return ret;
2538 }
2539
2540 static int visit_string_decl(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *expressions,
2541 struct ctf_field_class_string **string_decl)
2542 {
2543 int set = 0;
2544 int ret = 0;
2545 struct ctf_node *expression;
2546
2547 *string_decl = NULL;
2548
2549 bt_list_for_each_entry (expression, expressions, siblings) {
2550 struct ctf_node *left, *right;
2551
2552 left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings);
2553 right =
2554 _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings);
2555
2556 if (left->u.unary_expression.type != UNARY_STRING) {
2557 _BT_CPPLOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type={}",
2558 left->u.unary_expression.type);
2559 ret = -EINVAL;
2560 goto error;
2561 }
2562
2563 if (strcmp(left->u.unary_expression.u.string, "encoding") == 0) {
2564 char *s_right;
2565
2566 if (_IS_SET(&set, _STRING_ENCODING_SET)) {
2567 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "string field class");
2568 ret = -EPERM;
2569 goto error;
2570 }
2571
2572 if (right->u.unary_expression.type != UNARY_STRING) {
2573 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2574 "Invalid `encoding` attribute in string field class: "
2575 "expecting unary string.");
2576 ret = -EINVAL;
2577 goto error;
2578 }
2579
2580 s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
2581 if (!s_right) {
2582 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2583 right,
2584 "Unexpected unary expression for string field class's `encoding` attribute.");
2585 ret = -EINVAL;
2586 goto error;
2587 }
2588
2589 if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 ||
2590 strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 ||
2591 strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) {
2592 /* empty */
2593 } else if (strcmp(s_right, "none") == 0) {
2594 /* empty */
2595 } else {
2596 _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
2597 "Invalid `encoding` attribute in string field class: "
2598 "unknown encoding: encoding=\"{}\"",
2599 s_right);
2600 g_free(s_right);
2601 ret = -EINVAL;
2602 goto error;
2603 }
2604
2605 g_free(s_right);
2606 _SET(&set, _STRING_ENCODING_SET);
2607 } else {
2608 _BT_CPPLOGW_NODE(left,
2609 "Unknown attribute in string field class: "
2610 "attr-name=\"{}\"",
2611 left->u.unary_expression.u.string);
2612 }
2613 }
2614
2615 *string_decl = ctf_field_class_string_create();
2616 BT_ASSERT(*string_decl);
2617 return 0;
2618
2619 error:
2620 ctf_field_class_destroy(&(*string_decl)->base);
2621 *string_decl = NULL;
2622 return ret;
2623 }
2624
2625 static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *ctx,
2626 struct ctf_node *ts_list, struct ctf_field_class **decl)
2627 {
2628 int ret = 0;
2629 struct ctf_node *first, *node;
2630
2631 *decl = NULL;
2632
2633 if (ts_list->type != NODE_TYPE_SPECIFIER_LIST) {
2634 _BT_CPPLOGE_APPEND_CAUSE_NODE(ts_list, "Unexpected node type: node-type={}", ts_list->type);
2635 ret = -EINVAL;
2636 goto error;
2637 }
2638
2639 first = _BT_LIST_FIRST_ENTRY(&ts_list->u.field_class_specifier_list.head, struct ctf_node,
2640 siblings);
2641 if (first->type != NODE_TYPE_SPECIFIER) {
2642 _BT_CPPLOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type={}", first->type);
2643 ret = -EINVAL;
2644 goto error;
2645 }
2646
2647 node = first->u.field_class_specifier.node;
2648
2649 switch (first->u.field_class_specifier.type) {
2650 case TYPESPEC_INTEGER:
2651 {
2652 ctf_field_class_int *int_decl;
2653
2654 ret = visit_integer_decl(ctx, &node->u.integer.expressions, &int_decl);
2655 if (ret) {
2656 BT_ASSERT(!int_decl);
2657 goto error;
2658 }
2659
2660 *decl = &int_decl->base.base;
2661 break;
2662 }
2663 case TYPESPEC_FLOATING_POINT:
2664 {
2665 ctf_field_class_float *float_decl;
2666
2667 ret =
2668 visit_floating_point_number_decl(ctx, &node->u.floating_point.expressions, &float_decl);
2669 if (ret) {
2670 BT_ASSERT(!float_decl);
2671 goto error;
2672 }
2673
2674 *decl = &float_decl->base.base;
2675 break;
2676 }
2677 case TYPESPEC_STRING:
2678 {
2679 ctf_field_class_string *string_decl;
2680
2681 ret = visit_string_decl(ctx, &node->u.string.expressions, &string_decl);
2682 if (ret) {
2683 BT_ASSERT(!string_decl);
2684 goto error;
2685 }
2686
2687 *decl = &string_decl->base;
2688 break;
2689 }
2690 case TYPESPEC_STRUCT:
2691 {
2692 ctf_field_class_struct *struct_decl;
2693
2694 ret = visit_struct_decl(ctx, node->u._struct.name, &node->u._struct.declaration_list,
2695 node->u._struct.has_body, &node->u._struct.min_align, &struct_decl);
2696 if (ret) {
2697 BT_ASSERT(!struct_decl);
2698 goto error;
2699 }
2700
2701 *decl = &struct_decl->base;
2702 break;
2703 }
2704 case TYPESPEC_VARIANT:
2705 {
2706 ctf_field_class_variant *variant_decl;
2707
2708 ret = visit_variant_decl(ctx, node->u.variant.name, node->u.variant.choice,
2709 &node->u.variant.declaration_list, node->u.variant.has_body,
2710 &variant_decl);
2711 if (ret) {
2712 BT_ASSERT(!variant_decl);
2713 goto error;
2714 }
2715
2716 *decl = &variant_decl->base;
2717 break;
2718 }
2719 case TYPESPEC_ENUM:
2720 {
2721 ctf_field_class_enum *enum_decl;
2722
2723 ret = visit_enum_decl(ctx, node->u._enum.enum_id, node->u._enum.container_field_class,
2724 &node->u._enum.enumerator_list, node->u._enum.has_body, &enum_decl);
2725 if (ret) {
2726 BT_ASSERT(!enum_decl);
2727 goto error;
2728 }
2729
2730 *decl = &enum_decl->base.base.base;
2731 break;
2732 }
2733 case TYPESPEC_VOID:
2734 case TYPESPEC_CHAR:
2735 case TYPESPEC_SHORT:
2736 case TYPESPEC_INT:
2737 case TYPESPEC_LONG:
2738 case TYPESPEC_FLOAT:
2739 case TYPESPEC_DOUBLE:
2740 case TYPESPEC_SIGNED:
2741 case TYPESPEC_UNSIGNED:
2742 case TYPESPEC_BOOL:
2743 case TYPESPEC_COMPLEX:
2744 case TYPESPEC_IMAGINARY:
2745 case TYPESPEC_CONST:
2746 case TYPESPEC_ID_TYPE:
2747 ret = visit_field_class_specifier(ctx, ts_list, decl);
2748 if (ret) {
2749 _BT_CPPLOGE_APPEND_CAUSE_NODE(first, "Cannot visit field class specifier: ret={}", ret);
2750 BT_ASSERT(!*decl);
2751 goto error;
2752 }
2753 break;
2754 default:
2755 _BT_CPPLOGE_APPEND_CAUSE_NODE(first, "Unexpected field class specifier type: node-type={}",
2756 first->u.field_class_specifier.type);
2757 ret = -EINVAL;
2758 goto error;
2759 }
2760
2761 BT_ASSERT(*decl);
2762 return 0;
2763
2764 error:
2765 ctf_field_class_destroy(*decl);
2766 *decl = NULL;
2767 return ret;
2768 }
2769
2770 static int visit_event_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node,
2771 struct ctf_event_class *event_class, uint64_t *stream_id,
2772 int *set)
2773 {
2774 int ret = 0;
2775 char *left = NULL;
2776
2777 switch (node->type) {
2778 case NODE_TYPEDEF:
2779 ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
2780 &node->u.field_class_def.field_class_declarators);
2781 if (ret) {
2782 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot add field class found in event class.");
2783 goto error;
2784 }
2785 break;
2786 case NODE_TYPEALIAS:
2787 ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
2788 node->u.field_class_alias.alias);
2789 if (ret) {
2790 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
2791 "Cannot add field class alias found in event class.");
2792 goto error;
2793 }
2794 break;
2795 case NODE_CTF_EXPRESSION:
2796 {
2797 left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
2798 if (!left) {
2799 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
2800 ret = -EINVAL;
2801 goto error;
2802 }
2803
2804 if (strcmp(left, "name") == 0) {
2805 /* This is already known at this stage */
2806 if (_IS_SET(set, _EVENT_NAME_SET)) {
2807 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "name", "event class");
2808 ret = -EPERM;
2809 goto error;
2810 }
2811
2812 _SET(set, _EVENT_NAME_SET);
2813 } else if (strcmp(left, "id") == 0) {
2814 int64_t id = -1;
2815
2816 if (_IS_SET(set, _EVENT_ID_SET)) {
2817 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "event class");
2818 ret = -EPERM;
2819 goto error;
2820 }
2821
2822 ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id);
2823 /* Only read "id" if get_unary_unsigned() succeeded. */
2824 if (ret || (!ret && id < 0)) {
2825 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2826 node, "Unexpected unary expression for event class's `id` attribute.");
2827 ret = -EINVAL;
2828 goto error;
2829 }
2830
2831 event_class->id = id;
2832 _SET(set, _EVENT_ID_SET);
2833 } else if (strcmp(left, "stream_id") == 0) {
2834 if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
2835 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "stream_id", "event class");
2836 ret = -EPERM;
2837 goto error;
2838 }
2839
2840 ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, stream_id);
2841
2842 /*
2843 * Only read "stream_id" if get_unary_unsigned()
2844 * succeeded.
2845 */
2846 if (ret) {
2847 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2848 node, "Unexpected unary expression for event class's `stream_id` attribute.");
2849 ret = -EINVAL;
2850 goto error;
2851 }
2852
2853 _SET(set, _EVENT_STREAM_ID_SET);
2854 } else if (strcmp(left, "context") == 0) {
2855 if (_IS_SET(set, _EVENT_CONTEXT_SET)) {
2856 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate `context` entry in event class.");
2857 ret = -EPERM;
2858 goto error;
2859 }
2860
2861 ret = visit_field_class_specifier_list(
2862 ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings),
2863 &event_class->spec_context_fc);
2864 if (ret) {
2865 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
2866 "Cannot create event class's context field class.");
2867 goto error;
2868 }
2869
2870 BT_ASSERT(event_class->spec_context_fc);
2871 _SET(set, _EVENT_CONTEXT_SET);
2872 } else if (strcmp(left, "fields") == 0) {
2873 if (_IS_SET(set, _EVENT_FIELDS_SET)) {
2874 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate `fields` entry in event class.");
2875 ret = -EPERM;
2876 goto error;
2877 }
2878
2879 ret = visit_field_class_specifier_list(
2880 ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings),
2881 &event_class->payload_fc);
2882 if (ret) {
2883 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
2884 "Cannot create event class's payload field class.");
2885 goto error;
2886 }
2887
2888 BT_ASSERT(event_class->payload_fc);
2889 _SET(set, _EVENT_FIELDS_SET);
2890 } else if (strcmp(left, "loglevel") == 0) {
2891 uint64_t loglevel_value;
2892 bool is_log_level_known = true;
2893 bt_event_class_log_level log_level;
2894
2895 if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) {
2896 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "loglevel", "event class");
2897 ret = -EPERM;
2898 goto error;
2899 }
2900
2901 ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &loglevel_value);
2902 if (ret) {
2903 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2904 node, "Unexpected unary expression for event class's `loglevel` attribute.");
2905 ret = -EINVAL;
2906 goto error;
2907 }
2908
2909 switch (loglevel_value) {
2910 case 0:
2911 log_level = BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY;
2912 break;
2913 case 1:
2914 log_level = BT_EVENT_CLASS_LOG_LEVEL_ALERT;
2915 break;
2916 case 2:
2917 log_level = BT_EVENT_CLASS_LOG_LEVEL_CRITICAL;
2918 break;
2919 case 3:
2920 log_level = BT_EVENT_CLASS_LOG_LEVEL_ERROR;
2921 break;
2922 case 4:
2923 log_level = BT_EVENT_CLASS_LOG_LEVEL_WARNING;
2924 break;
2925 case 5:
2926 log_level = BT_EVENT_CLASS_LOG_LEVEL_NOTICE;
2927 break;
2928 case 6:
2929 log_level = BT_EVENT_CLASS_LOG_LEVEL_INFO;
2930 break;
2931 case 7:
2932 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM;
2933 break;
2934 case 8:
2935 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM;
2936 break;
2937 case 9:
2938 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS;
2939 break;
2940 case 10:
2941 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE;
2942 break;
2943 case 11:
2944 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT;
2945 break;
2946 case 12:
2947 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION;
2948 break;
2949 case 13:
2950 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE;
2951 break;
2952 case 14:
2953 log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG;
2954 break;
2955 default:
2956 is_log_level_known = false;
2957 _BT_CPPLOGW_NODE(
2958 node,
2959 "Not setting event class's log level because its value is unknown: "
2960 "log-level={}",
2961 loglevel_value);
2962 }
2963
2964 if (is_log_level_known) {
2965 ctf_event_class_set_log_level(event_class, log_level);
2966 }
2967
2968 _SET(set, _EVENT_LOG_LEVEL_SET);
2969 } else if (strcmp(left, "model.emf.uri") == 0) {
2970 char *right;
2971
2972 if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) {
2973 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "model.emf.uri", "event class");
2974 ret = -EPERM;
2975 goto error;
2976 }
2977
2978 right = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.right);
2979 if (!right) {
2980 _BT_CPPLOGE_APPEND_CAUSE_NODE(
2981 node,
2982 "Unexpected unary expression for event class's `model.emf.uri` attribute.");
2983 ret = -EINVAL;
2984 goto error;
2985 }
2986
2987 if (strlen(right) == 0) {
2988 _BT_CPPLOGW_NODE(node, "Not setting event class's EMF URI because it's empty.");
2989 } else {
2990 g_string_assign(event_class->emf_uri, right);
2991 }
2992
2993 g_free(right);
2994 _SET(set, _EVENT_MODEL_EMF_URI_SET);
2995 } else {
2996 _BT_CPPLOGW_NODE(node,
2997 "Unknown attribute in event class: "
2998 "attr-name=\"{}\"",
2999 left);
3000 }
3001
3002 g_free(left);
3003 left = NULL;
3004 break;
3005 }
3006 default:
3007 ret = -EPERM;
3008 goto error;
3009 }
3010
3011 goto end;
3012
3013 error:
3014 g_free(left);
3015
3016 end:
3017 return ret;
3018 }
3019
3020 static char *get_event_decl_name(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
3021 {
3022 char *left = NULL;
3023 char *name = NULL;
3024 struct ctf_node *iter;
3025 struct bt_list_head *decl_list = &node->u.event.declaration_list;
3026
3027 bt_list_for_each_entry (iter, decl_list, siblings) {
3028 if (iter->type != NODE_CTF_EXPRESSION) {
3029 continue;
3030 }
3031
3032 left = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.left);
3033 if (!left) {
3034 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot concatenate unary strings.");
3035 goto error;
3036 }
3037
3038 if (strcmp(left, "name") == 0) {
3039 name = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.right);
3040 if (!name) {
3041 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3042 iter, "Unexpected unary expression for event class's `name` attribute.");
3043 goto error;
3044 }
3045 }
3046
3047 g_free(left);
3048 left = NULL;
3049
3050 if (name) {
3051 break;
3052 }
3053 }
3054
3055 return name;
3056
3057 error:
3058 g_free(left);
3059 return NULL;
3060 }
3061
3062 static int visit_event_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
3063 {
3064 int ret = 0;
3065 int set = 0;
3066 struct ctf_node *iter;
3067 uint64_t stream_id = 0;
3068 char *event_name = NULL;
3069 struct ctf_event_class *event_class = NULL;
3070 struct ctf_stream_class *stream_class = NULL;
3071 struct bt_list_head *decl_list = &node->u.event.declaration_list;
3072 bool pop_scope = false;
3073
3074 if (node->visited) {
3075 goto end;
3076 }
3077
3078 node->visited = TRUE;
3079 event_name = get_event_decl_name(ctx, node);
3080 if (!event_name) {
3081 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Missing `name` attribute in event class.");
3082 ret = -EPERM;
3083 goto error;
3084 }
3085
3086 event_class = ctf_event_class_create();
3087 BT_ASSERT(event_class);
3088 g_string_assign(event_class->name, event_name);
3089 _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
3090 pop_scope = true;
3091
3092 bt_list_for_each_entry (iter, decl_list, siblings) {
3093 ret = visit_event_decl_entry(ctx, iter, event_class, &stream_id, &set);
3094 if (ret) {
3095 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
3096 "Cannot visit event class's entry: "
3097 "ret={}",
3098 ret);
3099 goto error;
3100 }
3101 }
3102
3103 if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) {
3104 /*
3105 * Allow missing stream_id if there is only a single
3106 * stream class.
3107 */
3108 switch (ctx->ctf_tc->stream_classes->len) {
3109 case 0:
3110 /* Create implicit stream class if there's none */
3111 stream_id = 0;
3112 stream_class = ctf_stream_class_create();
3113 BT_ASSERT(stream_class);
3114 stream_class->id = stream_id;
3115 g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class);
3116 break;
3117 case 1:
3118 /* Single stream class: get its ID */
3119 stream_class = (ctf_stream_class *) ctx->ctf_tc->stream_classes->pdata[0];
3120 stream_id = stream_class->id;
3121 break;
3122 default:
3123 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Missing `stream_id` attribute in event class.");
3124 ret = -EPERM;
3125 goto error;
3126 }
3127 }
3128
3129 /* We have the stream ID now; get the stream class if found */
3130 if (!stream_class) {
3131 stream_class = ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, stream_id);
3132 if (!stream_class) {
3133 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3134 "Cannot find stream class at this point: "
3135 "id={}",
3136 stream_id);
3137 ret = -EINVAL;
3138 goto error;
3139 }
3140 }
3141
3142 BT_ASSERT(stream_class);
3143
3144 if (!_IS_SET(&set, _EVENT_ID_SET)) {
3145 /* Allow only one event without ID per stream */
3146 if (stream_class->event_classes->len != 0) {
3147 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Missing `id` attribute in event class.");
3148 ret = -EPERM;
3149 goto error;
3150 }
3151
3152 /* Automatic ID */
3153 event_class->id = 0;
3154 }
3155
3156 if (ctf_stream_class_borrow_event_class_by_id(stream_class, event_class->id)) {
3157 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3158 "Duplicate event class (same ID) in the same stream class: "
3159 "id={}",
3160 event_class->id);
3161 ret = -EEXIST;
3162 goto error;
3163 }
3164
3165 ctf_stream_class_append_event_class(stream_class, event_class);
3166 event_class = NULL;
3167 goto end;
3168
3169 error:
3170 ctf_event_class_destroy(event_class);
3171 event_class = NULL;
3172
3173 if (ret >= 0) {
3174 ret = -1;
3175 }
3176
3177 end:
3178 if (pop_scope) {
3179 ctx_pop_scope(ctx);
3180 }
3181
3182 g_free(event_name);
3183
3184 return ret;
3185 }
3186
3187 static int auto_map_field_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx,
3188 struct ctf_field_class *fc)
3189 {
3190 struct ctf_clock_class *clock_class_to_map_to = NULL;
3191 uint64_t clock_class_count;
3192
3193 if (!fc) {
3194 return 0;
3195 }
3196
3197 if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
3198 return 0;
3199 }
3200
3201 ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
3202
3203 if (int_fc->mapped_clock_class) {
3204 /* Already mapped */
3205 return 0;
3206 }
3207
3208 clock_class_count = ctx->ctf_tc->clock_classes->len;
3209
3210 switch (clock_class_count) {
3211 case 0:
3212 /*
3213 * No clock class exists in the trace at this point. Create an
3214 * implicit one at 1 GHz, named `default`, and use this clock
3215 * class.
3216 */
3217 clock_class_to_map_to = ctf_clock_class_create();
3218 BT_ASSERT(clock_class_to_map_to);
3219 clock_class_to_map_to->frequency = UINT64_C(1000000000);
3220 g_string_assign(clock_class_to_map_to->name, "default");
3221 g_ptr_array_add(ctx->ctf_tc->clock_classes, clock_class_to_map_to);
3222 break;
3223 case 1:
3224 /*
3225 * Only one clock class exists in the trace at this point: use
3226 * this one.
3227 */
3228 clock_class_to_map_to = (ctf_clock_class *) ctx->ctf_tc->clock_classes->pdata[0];
3229 break;
3230 default:
3231 /*
3232 * Timestamp field not mapped to a clock class and there's more
3233 * than one clock class in the trace: this is an error.
3234 */
3235 BT_CPPLOGE_APPEND_CAUSE_SPEC(
3236 ctx->logger, "Timestamp field found with no mapped clock class, "
3237 "but there's more than one clock class in the trace at this point.");
3238 return -1;
3239 }
3240
3241 BT_ASSERT(clock_class_to_map_to);
3242 int_fc->mapped_clock_class = clock_class_to_map_to;
3243
3244 return 0;
3245 }
3246
3247 static int auto_map_fields_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx,
3248 struct ctf_field_class *root_fc,
3249 const char *field_name)
3250 {
3251 int ret = 0;
3252 uint64_t i, count;
3253 struct ctf_field_class_struct *struct_fc = (ctf_field_class_struct *) root_fc;
3254 struct ctf_field_class_variant *var_fc = (ctf_field_class_variant *) root_fc;
3255
3256 if (!root_fc) {
3257 goto end;
3258 }
3259
3260 if (root_fc->type != CTF_FIELD_CLASS_TYPE_STRUCT &&
3261 root_fc->type != CTF_FIELD_CLASS_TYPE_VARIANT) {
3262 goto end;
3263 }
3264
3265 if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) {
3266 count = struct_fc->members->len;
3267 } else {
3268 count = var_fc->options->len;
3269 }
3270
3271 for (i = 0; i < count; i++) {
3272 struct ctf_named_field_class *named_fc = NULL;
3273
3274 if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) {
3275 named_fc = ctf_field_class_struct_borrow_member_by_index(struct_fc, i);
3276 } else if (root_fc->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
3277 named_fc = ctf_field_class_variant_borrow_option_by_index(var_fc, i);
3278 } else {
3279 bt_common_abort();
3280 }
3281
3282 if (strcmp(named_fc->name->str, field_name) == 0) {
3283 ret = auto_map_field_to_trace_clock_class(ctx, named_fc->fc);
3284 if (ret) {
3285 BT_CPPLOGE_APPEND_CAUSE_SPEC(
3286 ctx->logger,
3287 "Cannot automatically map field to trace's clock class: "
3288 "field-name=\"{}\"",
3289 field_name);
3290 goto end;
3291 }
3292 }
3293
3294 ret = auto_map_fields_to_trace_clock_class(ctx, named_fc->fc, field_name);
3295 if (ret) {
3296 BT_CPPLOGE_APPEND_CAUSE_SPEC(
3297 ctx->logger,
3298 "Cannot automatically map structure or variant field class's fields to trace's clock class: "
3299 "field-name=\"{}\", root-field-name=\"{}\"",
3300 field_name, named_fc->name->str);
3301 goto end;
3302 }
3303 }
3304
3305 end:
3306 return ret;
3307 }
3308
3309 static int visit_stream_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node,
3310 struct ctf_stream_class *stream_class, int *set)
3311 {
3312 int ret = 0;
3313 char *left = NULL;
3314
3315 switch (node->type) {
3316 case NODE_TYPEDEF:
3317 ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
3318 &node->u.field_class_def.field_class_declarators);
3319 if (ret) {
3320 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot add field class found in stream class.");
3321 goto error;
3322 }
3323 break;
3324 case NODE_TYPEALIAS:
3325 ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
3326 node->u.field_class_alias.alias);
3327 if (ret) {
3328 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3329 "Cannot add field class alias found in stream class.");
3330 goto error;
3331 }
3332 break;
3333 case NODE_CTF_EXPRESSION:
3334 {
3335 left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
3336 if (!left) {
3337 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
3338 ret = -EINVAL;
3339 goto error;
3340 }
3341
3342 if (strcmp(left, "id") == 0) {
3343 int64_t id;
3344
3345 if (_IS_SET(set, _STREAM_ID_SET)) {
3346 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "stream declaration");
3347 ret = -EPERM;
3348 goto error;
3349 }
3350
3351 ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id);
3352
3353 /* Only read "id" if get_unary_unsigned() succeeded. */
3354 if (ret || (!ret && id < 0)) {
3355 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3356 node, "Unexpected unary expression for stream class's `id` attribute.");
3357 ret = -EINVAL;
3358 goto error;
3359 }
3360
3361 if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, id)) {
3362 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate stream class (same ID): id={}", id);
3363 ret = -EEXIST;
3364 goto error;
3365 }
3366
3367 stream_class->id = id;
3368 _SET(set, _STREAM_ID_SET);
3369 } else if (strcmp(left, "event.header") == 0) {
3370 if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
3371 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3372 "Duplicate `event.header` entry in stream class.");
3373 ret = -EPERM;
3374 goto error;
3375 }
3376
3377 ret = visit_field_class_specifier_list(
3378 ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings),
3379 &stream_class->event_header_fc);
3380 if (ret) {
3381 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3382 node, "Cannot create stream class's event header field class.");
3383 goto error;
3384 }
3385
3386 BT_ASSERT(stream_class->event_header_fc);
3387 ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->event_header_fc,
3388 "timestamp");
3389 if (ret) {
3390 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3391 node,
3392 "Cannot automatically map specific event header field class fields named `timestamp` to trace's clock class.");
3393 goto error;
3394 }
3395
3396 _SET(set, _STREAM_EVENT_HEADER_SET);
3397 } else if (strcmp(left, "event.context") == 0) {
3398 if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
3399 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3400 "Duplicate `event.context` entry in stream class.");
3401 ret = -EPERM;
3402 goto error;
3403 }
3404
3405 ret = visit_field_class_specifier_list(
3406 ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings),
3407 &stream_class->event_common_context_fc);
3408 if (ret) {
3409 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3410 node, "Cannot create stream class's event context field class.");
3411 goto error;
3412 }
3413
3414 BT_ASSERT(stream_class->event_common_context_fc);
3415 _SET(set, _STREAM_EVENT_CONTEXT_SET);
3416 } else if (strcmp(left, "packet.context") == 0) {
3417 if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
3418 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3419 "Duplicate `packet.context` entry in stream class.");
3420 ret = -EPERM;
3421 goto error;
3422 }
3423
3424 ret = visit_field_class_specifier_list(
3425 ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings),
3426 &stream_class->packet_context_fc);
3427 if (ret) {
3428 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3429 node, "Cannot create stream class's packet context field class.");
3430 goto error;
3431 }
3432
3433 BT_ASSERT(stream_class->packet_context_fc);
3434 ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->packet_context_fc,
3435 "timestamp_begin");
3436 if (ret) {
3437 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3438 node,
3439 "Cannot automatically map specific packet context field class fields named `timestamp_begin` to trace's clock class.");
3440 goto error;
3441 }
3442
3443 ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->packet_context_fc,
3444 "timestamp_end");
3445 if (ret) {
3446 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3447 node,
3448 "Cannot automatically map specific packet context field class fields named `timestamp_end` to trace's clock class.");
3449 goto error;
3450 }
3451
3452 _SET(set, _STREAM_PACKET_CONTEXT_SET);
3453 } else {
3454 _BT_CPPLOGW_NODE(node,
3455 "Unknown attribute in stream class: "
3456 "attr-name=\"{}\"",
3457 left);
3458 }
3459
3460 g_free(left);
3461 left = NULL;
3462 break;
3463 }
3464
3465 default:
3466 ret = -EPERM;
3467 goto error;
3468 }
3469
3470 return 0;
3471
3472 error:
3473 g_free(left);
3474 return ret;
3475 }
3476
3477 static int visit_stream_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
3478 {
3479 int set = 0;
3480 int ret = 0;
3481 struct ctf_node *iter;
3482 struct ctf_stream_class *stream_class = NULL;
3483 struct bt_list_head *decl_list = &node->u.stream.declaration_list;
3484
3485 if (node->visited) {
3486 goto end;
3487 }
3488
3489 node->visited = TRUE;
3490 stream_class = ctf_stream_class_create();
3491 BT_ASSERT(stream_class);
3492 _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
3493
3494 bt_list_for_each_entry (iter, decl_list, siblings) {
3495 ret = visit_stream_decl_entry(ctx, iter, stream_class, &set);
3496 if (ret) {
3497 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
3498 "Cannot visit stream class's entry: "
3499 "ret={}",
3500 ret);
3501 ctx_pop_scope(ctx);
3502 goto error;
3503 }
3504 }
3505
3506 ctx_pop_scope(ctx);
3507
3508 if (_IS_SET(&set, _STREAM_ID_SET)) {
3509 /* Check that packet header has `stream_id` field */
3510 struct ctf_named_field_class *named_fc = NULL;
3511
3512 if (!ctx->ctf_tc->packet_header_fc) {
3513 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Stream class has a `id` attribute, "
3514 "but trace has no packet header field class.");
3515 ret = -EINVAL;
3516 goto error;
3517 }
3518
3519 named_fc = ctf_field_class_struct_borrow_member_by_name(
3520 ctf_field_class_as_struct(ctx->ctf_tc->packet_header_fc), "stream_id");
3521 if (!named_fc) {
3522 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3523 node, "Stream class has a `id` attribute, "
3524 "but trace's packet header field class has no `stream_id` field.");
3525 ret = -EINVAL;
3526 goto error;
3527 }
3528
3529 if (named_fc->fc->type != CTF_FIELD_CLASS_TYPE_INT &&
3530 named_fc->fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
3531 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3532 node,
3533 "Stream class has a `id` attribute, "
3534 "but trace's packet header field class's `stream_id` field is not an integer field class.");
3535 ret = -EINVAL;
3536 goto error;
3537 }
3538 } else {
3539 /* Allow only _one_ ID-less stream */
3540 if (ctx->ctf_tc->stream_classes->len != 0) {
3541 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3542 node,
3543 "Missing `id` attribute in stream class as there's more than one stream class in the trace.");
3544 ret = -EPERM;
3545 goto error;
3546 }
3547
3548 /* Automatic ID: 0 */
3549 stream_class->id = 0;
3550 }
3551
3552 /*
3553 * Make sure that this stream class's ID is currently unique in
3554 * the trace.
3555 */
3556 if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, stream_class->id)) {
3557 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate stream class (same ID): id={}",
3558 stream_class->id);
3559 ret = -EINVAL;
3560 goto error;
3561 }
3562
3563 g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class);
3564 stream_class = NULL;
3565 goto end;
3566
3567 error:
3568 ctf_stream_class_destroy(stream_class);
3569 stream_class = NULL;
3570
3571 end:
3572 return ret;
3573 }
3574
3575 static int visit_trace_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node,
3576 int *set)
3577 {
3578 int ret = 0;
3579 char *left = NULL;
3580 uint64_t val;
3581
3582 switch (node->type) {
3583 case NODE_TYPEDEF:
3584 ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
3585 &node->u.field_class_def.field_class_declarators);
3586 if (ret) {
3587 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3588 "Cannot add field class found in trace (`trace` block).");
3589 goto error;
3590 }
3591 break;
3592 case NODE_TYPEALIAS:
3593 ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
3594 node->u.field_class_alias.alias);
3595 if (ret) {
3596 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3597 node, "Cannot add field class alias found in trace (`trace` block).");
3598 goto error;
3599 }
3600 break;
3601 case NODE_CTF_EXPRESSION:
3602 {
3603 left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
3604 if (!left) {
3605 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
3606 ret = -EINVAL;
3607 goto error;
3608 }
3609
3610 if (strcmp(left, "major") == 0) {
3611 if (_IS_SET(set, _TRACE_MAJOR_SET)) {
3612 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "major", "trace");
3613 ret = -EPERM;
3614 goto error;
3615 }
3616
3617 ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val);
3618 if (ret) {
3619 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3620 node, "Unexpected unary expression for trace's `major` attribute.");
3621 ret = -EINVAL;
3622 goto error;
3623 }
3624
3625 if (val != 1) {
3626 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3627 "Invalid trace's `minor` attribute: expecting 1.");
3628 ret = -EINVAL;
3629 goto error;
3630 }
3631
3632 ctx->ctf_tc->major = val;
3633 _SET(set, _TRACE_MAJOR_SET);
3634 } else if (strcmp(left, "minor") == 0) {
3635 if (_IS_SET(set, _TRACE_MINOR_SET)) {
3636 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "minor", "trace");
3637 ret = -EPERM;
3638 goto error;
3639 }
3640
3641 ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val);
3642 if (ret) {
3643 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3644 node, "Unexpected unary expression for trace's `minor` attribute.");
3645 ret = -EINVAL;
3646 goto error;
3647 }
3648
3649 if (val != 8) {
3650 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3651 "Invalid trace's `minor` attribute: expecting 8.");
3652 ret = -EINVAL;
3653 goto error;
3654 }
3655
3656 ctx->ctf_tc->minor = val;
3657 _SET(set, _TRACE_MINOR_SET);
3658 } else if (strcmp(left, "uuid") == 0) {
3659 if (_IS_SET(set, _TRACE_UUID_SET)) {
3660 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "uuid", "trace");
3661 ret = -EPERM;
3662 goto error;
3663 }
3664
3665 ret = get_unary_uuid(&node->u.ctf_expression.right, ctx->ctf_tc->uuid, ctx->logger);
3666 if (ret) {
3667 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Invalid trace's `uuid` attribute.");
3668 goto error;
3669 }
3670
3671 ctx->ctf_tc->is_uuid_set = true;
3672 _SET(set, _TRACE_UUID_SET);
3673 } else if (strcmp(left, "byte_order") == 0) {
3674 /* Default byte order is already known at this stage */
3675 if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
3676 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace");
3677 ret = -EPERM;
3678 goto error;
3679 }
3680
3681 BT_ASSERT(ctx->ctf_tc->default_byte_order != CTF_BYTE_ORDER_UNKNOWN);
3682 _SET(set, _TRACE_BYTE_ORDER_SET);
3683 } else if (strcmp(left, "packet.header") == 0) {
3684 if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
3685 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate `packet.header` entry in trace.");
3686 ret = -EPERM;
3687 goto error;
3688 }
3689
3690 ret = visit_field_class_specifier_list(
3691 ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings),
3692 &ctx->ctf_tc->packet_header_fc);
3693 if (ret) {
3694 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3695 "Cannot create trace's packet header field class.");
3696 goto error;
3697 }
3698
3699 BT_ASSERT(ctx->ctf_tc->packet_header_fc);
3700 _SET(set, _TRACE_PACKET_HEADER_SET);
3701 } else {
3702 _BT_CPPLOGW_NODE(node,
3703 "Unknown attribute in stream class: "
3704 "attr-name=\"{}\"",
3705 left);
3706 }
3707
3708 g_free(left);
3709 left = NULL;
3710 break;
3711 }
3712 default:
3713 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Unknown expression in trace.");
3714 ret = -EINVAL;
3715 goto error;
3716 }
3717
3718 return 0;
3719
3720 error:
3721 g_free(left);
3722 return ret;
3723 }
3724
3725 static int visit_trace_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
3726 {
3727 int ret = 0;
3728 int set = 0;
3729 struct ctf_node *iter;
3730 struct bt_list_head *decl_list = &node->u.trace.declaration_list;
3731
3732 if (node->visited) {
3733 goto end;
3734 }
3735
3736 node->visited = TRUE;
3737
3738 if (ctx->is_trace_visited) {
3739 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block).");
3740 ret = -EEXIST;
3741 goto error;
3742 }
3743
3744 _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
3745
3746 bt_list_for_each_entry (iter, decl_list, siblings) {
3747 ret = visit_trace_decl_entry(ctx, iter, &set);
3748 if (ret) {
3749 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
3750 "Cannot visit trace's entry (`trace` block): "
3751 "ret={}",
3752 ret);
3753 ctx_pop_scope(ctx);
3754 goto error;
3755 }
3756 }
3757
3758 ctx_pop_scope(ctx);
3759
3760 if (!_IS_SET(&set, _TRACE_MAJOR_SET)) {
3761 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Missing `major` attribute in trace (`trace` block).");
3762 ret = -EPERM;
3763 goto error;
3764 }
3765
3766 if (!_IS_SET(&set, _TRACE_MINOR_SET)) {
3767 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Missing `minor` attribute in trace (`trace` block).");
3768 ret = -EPERM;
3769 goto error;
3770 }
3771
3772 if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
3773 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
3774 "Missing `byte_order` attribute in trace (`trace` block).");
3775 ret = -EPERM;
3776 goto error;
3777 }
3778
3779 ctx->is_trace_visited = true;
3780
3781 end:
3782 return 0;
3783
3784 error:
3785 return ret;
3786 }
3787
3788 static int visit_env(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
3789 {
3790 int ret = 0;
3791 char *left = NULL;
3792 struct ctf_node *entry_node;
3793 struct bt_list_head *decl_list = &node->u.env.declaration_list;
3794
3795 if (node->visited) {
3796 goto end;
3797 }
3798
3799 node->visited = TRUE;
3800
3801 bt_list_for_each_entry (entry_node, decl_list, siblings) {
3802 struct bt_list_head *right_head = &entry_node->u.ctf_expression.right;
3803
3804 if (entry_node->type != NODE_CTF_EXPRESSION) {
3805 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node,
3806 "Wrong expression in environment entry: "
3807 "node-type={}",
3808 entry_node->type);
3809 ret = -EPERM;
3810 goto error;
3811 }
3812
3813 left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
3814 if (!left) {
3815 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Cannot get environment entry's name.");
3816 ret = -EINVAL;
3817 goto error;
3818 }
3819
3820 if (is_unary_string(right_head)) {
3821 char *right = ctf_ast_concatenate_unary_strings(right_head);
3822
3823 if (!right) {
3824 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3825 entry_node,
3826 "Unexpected unary expression for environment entry's value: "
3827 "name=\"{}\"",
3828 left);
3829 ret = -EINVAL;
3830 goto error;
3831 }
3832
3833 if (strcmp(left, "tracer_name") == 0) {
3834 if (strncmp(right, "lttng", 5) == 0) {
3835 BT_CPPLOGI_SPEC(ctx->logger,
3836 "Detected LTTng trace from `{}` environment value: "
3837 "tracer-name=\"{}\"",
3838 left, right);
3839 ctx->is_lttng = true;
3840 }
3841 }
3842
3843 ctf_trace_class_append_env_entry(ctx->ctf_tc, left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR,
3844 right, 0);
3845 g_free(right);
3846 } else if (is_unary_unsigned(right_head) || is_unary_signed(right_head)) {
3847 int64_t v;
3848
3849 if (is_unary_unsigned(right_head)) {
3850 ret = get_unary_unsigned(ctx, right_head, (uint64_t *) &v);
3851 } else {
3852 ret = get_unary_signed(right_head, &v);
3853 }
3854 if (ret) {
3855 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3856 entry_node,
3857 "Unexpected unary expression for environment entry's value: "
3858 "name=\"{}\"",
3859 left);
3860 ret = -EINVAL;
3861 goto error;
3862 }
3863
3864 ctf_trace_class_append_env_entry(ctx->ctf_tc, left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT,
3865 NULL, v);
3866 } else {
3867 _BT_CPPLOGW_NODE(entry_node,
3868 "Environment entry has unknown type: "
3869 "name=\"{}\"",
3870 left);
3871 }
3872
3873 g_free(left);
3874 left = NULL;
3875 }
3876
3877 end:
3878 return 0;
3879
3880 error:
3881 g_free(left);
3882 return ret;
3883 }
3884
3885 static int set_trace_byte_order(struct ctf_visitor_generate_ir *ctx, struct ctf_node *trace_node)
3886 {
3887 int ret = 0;
3888 int set = 0;
3889 char *left = NULL;
3890 struct ctf_node *node;
3891 struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list;
3892
3893 bt_list_for_each_entry (node, decl_list, siblings) {
3894 if (node->type == NODE_CTF_EXPRESSION) {
3895 struct ctf_node *right_node;
3896
3897 left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
3898 if (!left) {
3899 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
3900 ret = -EINVAL;
3901 goto error;
3902 }
3903
3904 if (strcmp(left, "byte_order") == 0) {
3905 enum ctf_byte_order bo;
3906
3907 if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
3908 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace");
3909 ret = -EPERM;
3910 goto error;
3911 }
3912
3913 _SET(&set, _TRACE_BYTE_ORDER_SET);
3914 right_node =
3915 _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings);
3916 bo = byte_order_from_unary_expr(ctx, right_node);
3917 if (bo == CTF_BYTE_ORDER_UNKNOWN) {
3918 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3919 node, "Invalid `byte_order` attribute in trace (`trace` block): "
3920 "expecting `le`, `be`, or `network`.");
3921 ret = -EINVAL;
3922 goto error;
3923 } else if (bo == CTF_BYTE_ORDER_DEFAULT) {
3924 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3925 node, "Invalid `byte_order` attribute in trace (`trace` block): "
3926 "cannot be set to `native` here.");
3927 ret = -EPERM;
3928 goto error;
3929 }
3930
3931 ctx->ctf_tc->default_byte_order = bo;
3932 }
3933
3934 g_free(left);
3935 left = NULL;
3936 }
3937 }
3938
3939 if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
3940 _BT_CPPLOGE_APPEND_CAUSE_NODE(trace_node,
3941 "Missing `byte_order` attribute in trace (`trace` block).");
3942 ret = -EINVAL;
3943 goto error;
3944 }
3945
3946 return 0;
3947
3948 error:
3949 g_free(left);
3950 return ret;
3951 }
3952
3953 static int visit_clock_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *entry_node,
3954 struct ctf_clock_class *clock, int *set, int64_t *offset_seconds,
3955 uint64_t *offset_cycles)
3956 {
3957 int ret = 0;
3958 char *left = NULL;
3959
3960 if (entry_node->type != NODE_CTF_EXPRESSION) {
3961 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type={}",
3962 entry_node->type);
3963 ret = -EPERM;
3964 goto error;
3965 }
3966
3967 left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
3968 if (!left) {
3969 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Cannot concatenate unary strings.");
3970 ret = -EINVAL;
3971 goto error;
3972 }
3973
3974 if (strcmp(left, "name") == 0) {
3975 char *right;
3976
3977 if (_IS_SET(set, _CLOCK_NAME_SET)) {
3978 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "name", "clock class");
3979 ret = -EPERM;
3980 goto error;
3981 }
3982
3983 right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right);
3984 if (!right) {
3985 _BT_CPPLOGE_APPEND_CAUSE_NODE(
3986 entry_node, "Unexpected unary expression for clock class's `name` attribute.");
3987 ret = -EINVAL;
3988 goto error;
3989 }
3990
3991 g_string_assign(clock->name, right);
3992 g_free(right);
3993 _SET(set, _CLOCK_NAME_SET);
3994 } else if (strcmp(left, "uuid") == 0) {
3995 bt_uuid_t uuid;
3996
3997 if (_IS_SET(set, _CLOCK_UUID_SET)) {
3998 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "uuid", "clock class");
3999 ret = -EPERM;
4000 goto error;
4001 }
4002
4003 ret = get_unary_uuid(&entry_node->u.ctf_expression.right, uuid, ctx->logger);
4004 if (ret) {
4005 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Invalid clock class's `uuid` attribute.");
4006 goto error;
4007 }
4008
4009 clock->has_uuid = true;
4010 bt_uuid_copy(clock->uuid, uuid);
4011 _SET(set, _CLOCK_UUID_SET);
4012 } else if (strcmp(left, "description") == 0) {
4013 char *right;
4014
4015 if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
4016 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "description", "clock class");
4017 ret = -EPERM;
4018 goto error;
4019 }
4020
4021 right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right);
4022 if (!right) {
4023 _BT_CPPLOGE_APPEND_CAUSE_NODE(
4024 entry_node,
4025 "Unexpected unary expression for clock class's `description` attribute.");
4026 ret = -EINVAL;
4027 goto error;
4028 }
4029
4030 g_string_assign(clock->description, right);
4031 g_free(right);
4032 _SET(set, _CLOCK_DESCRIPTION_SET);
4033 } else if (strcmp(left, "freq") == 0) {
4034 uint64_t freq = UINT64_C(-1);
4035
4036 if (_IS_SET(set, _CLOCK_FREQ_SET)) {
4037 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "freq", "clock class");
4038 ret = -EPERM;
4039 goto error;
4040 }
4041
4042 ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &freq);
4043 if (ret) {
4044 _BT_CPPLOGE_APPEND_CAUSE_NODE(
4045 entry_node, "Unexpected unary expression for clock class's `freq` attribute.");
4046 ret = -EINVAL;
4047 goto error;
4048 }
4049
4050 if (freq == UINT64_C(-1) || freq == 0) {
4051 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Invalid clock class frequency: freq={}",
4052 freq);
4053 ret = -EINVAL;
4054 goto error;
4055 }
4056
4057 clock->frequency = freq;
4058 _SET(set, _CLOCK_FREQ_SET);
4059 } else if (strcmp(left, "precision") == 0) {
4060 uint64_t precision;
4061
4062 if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
4063 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "precision", "clock class");
4064 ret = -EPERM;
4065 goto error;
4066 }
4067
4068 ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &precision);
4069 if (ret) {
4070 _BT_CPPLOGE_APPEND_CAUSE_NODE(
4071 entry_node, "Unexpected unary expression for clock class's `precision` attribute.");
4072 ret = -EINVAL;
4073 goto error;
4074 }
4075
4076 clock->precision = precision;
4077 _SET(set, _CLOCK_PRECISION_SET);
4078 } else if (strcmp(left, "offset_s") == 0) {
4079 if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
4080 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset_s", "clock class");
4081 ret = -EPERM;
4082 goto error;
4083 }
4084
4085 ret = get_unary_signed(&entry_node->u.ctf_expression.right, offset_seconds);
4086 if (ret) {
4087 _BT_CPPLOGE_APPEND_CAUSE_NODE(
4088 entry_node, "Unexpected unary expression for clock class's `offset_s` attribute.");
4089 ret = -EINVAL;
4090 goto error;
4091 }
4092
4093 _SET(set, _CLOCK_OFFSET_S_SET);
4094 } else if (strcmp(left, "offset") == 0) {
4095 if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
4096 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset", "clock class");
4097 ret = -EPERM;
4098 goto error;
4099 }
4100
4101 ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, offset_cycles);
4102 if (ret) {
4103 _BT_CPPLOGE_APPEND_CAUSE_NODE(
4104 entry_node, "Unexpected unary expression for clock class's `offset` attribute.");
4105 ret = -EINVAL;
4106 goto error;
4107 }
4108
4109 _SET(set, _CLOCK_OFFSET_SET);
4110 } else if (strcmp(left, "absolute") == 0) {
4111 struct ctf_node *right;
4112
4113 if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
4114 _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "absolute", "clock class");
4115 ret = -EPERM;
4116 goto error;
4117 }
4118
4119 right =
4120 _BT_LIST_FIRST_ENTRY(&entry_node->u.ctf_expression.right, struct ctf_node, siblings);
4121 ret = get_boolean(ctx, right);
4122 if (ret < 0) {
4123 _BT_CPPLOGE_APPEND_CAUSE_NODE(
4124 entry_node, "Unexpected unary expression for clock class's `absolute` attribute.");
4125 ret = -EINVAL;
4126 goto error;
4127 }
4128
4129 clock->is_absolute = ret;
4130 _SET(set, _CLOCK_ABSOLUTE_SET);
4131 } else {
4132 _BT_CPPLOGW_NODE(entry_node, "Unknown attribute in clock class: attr-name=\"{}\"", left);
4133 }
4134
4135 g_free(left);
4136 left = NULL;
4137 return 0;
4138
4139 error:
4140 g_free(left);
4141 return ret;
4142 }
4143
4144 static int visit_clock_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *clock_node)
4145 {
4146 int ret = 0;
4147 int set = 0;
4148 struct ctf_clock_class *clock;
4149 struct ctf_node *entry_node;
4150 struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list;
4151 const char *clock_class_name;
4152 int64_t offset_seconds = 0;
4153 uint64_t offset_cycles = 0;
4154 long long offsetSecLL;
4155 unsigned long long offsetCyclesULL;
4156
4157 if (clock_node->visited) {
4158 return 0;
4159 }
4160
4161 clock_node->visited = TRUE;
4162
4163 /* CTF 1.8's default frequency for a clock class is 1 GHz */
4164 clock = ctf_clock_class_create();
4165 if (!clock) {
4166 _BT_CPPLOGE_APPEND_CAUSE_NODE(clock_node, "Cannot create default clock class.");
4167 ret = -ENOMEM;
4168 goto end;
4169 }
4170
4171 bt_list_for_each_entry (entry_node, decl_list, siblings) {
4172 ret = visit_clock_decl_entry(ctx, entry_node, clock, &set, &offset_seconds, &offset_cycles);
4173 if (ret) {
4174 _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Cannot visit clock class's entry: ret={}",
4175 ret);
4176 goto end;
4177 }
4178 }
4179
4180 if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
4181 _BT_CPPLOGE_APPEND_CAUSE_NODE(clock_node, "Missing `name` attribute in clock class.");
4182 ret = -EPERM;
4183 goto end;
4184 }
4185
4186 clock_class_name = clock->name->str;
4187 BT_ASSERT(clock_class_name);
4188 if (ctx->is_lttng && strcmp(clock_class_name, "monotonic") == 0) {
4189 /*
4190 * Old versions of LTTng forgot to set its clock class
4191 * as absolute, even if it is. This is important because
4192 * it's a condition to be able to sort messages
4193 * from different sources.
4194 */
4195 clock->is_absolute = true;
4196 }
4197
4198 /*
4199 * Adjust offsets so that the part in cycles is less than the
4200 * frequency (move to the part in seconds).
4201 */
4202 {
4203 offsetSecLL = offset_seconds;
4204 offsetCyclesULL = offset_cycles;
4205 const auto normalized =
4206 ctf::src::normalizeClkOffset(offsetSecLL, offsetCyclesULL, clock->frequency);
4207 offsetSecLL = normalized.first;
4208 offsetCyclesULL = normalized.second;
4209 BT_ASSERT(offsetCyclesULL < clock->frequency);
4210 clock->offset_seconds = offsetSecLL;
4211 clock->offset_cycles = offsetCyclesULL;
4212 }
4213
4214 g_ptr_array_add(ctx->ctf_tc->clock_classes, clock);
4215 clock = NULL;
4216
4217 end:
4218 if (clock) {
4219 ctf_clock_class_destroy(clock);
4220 }
4221
4222 return ret;
4223 }
4224
4225 static int visit_root_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *root_decl_node)
4226 {
4227 int ret = 0;
4228
4229 if (root_decl_node->visited) {
4230 goto end;
4231 }
4232
4233 root_decl_node->visited = TRUE;
4234
4235 switch (root_decl_node->type) {
4236 case NODE_TYPEDEF:
4237 ret =
4238 visit_field_class_def(ctx, root_decl_node->u.field_class_def.field_class_specifier_list,
4239 &root_decl_node->u.field_class_def.field_class_declarators);
4240 if (ret) {
4241 _BT_CPPLOGE_APPEND_CAUSE_NODE(root_decl_node,
4242 "Cannot add field class found in root scope.");
4243 goto end;
4244 }
4245 break;
4246 case NODE_TYPEALIAS:
4247 ret = visit_field_class_alias(ctx, root_decl_node->u.field_class_alias.target,
4248 root_decl_node->u.field_class_alias.alias);
4249 if (ret) {
4250 _BT_CPPLOGE_APPEND_CAUSE_NODE(root_decl_node,
4251 "Cannot add field class alias found in root scope.");
4252 goto end;
4253 }
4254 break;
4255 case NODE_TYPE_SPECIFIER_LIST:
4256 {
4257 struct ctf_field_class *decl = NULL;
4258
4259 /*
4260 * Just add the field class specifier to the root
4261 * declaration scope. Put local reference.
4262 */
4263 ret = visit_field_class_specifier_list(ctx, root_decl_node, &decl);
4264 if (ret) {
4265 _BT_CPPLOGE_APPEND_CAUSE_NODE(root_decl_node,
4266 "Cannot visit root scope's field class: "
4267 "ret={}",
4268 ret);
4269 BT_ASSERT(!decl);
4270 goto end;
4271 }
4272
4273 ctf_field_class_destroy(decl);
4274 decl = NULL;
4275 break;
4276 }
4277 default:
4278 _BT_CPPLOGE_APPEND_CAUSE_NODE(root_decl_node, "Unexpected node type: node-type={}",
4279 root_decl_node->type);
4280 ret = -EPERM;
4281 goto end;
4282 }
4283
4284 end:
4285 return ret;
4286 }
4287
4288 int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
4289 {
4290 int ret = 0;
4291
4292 BT_CPPLOGI_SPEC(ctx->logger, "Visiting metadata's AST to generate CTF IR objects.");
4293
4294 switch (node->type) {
4295 case NODE_ROOT:
4296 {
4297 struct ctf_node *iter;
4298 bool got_trace_decl = false;
4299
4300 /*
4301 * The first thing we need is the native byte order of
4302 * the trace block, because early class aliases can have
4303 * a `byte_order` attribute set to `native`. If we don't
4304 * have the native byte order yet, and we don't have any
4305 * trace block yet, then fail with EINCOMPLETE.
4306 */
4307 if (ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_UNKNOWN) {
4308 bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
4309 if (got_trace_decl) {
4310 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block).");
4311 ret = -1;
4312 goto end;
4313 }
4314
4315 ret = set_trace_byte_order(ctx, iter);
4316 if (ret) {
4317 _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
4318 "Cannot set trace's native byte order: "
4319 "ret={}",
4320 ret);
4321 goto end;
4322 }
4323
4324 got_trace_decl = true;
4325 }
4326
4327 if (!got_trace_decl) {
4328 BT_CPPLOGD_SPEC(ctx->logger, "Incomplete AST: need trace (`trace` block).");
4329 ret = -EINCOMPLETE;
4330 goto end;
4331 }
4332 }
4333
4334 BT_ASSERT(ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_LITTLE ||
4335 ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_BIG);
4336 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4337
4338 /* Environment */
4339 bt_list_for_each_entry (iter, &node->u.root.env, siblings) {
4340 ret = visit_env(ctx, iter);
4341 if (ret) {
4342 _BT_CPPLOGE_APPEND_CAUSE_NODE(
4343 iter,
4344 "Cannot visit trace's environment (`env` block) entry: "
4345 "ret={}",
4346 ret);
4347 goto end;
4348 }
4349 }
4350
4351 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4352
4353 /*
4354 * Visit clock blocks.
4355 */
4356 bt_list_for_each_entry (iter, &node->u.root.clock, siblings) {
4357 ret = visit_clock_decl(ctx, iter);
4358 if (ret) {
4359 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit clock class: ret={}", ret);
4360 goto end;
4361 }
4362 }
4363
4364 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4365
4366 /*
4367 * Visit root declarations next, as they can be used by any
4368 * following entity.
4369 */
4370 bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) {
4371 ret = visit_root_decl(ctx, iter);
4372 if (ret) {
4373 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit root entry: ret={}", ret);
4374 goto end;
4375 }
4376 }
4377
4378 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4379
4380 /* Callsite blocks are not supported */
4381 bt_list_for_each_entry (iter, &node->u.root.callsite, siblings) {
4382 _BT_CPPLOGW_NODE(iter, "\"callsite\" blocks are not supported as of this version.");
4383 }
4384
4385 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4386
4387 /* Trace */
4388 bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
4389 ret = visit_trace_decl(ctx, iter);
4390 if (ret) {
4391 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
4392 "Cannot visit trace (`trace` block): "
4393 "ret={}",
4394 ret);
4395 goto end;
4396 }
4397 }
4398
4399 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4400
4401 /* Streams */
4402 bt_list_for_each_entry (iter, &node->u.root.stream, siblings) {
4403 ret = visit_stream_decl(ctx, iter);
4404 if (ret) {
4405 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit stream class: ret={}", ret);
4406 goto end;
4407 }
4408 }
4409
4410 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4411
4412 /* Events */
4413 bt_list_for_each_entry (iter, &node->u.root.event, siblings) {
4414 ret = visit_event_decl(ctx, iter);
4415 if (ret) {
4416 _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit event class: ret={}", ret);
4417 goto end;
4418 }
4419 }
4420
4421 BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
4422 break;
4423 }
4424 default:
4425 _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Unexpected node type: node-type={}", node->type);
4426 ret = -EINVAL;
4427 goto end;
4428 }
4429
4430 /* Update default clock classes */
4431 ret = ctf_trace_class_update_default_clock_classes(ctx->ctf_tc, ctx->logger);
4432 if (ret) {
4433 ret = -EINVAL;
4434 goto end;
4435 }
4436
4437 /* Update trace class meanings */
4438 ret = ctf_trace_class_update_meanings(ctx->ctf_tc);
4439 if (ret) {
4440 ret = -EINVAL;
4441 goto end;
4442 }
4443
4444 /* Update text arrays and sequences */
4445 ret = ctf_trace_class_update_text_array_sequence(ctx->ctf_tc);
4446 if (ret) {
4447 ret = -EINVAL;
4448 goto end;
4449 }
4450
4451 /* Update structure/array/sequence alignments */
4452 ret = ctf_trace_class_update_alignments(ctx->ctf_tc);
4453 if (ret) {
4454 ret = -EINVAL;
4455 goto end;
4456 }
4457
4458 /* Resolve sequence lengths and variant tags */
4459 ret = ctf_trace_class_resolve_field_classes(ctx->ctf_tc, ctx->logger);
4460 if (ret) {
4461 ret = -EINVAL;
4462 goto end;
4463 }
4464
4465 /* Validate what we have so far */
4466 ret = ctf_trace_class_validate(ctx->ctf_tc, ctx->logger);
4467 if (ret) {
4468 ret = -EINVAL;
4469 goto end;
4470 }
4471
4472 /*
4473 * If there are fields which are not related to the CTF format
4474 * itself in the packet header and in event header field
4475 * classes, warn about it because they are never translated.
4476 */
4477 ctf_trace_class_warn_meaningless_header_fields(ctx->ctf_tc, ctx->logger);
4478
4479 end:
4480 return ret;
4481 }
This page took 0.126235 seconds and 5 git commands to generate.