lib: decouple variant FC option names from selector FC mapping names
[babeltrace.git] / src / plugins / ctf / fs-sink / translate-trace-ir-to-ctf-ir.c
1 /*
2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #define BT_COMP_LOG_SELF_COMP (ctx->self_comp)
24 #define BT_LOG_OUTPUT_LEVEL (ctx->log_level)
25 #define BT_LOG_TAG "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"
26 #include "plugins/comp-logging.h"
27
28 #include <babeltrace2/babeltrace.h>
29 #include "common/macros.h"
30 #include "common/common.h"
31 #include "common/assert.h"
32 #include <stdio.h>
33 #include <stdbool.h>
34 #include <string.h>
35 #include <glib.h>
36
37 #include "fs-sink.h"
38 #include "fs-sink-ctf-meta.h"
39
40 struct field_path_elem {
41 uint64_t index_in_parent;
42 GString *name;
43
44 /* Weak */
45 const bt_field_class *ir_fc;
46
47 /* Weak */
48 struct fs_sink_ctf_field_class *parent_fc;
49 };
50
51 struct ctx {
52 bt_logging_level log_level;
53 bt_self_component *self_comp;
54
55 /* Weak */
56 struct fs_sink_ctf_stream_class *cur_sc;
57
58 /* Weak */
59 struct fs_sink_ctf_event_class *cur_ec;
60
61 bt_scope cur_scope;
62
63 /*
64 * Array of `struct field_path_elem` */
65 GArray *cur_path;
66 };
67
68 static inline
69 struct field_path_elem *cur_path_stack_at(struct ctx *ctx, uint64_t i)
70 {
71 BT_ASSERT(i < ctx->cur_path->len);
72 return &g_array_index(ctx->cur_path, struct field_path_elem, i);
73 }
74
75 static inline
76 struct field_path_elem *cur_path_stack_top(struct ctx *ctx)
77 {
78 BT_ASSERT(ctx->cur_path->len > 0);
79 return cur_path_stack_at(ctx, ctx->cur_path->len - 1);
80 }
81
82 static inline
83 bool is_reserved_member_name(const char *name, const char *reserved_name)
84 {
85 bool is_reserved = false;
86
87 if (strcmp(name, reserved_name) == 0) {
88 is_reserved = true;
89 goto end;
90 }
91
92 if (name[0] == '_' && strcmp(&name[1], reserved_name) == 0) {
93 is_reserved = true;
94 goto end;
95 }
96
97 end:
98 return is_reserved;
99 }
100
101 static const char *reserved_tsdl_keywords[] = {
102 "align",
103 "callsite",
104 "const",
105 "char",
106 "clock",
107 "double",
108 "enum",
109 "env",
110 "event",
111 "floating_point",
112 "float",
113 "integer",
114 "int",
115 "long",
116 "short",
117 "signed",
118 "stream",
119 "string",
120 "struct",
121 "trace",
122 "typealias",
123 "typedef",
124 "unsigned",
125 "variant",
126 "void",
127 "_Bool",
128 "_Complex",
129 "_Imaginary",
130 };
131
132 static inline
133 bool ist_valid_identifier(const char *name)
134 {
135 const char *at;
136 uint64_t i;
137 bool ist_valid = true;
138
139 /* Make sure the name is not a reserved keyword */
140 for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords);
141 i++) {
142 if (strcmp(name, reserved_tsdl_keywords[i]) == 0) {
143 ist_valid = false;
144 goto end;
145 }
146 }
147
148 /* Make sure the name is not an empty string */
149 if (strlen(name) == 0) {
150 ist_valid = false;
151 goto end;
152 }
153
154 /* Make sure the name starts with a letter or `_` */
155 if (!isalpha(name[0]) && name[0] != '_') {
156 ist_valid = false;
157 goto end;
158 }
159
160 /* Make sure the name only contains letters, digits, and `_` */
161 for (at = name; *at != '\0'; at++) {
162 if (!isalnum(*at) && *at != '_') {
163 ist_valid = false;
164 goto end;
165 }
166 }
167
168 end:
169 return ist_valid;
170 }
171
172 static inline
173 bool must_protect_identifier(const char *name)
174 {
175 uint64_t i;
176 bool must_protect = false;
177
178 /* Protect a reserved keyword */
179 for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords);
180 i++) {
181 if (strcmp(name, reserved_tsdl_keywords[i]) == 0) {
182 must_protect = true;
183 goto end;
184 }
185 }
186
187 /* Protect an identifier which already starts with `_` */
188 if (name[0] == '_') {
189 must_protect = true;
190 goto end;
191 }
192
193 end:
194 return must_protect;
195 }
196
197 static inline
198 int cur_path_stack_push(struct ctx *ctx,
199 uint64_t index_in_parent, const char *name,
200 bool force_protect_name, const bt_field_class *ir_fc,
201 struct fs_sink_ctf_field_class *parent_fc)
202 {
203 int ret = 0;
204 struct field_path_elem *field_path_elem;
205
206 g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1);
207 field_path_elem = cur_path_stack_top(ctx);
208 field_path_elem->index_in_parent = index_in_parent;
209 field_path_elem->name = g_string_new(NULL);
210
211 if (name) {
212 if (force_protect_name) {
213 g_string_assign(field_path_elem->name, "_");
214 }
215
216 g_string_append(field_path_elem->name, name);
217
218 if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) {
219 if (is_reserved_member_name(name, "packet_size") ||
220 is_reserved_member_name(name, "content_size") ||
221 is_reserved_member_name(name, "timestamp_begin") ||
222 is_reserved_member_name(name, "timestamp_end") ||
223 is_reserved_member_name(name, "events_discarded") ||
224 is_reserved_member_name(name, "packet_seq_num")) {
225 BT_COMP_LOGE("Unsupported reserved TSDL structure field class member "
226 "or variant field class option name: name=\"%s\"",
227 name);
228 ret = -1;
229 goto end;
230 }
231 }
232
233 if (!ist_valid_identifier(field_path_elem->name->str)) {
234 ret = -1;
235 BT_COMP_LOGE("Unsupported non-TSDL structure field class member "
236 "or variant field class option name: name=\"%s\"",
237 field_path_elem->name->str);
238 goto end;
239 }
240 }
241
242 field_path_elem->ir_fc = ir_fc;
243 field_path_elem->parent_fc = parent_fc;
244
245 end:
246 return ret;
247 }
248
249 static inline
250 void cur_path_stack_pop(struct ctx *ctx)
251 {
252 struct field_path_elem *field_path_elem;
253
254 BT_ASSERT(ctx->cur_path->len > 0);
255 field_path_elem = cur_path_stack_top(ctx);
256
257 if (field_path_elem->name) {
258 g_string_free(field_path_elem->name, TRUE);
259 field_path_elem->name = NULL;
260 }
261
262 g_array_set_size(ctx->cur_path, ctx->cur_path->len - 1);
263 }
264
265 /*
266 * Creates a relative field ref (a single name) from IR field path
267 * `tgt_ir_field_path`.
268 *
269 * This function tries to locate the target field class recursively from
270 * the top to the bottom of the context's current path using only the
271 * target field class's own name. This is because many CTF reading tools
272 * do not support a relative field ref with more than one element, for
273 * example `prev_struct.len`.
274 *
275 * Returns a negative value if this resolving operation failed.
276 */
277 static
278 int create_relative_field_ref(struct ctx *ctx,
279 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
280 struct fs_sink_ctf_field_class **user_tgt_fc)
281 {
282 int ret = 0;
283 struct fs_sink_ctf_field_class *tgt_fc = NULL;
284 uint64_t i;
285 int64_t si;
286 const char *tgt_fc_name = NULL;
287 struct field_path_elem *field_path_elem;
288
289 /* Get target field class's name */
290 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
291 case BT_SCOPE_PACKET_CONTEXT:
292 BT_ASSERT(ctx->cur_sc);
293 tgt_fc = ctx->cur_sc->packet_context_fc;
294 break;
295 case BT_SCOPE_EVENT_COMMON_CONTEXT:
296 BT_ASSERT(ctx->cur_sc);
297 tgt_fc = ctx->cur_sc->event_common_context_fc;
298 break;
299 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
300 BT_ASSERT(ctx->cur_ec);
301 tgt_fc = ctx->cur_ec->spec_context_fc;
302 break;
303 case BT_SCOPE_EVENT_PAYLOAD:
304 BT_ASSERT(ctx->cur_ec);
305 tgt_fc = ctx->cur_ec->payload_fc;
306 break;
307 default:
308 abort();
309 }
310
311 i = 0;
312
313 while (i < bt_field_path_get_item_count(tgt_ir_field_path)) {
314 const bt_field_path_item *fp_item =
315 bt_field_path_borrow_item_by_index_const(
316 tgt_ir_field_path, i);
317 struct fs_sink_ctf_named_field_class *named_fc = NULL;
318
319 BT_ASSERT(tgt_fc);
320 BT_ASSERT(fp_item);
321
322 switch (tgt_fc->type) {
323 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
324 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
325 BT_FIELD_PATH_ITEM_TYPE_INDEX);
326 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
327 (void *) tgt_fc,
328 bt_field_path_item_index_get_index(fp_item));
329 break;
330 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
331 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
332 BT_FIELD_PATH_ITEM_TYPE_INDEX);
333 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
334 (void *) tgt_fc,
335 bt_field_path_item_index_get_index(fp_item));
336 break;
337 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
338 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
339 {
340 struct fs_sink_ctf_field_class_array_base *array_base_fc =
341 (void *) tgt_fc;
342
343 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
344 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
345 tgt_fc = array_base_fc->elem_fc;
346 break;
347 }
348 default:
349 abort();
350 }
351
352 if (named_fc) {
353 tgt_fc = named_fc->fc;
354 tgt_fc_name = named_fc->name->str;
355 i++;
356 }
357 }
358
359 BT_ASSERT(tgt_fc);
360 BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
361 BT_ASSERT(tgt_fc_name);
362
363 /* Find target field class having this name in current context */
364 for (si = ctx->cur_path->len - 1; si >= 0; si--) {
365 struct fs_sink_ctf_field_class *fc;
366 struct fs_sink_ctf_field_class_struct *struct_fc;
367 struct fs_sink_ctf_field_class_variant *var_fc;
368 struct fs_sink_ctf_named_field_class *named_fc;
369 uint64_t len;
370
371 field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
372 fc = field_path_elem->parent_fc;
373 if (!fc) {
374 /* Reached stack's bottom */
375 ret = -1;
376 goto end;
377 }
378
379 switch (fc->type) {
380 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
381 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
382 break;
383 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
384 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
385 continue;
386 default:
387 /* Not supported by TSDL 1.8 */
388 ret = -1;
389 goto end;
390 }
391
392 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
393 struct_fc = (void *) fc;
394 len = struct_fc->members->len;
395 } else {
396 var_fc = (void *) fc;
397 len = var_fc->options->len;
398 }
399
400 for (i = 0; i < len; i++) {
401 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
402 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
403 struct_fc, i);
404 } else {
405 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
406 var_fc, i);
407 }
408
409 if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
410 if (named_fc->fc == tgt_fc) {
411 g_string_assign(tgt_field_ref,
412 tgt_fc_name);
413
414 if (user_tgt_fc) {
415 *user_tgt_fc = tgt_fc;
416 }
417 } else {
418 /*
419 * Using only the target field
420 * class's name, we're not
421 * reaching the target field
422 * class. This is not supported
423 * by TSDL 1.8.
424 */
425 ret = -1;
426 }
427
428 goto end;
429 }
430 }
431 }
432
433 end:
434 return ret;
435 }
436
437 /*
438 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
439 *
440 * Returns a negative value if this resolving operation failed.
441 */
442 static
443 int create_absolute_field_ref(struct ctx *ctx,
444 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
445 struct fs_sink_ctf_field_class **user_tgt_fc)
446 {
447 int ret = 0;
448 struct fs_sink_ctf_field_class *fc = NULL;
449 uint64_t i;
450
451 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
452 case BT_SCOPE_PACKET_CONTEXT:
453 BT_ASSERT(ctx->cur_sc);
454 fc = ctx->cur_sc->packet_context_fc;
455 g_string_assign(tgt_field_ref, "stream.packet.context");
456 break;
457 case BT_SCOPE_EVENT_COMMON_CONTEXT:
458 BT_ASSERT(ctx->cur_sc);
459 fc = ctx->cur_sc->event_common_context_fc;
460 g_string_assign(tgt_field_ref, "stream.event.context");
461 break;
462 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
463 BT_ASSERT(ctx->cur_ec);
464 fc = ctx->cur_ec->spec_context_fc;
465 g_string_assign(tgt_field_ref, "event.context");
466 break;
467 case BT_SCOPE_EVENT_PAYLOAD:
468 BT_ASSERT(ctx->cur_ec);
469 fc = ctx->cur_ec->payload_fc;
470 g_string_assign(tgt_field_ref, "event.fields");
471 break;
472 default:
473 abort();
474 }
475
476 BT_ASSERT(fc);
477
478 for (i = 0; i < bt_field_path_get_item_count(tgt_ir_field_path); i++) {
479 const bt_field_path_item *fp_item =
480 bt_field_path_borrow_item_by_index_const(
481 tgt_ir_field_path, i);
482 struct fs_sink_ctf_named_field_class *named_fc = NULL;
483
484 if (bt_field_path_item_get_type(fp_item) !=
485 BT_FIELD_PATH_ITEM_TYPE_INDEX) {
486 /* Not supported by TSDL 1.8 */
487 ret = -1;
488 goto end;
489 }
490
491 switch (fc->type) {
492 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
493 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
494 BT_FIELD_PATH_ITEM_TYPE_INDEX);
495 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
496 (void *) fc,
497 bt_field_path_item_index_get_index(fp_item));
498 break;
499 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
500 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
501 BT_FIELD_PATH_ITEM_TYPE_INDEX);
502 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
503 (void *) fc,
504 bt_field_path_item_index_get_index(fp_item));
505 break;
506 default:
507 abort();
508 }
509
510 BT_ASSERT(named_fc);
511 g_string_append_c(tgt_field_ref, '.');
512 g_string_append(tgt_field_ref, named_fc->name->str);
513 fc = named_fc->fc;
514 }
515
516 if (user_tgt_fc) {
517 *user_tgt_fc = fc;
518 }
519
520 end:
521 return ret;
522 }
523
524 /*
525 * Resolves a target field class located at `tgt_ir_field_path`, writing
526 * the resolved field ref to `tgt_field_ref` and setting
527 * `*create_before` according to whether or not the target field must be
528 * created immediately before (in which case `tgt_field_ref` is
529 * irrelevant).
530 */
531 static
532 void resolve_field_class(struct ctx *ctx,
533 const bt_field_path *tgt_ir_field_path,
534 GString *tgt_field_ref, bool *create_before,
535 struct fs_sink_ctf_field_class **user_tgt_fc)
536 {
537 int ret;
538 bt_scope tgt_scope;
539
540 *create_before = false;
541
542 if (!tgt_ir_field_path) {
543 *create_before = true;
544 goto end;
545 }
546
547 tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
548
549 if (tgt_scope == ctx->cur_scope) {
550 /*
551 * Try, in this order:
552 *
553 * 1. Use a relative path, using only the target field
554 * class's name. This is what is the most commonly
555 * supported by popular CTF reading tools.
556 *
557 * 2. Use an absolute path. This could fail if there's
558 * an array field class from the current root's field
559 * class to the target field class.
560 *
561 * 3. Create the target field class before the
562 * requesting field class (fallback).
563 */
564 ret = create_relative_field_ref(ctx, tgt_ir_field_path,
565 tgt_field_ref, user_tgt_fc);
566 if (ret) {
567 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
568 tgt_field_ref, user_tgt_fc);
569 if (ret) {
570 *create_before = true;
571 ret = 0;
572 goto end;
573 }
574 }
575 } else {
576 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
577 tgt_field_ref, user_tgt_fc);
578
579 /* It must always work in previous scopes */
580 BT_ASSERT(ret == 0);
581 }
582
583 end:
584 return;
585 }
586
587 static
588 int translate_field_class(struct ctx *ctx);
589
590 static inline
591 void append_to_parent_field_class(struct ctx *ctx,
592 struct fs_sink_ctf_field_class *fc)
593 {
594 struct fs_sink_ctf_field_class *parent_fc =
595 cur_path_stack_top(ctx)->parent_fc;
596
597 switch (parent_fc->type) {
598 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
599 fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
600 cur_path_stack_top(ctx)->name->str, fc);
601 break;
602 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
603 fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
604 cur_path_stack_top(ctx)->name->str, fc);
605 break;
606 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
607 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
608 {
609 struct fs_sink_ctf_field_class_array_base *array_base_fc =
610 (void *) parent_fc;
611
612 BT_ASSERT(!array_base_fc->elem_fc);
613 array_base_fc->elem_fc = fc;
614 array_base_fc->base.alignment = fc->alignment;
615 break;
616 }
617 default:
618 abort();
619 }
620 }
621
622 static inline
623 void update_parent_field_class_alignment(struct ctx *ctx,
624 unsigned int alignment)
625 {
626 struct fs_sink_ctf_field_class *parent_fc =
627 cur_path_stack_top(ctx)->parent_fc;
628
629 switch (parent_fc->type) {
630 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
631 fs_sink_ctf_field_class_struct_align_at_least(
632 (void *) parent_fc, alignment);
633 break;
634 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
635 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
636 {
637 struct fs_sink_ctf_field_class_array_base *array_base_fc =
638 (void *) parent_fc;
639
640 array_base_fc->base.alignment = alignment;
641 break;
642 }
643 default:
644 break;
645 }
646 }
647
648 static inline
649 int translate_structure_field_class_members(struct ctx *ctx,
650 struct fs_sink_ctf_field_class_struct *struct_fc,
651 const bt_field_class *ir_fc)
652 {
653 int ret = 0;
654 uint64_t i;
655
656 for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
657 const bt_field_class_structure_member *member;
658 const char *name;
659 const bt_field_class *memb_ir_fc;
660
661 member =
662 bt_field_class_structure_borrow_member_by_index_const(
663 ir_fc, i);
664 name = bt_field_class_structure_member_get_name(member);
665 memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
666 member);
667 ret = cur_path_stack_push(ctx, i, name, true, memb_ir_fc,
668 (void *) struct_fc);
669 if (ret) {
670 BT_COMP_LOGE("Cannot translate structure field class member: "
671 "name=\"%s\"", name);
672 goto end;
673 }
674
675 ret = translate_field_class(ctx);
676 if (ret) {
677 BT_COMP_LOGE("Cannot translate structure field class member: "
678 "name=\"%s\"", name);
679 goto end;
680 }
681
682 cur_path_stack_pop(ctx);
683 }
684
685 end:
686 return ret;
687 }
688
689 static inline
690 int translate_structure_field_class(struct ctx *ctx)
691 {
692 int ret;
693 struct fs_sink_ctf_field_class_struct *fc =
694 fs_sink_ctf_field_class_struct_create_empty(
695 cur_path_stack_top(ctx)->ir_fc,
696 cur_path_stack_top(ctx)->index_in_parent);
697
698 BT_ASSERT(fc);
699 append_to_parent_field_class(ctx, (void *) fc);
700 ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
701 if (ret) {
702 goto end;
703 }
704
705 update_parent_field_class_alignment(ctx, fc->base.alignment);
706
707 end:
708 return ret;
709 }
710
711 /*
712 * This function returns whether or not a given field class `tag_fc`
713 * is valid as the tag field class of the variant field class `fc`.
714 *
715 * CTF 1.8 requires that the tag field class be an enumeration field
716 * class and that, for each variant field class option's range set, the
717 * tag field class contains a mapping which has the option's name and an
718 * equal range set.
719 */
720 static inline
721 bool _is_variant_field_class_tag_valid(
722 struct fs_sink_ctf_field_class_variant *fc,
723 struct fs_sink_ctf_field_class *tag_fc)
724 {
725 bool is_valid = true;
726 bt_field_class_type ir_tag_fc_type = bt_field_class_get_type(
727 tag_fc->ir_fc);
728 uint64_t i;
729 GString *escaped_opt_name = g_string_new(NULL);
730
731 BT_ASSERT(escaped_opt_name);
732
733 if (ir_tag_fc_type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION &&
734 ir_tag_fc_type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
735 is_valid = false;
736 goto end;
737 }
738
739 for (i = 0; i < bt_field_class_variant_get_option_count(
740 fc->base.ir_fc); i++) {
741 const bt_field_class_variant_option *var_opt_base =
742 bt_field_class_variant_borrow_option_by_index_const(
743 fc->base.ir_fc, i);
744 const char *opt_name = bt_field_class_variant_option_get_name(
745 var_opt_base);
746
747 /*
748 * If the option is named `name` in trace IR, then it
749 * was _possibly_ named `_name` originally if it comes
750 * from `src.ctf.fs`. This means the corresponding
751 * enumeration field class mapping was also named
752 * `_name`, but this one didn't change, as enumeration
753 * FC mapping names are not escaped; they are literal
754 * strings.
755 *
756 * The `sink.ctf.fs` component escapes all the variant
757 * FC option names with `_`. Therefore the
758 * _escaped name_ must match the original enumeration
759 * FC mapping name.
760 */
761 g_string_assign(escaped_opt_name, "_");
762 g_string_append(escaped_opt_name, opt_name);
763
764 if (ir_tag_fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
765 const bt_field_class_variant_with_unsigned_selector_option *var_opt =
766 bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const(
767 fc->base.ir_fc, i);
768 const bt_field_class_unsigned_enumeration_mapping *mapping;
769 const bt_integer_range_set_unsigned *opt_ranges;
770 const bt_integer_range_set_unsigned *mapping_ranges;
771
772 mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_label_const(
773 tag_fc->ir_fc, escaped_opt_name->str);
774 if (!mapping) {
775 is_valid = false;
776 goto end;
777 }
778
779 opt_ranges = bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const(
780 var_opt);
781 mapping_ranges = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const(
782 mapping);
783 if (!bt_integer_range_set_unsigned_compare(opt_ranges,
784 mapping_ranges)) {
785 is_valid = false;
786 goto end;
787 }
788 } else {
789 const bt_field_class_variant_with_signed_selector_option *var_opt =
790 bt_field_class_variant_with_signed_selector_borrow_option_by_index_const(
791 fc->base.ir_fc, i);
792 const bt_field_class_signed_enumeration_mapping *mapping;
793 const bt_integer_range_set_signed *opt_ranges;
794 const bt_integer_range_set_signed *mapping_ranges;
795
796 mapping = bt_field_class_signed_enumeration_borrow_mapping_by_label_const(
797 tag_fc->ir_fc, escaped_opt_name->str);
798 if (!mapping) {
799 is_valid = false;
800 goto end;
801 }
802
803 opt_ranges = bt_field_class_variant_with_signed_selector_option_borrow_ranges_const(
804 var_opt);
805 mapping_ranges = bt_field_class_signed_enumeration_mapping_borrow_ranges_const(
806 mapping);
807 if (!bt_integer_range_set_signed_compare(opt_ranges,
808 mapping_ranges)) {
809 is_valid = false;
810 goto end;
811 }
812 }
813 }
814
815 end:
816 return is_valid;
817 }
818
819 /*
820 * This function indicates whether or not a given variant FC option name
821 * must be protected (with the `_` prefix).
822 *
823 * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
824 * close as possible to an original CTF trace as decoded by
825 * `src.ctf.fs`.
826 *
827 * This scenario is valid in CTF 1.8:
828 *
829 * enum {
830 * HELLO,
831 * MEOW
832 * } tag;
833 *
834 * variant <tag> {
835 * int HELLO;
836 * string MEOW;
837 * };
838 *
839 * Once in trace IR, the enumeration FC mapping names and variant FC
840 * option names are kept as is. For this reason, we don't want to
841 * protect the variant FC option names here (by prepending `_`): this
842 * would make the variant FC option name and the enumeration FC mapping
843 * name not match.
844 *
845 * This scenario is also valid in CTF 1.8:
846 *
847 * enum {
848 * _HELLO,
849 * MEOW
850 * } tag;
851 *
852 * variant <tag> {
853 * int _HELLO;
854 * string MEOW;
855 * };
856 *
857 * Once in trace IR, the enumeration FC mapping names are kept as is,
858 * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
859 * for presentation, as recommended by CTF 1.8). When going back to
860 * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
861 * the corresponding enumeration FC mapping name.
862 *
863 * This scenario is also valid in CTF 1.8:
864 *
865 * enum {
866 * __HELLO,
867 * MEOW
868 * } tag;
869 *
870 * variant <tag> {
871 * int __HELLO;
872 * string MEOW;
873 * };
874 *
875 * Once in trace IR, the enumeration FC mapping names are kept as is,
876 * but the `__HELLO` variant FC option name becomes `_HELLO`
877 * (unprotected). When going back to TSDL, we need to protect `_HELLO`
878 * so that it becomes `__HELLO` to match the corresponding enumeration
879 * FC mapping name.
880 *
881 * `src.ctf.fs` always uses the _same_ integer range sets for a selector
882 * FC mapping and a corresponding variant FC option. We can use that
883 * fact to find the original variant FC option names by matching variant
884 * FC options and enumeration FC mappings by range set.
885 */
886 static
887 int must_protect_variant_option_name(const bt_field_class *ir_var_fc,
888 const bt_field_class *ir_tag_fc, uint64_t opt_i,
889 GString *name_buf, bool *must_protect)
890 {
891 int ret = 0;
892 uint64_t i;
893 bt_field_class_type ir_var_fc_type;
894 const void *opt_ranges = NULL;
895 const char *mapping_label = NULL;
896 const char *ir_opt_name;
897 const bt_field_class_variant_option *base_var_opt;
898 bool force_protect = false;
899
900 *must_protect = false;
901 ir_var_fc_type = bt_field_class_get_type(ir_var_fc);
902 base_var_opt = bt_field_class_variant_borrow_option_by_index_const(
903 ir_var_fc, opt_i);
904 BT_ASSERT(base_var_opt);
905 ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt);
906 BT_ASSERT(ir_opt_name);
907
908 /*
909 * Check if the variant FC option name is required to be
910 * protected (reserved TSDL keyword or starts with `_`). In that
911 * case, the name of the selector FC mapping we find must match
912 * exactly the protected name.
913 */
914 force_protect = must_protect_identifier(ir_opt_name);
915 if (force_protect) {
916 *must_protect = true;
917 g_string_assign(name_buf, "_");
918 g_string_append(name_buf, ir_opt_name);
919 } else {
920 g_string_assign(name_buf, ir_opt_name);
921 }
922
923 /* Borrow option's ranges */
924 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR) {
925 /* No ranges: we're done */
926 goto end;
927 } if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) {
928 const bt_field_class_variant_with_unsigned_selector_option *var_opt =
929 bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const(
930 ir_var_fc, opt_i);
931 opt_ranges =
932 bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const(
933 var_opt);
934 } else {
935 const bt_field_class_variant_with_signed_selector_option *var_opt =
936 bt_field_class_variant_with_signed_selector_borrow_option_by_index_const(
937 ir_var_fc, opt_i);
938 opt_ranges =
939 bt_field_class_variant_with_signed_selector_option_borrow_ranges_const(
940 var_opt);
941 }
942
943 /* Find corresponding mapping by range set in selector FC */
944 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_tag_fc);
945 i++) {
946 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) {
947 const bt_field_class_enumeration_mapping *mapping_base;
948 const bt_field_class_unsigned_enumeration_mapping *mapping;
949 const bt_integer_range_set_unsigned *mapping_ranges;
950
951 mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
952 ir_tag_fc, i);
953 mapping_ranges = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const(
954 mapping);
955
956 if (bt_integer_range_set_unsigned_compare(opt_ranges,
957 mapping_ranges)) {
958 /* We have a winner */
959 mapping_base =
960 bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
961 mapping);
962 mapping_label =
963 bt_field_class_enumeration_mapping_get_label(
964 mapping_base);
965 break;
966 }
967 } else {
968 const bt_field_class_enumeration_mapping *mapping_base;
969 const bt_field_class_signed_enumeration_mapping *mapping;
970 const bt_integer_range_set_signed *mapping_ranges;
971
972 mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
973 ir_tag_fc, i);
974 mapping_ranges = bt_field_class_signed_enumeration_mapping_borrow_ranges_const(
975 mapping);
976
977 if (bt_integer_range_set_signed_compare(opt_ranges,
978 mapping_ranges)) {
979 /* We have a winner */
980 mapping_base =
981 bt_field_class_signed_enumeration_mapping_as_mapping_const(
982 mapping);
983 mapping_label =
984 bt_field_class_enumeration_mapping_get_label(
985 mapping_base);
986 break;
987 }
988 }
989 }
990
991 if (!mapping_label) {
992 /* Range set not found: invalid selector for CTF 1.8 */
993 ret = -1;
994 goto end;
995 }
996
997 /*
998 * If the enumeration FC mapping name is not the same as the
999 * variant FC option name and we didn't protect already, try
1000 * protecting the option name and check again.
1001 */
1002 if (strcmp(mapping_label, name_buf->str) != 0) {
1003 if (force_protect) {
1004 ret = -1;
1005 goto end;
1006 }
1007
1008 if (mapping_label[0] == '\0') {
1009 ret = -1;
1010 goto end;
1011 }
1012
1013 g_string_assign(name_buf, "_");
1014 g_string_append(name_buf, ir_opt_name);
1015
1016 if (strcmp(mapping_label, name_buf->str) != 0) {
1017 ret = -1;
1018 goto end;
1019 }
1020
1021 /*
1022 * If this comes from a `src.ctf.fs` source, it looks
1023 * like the variant FC option name was initially
1024 * protected: protect it again when going back to TSDL.
1025 */
1026 *must_protect = true;
1027 }
1028
1029 end:
1030 return ret;
1031 }
1032
1033 static inline
1034 int translate_variant_field_class(struct ctx *ctx)
1035 {
1036 int ret = 0;
1037 uint64_t i;
1038 struct fs_sink_ctf_field_class_variant *fc =
1039 fs_sink_ctf_field_class_variant_create_empty(
1040 cur_path_stack_top(ctx)->ir_fc,
1041 cur_path_stack_top(ctx)->index_in_parent);
1042 bt_field_class_type ir_fc_type;
1043 const bt_field_path *ir_selector_field_path = NULL;
1044 struct fs_sink_ctf_field_class *tgt_fc = NULL;
1045 GString *name_buf = g_string_new(NULL);
1046 bt_value *prot_opt_names = bt_value_array_create();
1047 uint64_t opt_count;
1048
1049 BT_ASSERT(fc);
1050 BT_ASSERT(name_buf);
1051 BT_ASSERT(prot_opt_names);
1052 ir_fc_type = bt_field_class_get_type(fc->base.ir_fc);
1053 opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc);
1054
1055 if (ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR ||
1056 ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) {
1057 ir_selector_field_path = bt_field_class_variant_with_selector_borrow_selector_field_path_const(
1058 fc->base.ir_fc);
1059 BT_ASSERT(ir_selector_field_path);
1060 }
1061
1062 /* Resolve tag field class before appending to parent */
1063 resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref,
1064 &fc->tag_is_before, &tgt_fc);
1065
1066 if (ir_selector_field_path && tgt_fc) {
1067 uint64_t mapping_count;
1068 uint64_t option_count;
1069
1070 /* CTF 1.8: selector FC must be an enumeration FC */
1071 bt_field_class_type type = bt_field_class_get_type(
1072 tgt_fc->ir_fc);
1073
1074 if (type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION &&
1075 type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
1076 fc->tag_is_before = true;
1077 goto validate_opts;
1078 }
1079
1080 /*
1081 * Call must_protect_variant_option_name() for each
1082 * option below. In that case we also want selector FC
1083 * to contain as many mappings as the variant FC has
1084 * options.
1085 */
1086 mapping_count = bt_field_class_enumeration_get_mapping_count(
1087 tgt_fc->ir_fc);
1088 option_count = bt_field_class_variant_get_option_count(
1089 fc->base.ir_fc);
1090
1091 if (mapping_count != option_count) {
1092 fc->tag_is_before = true;
1093 goto validate_opts;
1094 }
1095 } else {
1096 /*
1097 * No compatible selector field class for CTF 1.8:
1098 * create the appropriate selector field class.
1099 */
1100 fc->tag_is_before = true;
1101 }
1102
1103 validate_opts:
1104 /*
1105 * First pass: detect any option name clash with option name
1106 * protection. In that case, we don't fail: just create the
1107 * selector field class before the variant field class.
1108 *
1109 * After this, `prot_opt_names` contains the final option names,
1110 * potentially protected if needed. They can still be invalid
1111 * TSDL identifiers however; this will be checked by
1112 * cur_path_stack_push().
1113 */
1114 for (i = 0; i < opt_count; i++) {
1115 bool must_protect = false;
1116
1117 ret = must_protect_variant_option_name(fc->base.ir_fc,
1118 tgt_fc->ir_fc, i, name_buf, &must_protect);
1119 if (ret) {
1120 fc->tag_is_before = true;
1121 }
1122
1123 ret = bt_value_array_append_string_element(prot_opt_names,
1124 name_buf->str);
1125 if (ret) {
1126 goto end;
1127 }
1128 }
1129
1130 for (i = 0; i < opt_count; i++) {
1131 uint64_t j;
1132 const bt_value *opt_name_a =
1133 bt_value_array_borrow_element_by_index_const(
1134 prot_opt_names, i);
1135
1136 for (j = 0; j < opt_count; j++) {
1137 const bt_value *opt_name_b;
1138
1139 if (i == j) {
1140 continue;
1141 }
1142
1143 opt_name_b =
1144 bt_value_array_borrow_element_by_index_const(
1145 prot_opt_names, j);
1146 if (bt_value_compare(opt_name_a, opt_name_b)) {
1147 /*
1148 * Variant FC option names are not
1149 * unique when protected.
1150 */
1151 fc->tag_is_before = true;
1152 goto append_to_parent;
1153 }
1154 }
1155 }
1156
1157 append_to_parent:
1158 append_to_parent_field_class(ctx, (void *) fc);
1159
1160 for (i = 0; i < opt_count; i++) {
1161 const bt_field_class_variant_option *opt;
1162 const bt_field_class *opt_ir_fc;
1163 const bt_value *prot_opt_name_val =
1164 bt_value_array_borrow_element_by_index_const(
1165 prot_opt_names, i);
1166 const char *prot_opt_name = bt_value_string_get(
1167 prot_opt_name_val);
1168
1169 BT_ASSERT(prot_opt_name);
1170 opt = bt_field_class_variant_borrow_option_by_index_const(
1171 fc->base.ir_fc, i);
1172 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
1173 opt);
1174
1175 /*
1176 * We don't ask cur_path_stack_push() to protect the
1177 * option name because it's already protected at this
1178 * point.
1179 */
1180 ret = cur_path_stack_push(ctx, i, prot_opt_name, false,
1181 opt_ir_fc, (void *) fc);
1182 if (ret) {
1183 BT_COMP_LOGE("Cannot translate variant field class option: "
1184 "name=\"%s\"", prot_opt_name);
1185 goto end;
1186 }
1187
1188 ret = translate_field_class(ctx);
1189 if (ret) {
1190 BT_COMP_LOGE("Cannot translate variant field class option: "
1191 "name=\"%s\"", prot_opt_name);
1192 goto end;
1193 }
1194
1195 cur_path_stack_pop(ctx);
1196 }
1197
1198 end:
1199 if (name_buf) {
1200 g_string_free(name_buf, TRUE);
1201 }
1202
1203 bt_value_put_ref(prot_opt_names);
1204 return ret;
1205 }
1206
1207 static inline
1208 int translate_static_array_field_class(struct ctx *ctx)
1209 {
1210 struct fs_sink_ctf_field_class_array *fc =
1211 fs_sink_ctf_field_class_array_create_empty(
1212 cur_path_stack_top(ctx)->ir_fc,
1213 cur_path_stack_top(ctx)->index_in_parent);
1214 const bt_field_class *elem_ir_fc =
1215 bt_field_class_array_borrow_element_field_class_const(
1216 fc->base.base.ir_fc);
1217 int ret;
1218
1219 BT_ASSERT(fc);
1220 append_to_parent_field_class(ctx, (void *) fc);
1221 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
1222 (void *) fc);
1223 if (ret) {
1224 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
1225 goto end;
1226 }
1227
1228 ret = translate_field_class(ctx);
1229 if (ret) {
1230 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
1231 goto end;
1232 }
1233
1234 cur_path_stack_pop(ctx);
1235 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1236
1237 end:
1238 return ret;
1239 }
1240
1241 static inline
1242 int translate_dynamic_array_field_class(struct ctx *ctx)
1243 {
1244 struct fs_sink_ctf_field_class_sequence *fc =
1245 fs_sink_ctf_field_class_sequence_create_empty(
1246 cur_path_stack_top(ctx)->ir_fc,
1247 cur_path_stack_top(ctx)->index_in_parent);
1248 const bt_field_class *elem_ir_fc =
1249 bt_field_class_array_borrow_element_field_class_const(
1250 fc->base.base.ir_fc);
1251 int ret;
1252
1253 BT_ASSERT(fc);
1254
1255 /* Resolve length field class before appending to parent */
1256 resolve_field_class(ctx,
1257 bt_field_class_dynamic_array_borrow_length_field_path_const(
1258 fc->base.base.ir_fc),
1259 fc->length_ref, &fc->length_is_before, NULL);
1260
1261 append_to_parent_field_class(ctx, (void *) fc);
1262 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
1263 (void *) fc);
1264 if (ret) {
1265 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
1266 goto end;
1267 }
1268
1269 ret = translate_field_class(ctx);
1270 if (ret) {
1271 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
1272 goto end;
1273 }
1274
1275 cur_path_stack_pop(ctx);
1276 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1277
1278 end:
1279 return ret;
1280 }
1281
1282 static inline
1283 int translate_integer_field_class(struct ctx *ctx)
1284 {
1285 struct fs_sink_ctf_field_class_int *fc =
1286 fs_sink_ctf_field_class_int_create(
1287 cur_path_stack_top(ctx)->ir_fc,
1288 cur_path_stack_top(ctx)->index_in_parent);
1289
1290 BT_ASSERT(fc);
1291 append_to_parent_field_class(ctx, (void *) fc);
1292 return 0;
1293 }
1294
1295 static inline
1296 int translate_real_field_class(struct ctx *ctx)
1297 {
1298 struct fs_sink_ctf_field_class_float *fc =
1299 fs_sink_ctf_field_class_float_create(
1300 cur_path_stack_top(ctx)->ir_fc,
1301 cur_path_stack_top(ctx)->index_in_parent);
1302
1303 BT_ASSERT(fc);
1304 append_to_parent_field_class(ctx, (void *) fc);
1305 return 0;
1306 }
1307
1308 static inline
1309 int translate_string_field_class(struct ctx *ctx)
1310 {
1311 struct fs_sink_ctf_field_class_string *fc =
1312 fs_sink_ctf_field_class_string_create(
1313 cur_path_stack_top(ctx)->ir_fc,
1314 cur_path_stack_top(ctx)->index_in_parent);
1315
1316 BT_ASSERT(fc);
1317 append_to_parent_field_class(ctx, (void *) fc);
1318 return 0;
1319 }
1320
1321 /*
1322 * Translates a field class, recursively.
1323 *
1324 * The field class's IR field class, parent field class, and index
1325 * within its parent are in the context's current path's top element
1326 * (cur_path_stack_top()).
1327 */
1328 static
1329 int translate_field_class(struct ctx *ctx)
1330 {
1331 int ret;
1332
1333 switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
1334 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
1335 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
1336 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1337 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1338 ret = translate_integer_field_class(ctx);
1339 break;
1340 case BT_FIELD_CLASS_TYPE_REAL:
1341 ret = translate_real_field_class(ctx);
1342 break;
1343 case BT_FIELD_CLASS_TYPE_STRING:
1344 ret = translate_string_field_class(ctx);
1345 break;
1346 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1347 ret = translate_structure_field_class(ctx);
1348 break;
1349 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1350 ret = translate_static_array_field_class(ctx);
1351 break;
1352 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1353 ret = translate_dynamic_array_field_class(ctx);
1354 break;
1355 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
1356 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
1357 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
1358 ret = translate_variant_field_class(ctx);
1359 break;
1360 default:
1361 abort();
1362 }
1363
1364 return ret;
1365 }
1366
1367 static
1368 int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
1369 struct fs_sink_ctf_field_class *parent_fc)
1370 {
1371 int ret = 0;
1372 GString *field_ref = NULL;
1373 bool is_before;
1374 const char *tgt_type;
1375 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
1376 (void *) parent_fc;
1377 uint64_t i;
1378 unsigned int suffix = 0;
1379
1380 if (!fc_name || !parent_fc ||
1381 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1382 /* Not supported */
1383 ret = -1;
1384 goto end;
1385 }
1386
1387 switch (fc->type) {
1388 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1389 {
1390 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
1391
1392 field_ref = seq_fc->length_ref;
1393 is_before = seq_fc->length_is_before;
1394 tgt_type = "len";
1395 break;
1396 }
1397 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1398 {
1399 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
1400
1401 field_ref = var_fc->tag_ref;
1402 is_before = var_fc->tag_is_before;
1403 tgt_type = "tag";
1404 break;
1405 }
1406 default:
1407 abort();
1408 }
1409
1410 BT_ASSERT(field_ref);
1411
1412 if (!is_before) {
1413 goto end;
1414 }
1415
1416 /* Initial field ref */
1417 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
1418
1419 /*
1420 * Make sure field ref does not clash with an existing field
1421 * class name within the same parent structure field class.
1422 */
1423 while (true) {
1424 bool name_ok = true;
1425
1426 for (i = 0; i < parent_struct_fc->members->len; i++) {
1427 struct fs_sink_ctf_named_field_class *named_fc =
1428 fs_sink_ctf_field_class_struct_borrow_member_by_index(
1429 parent_struct_fc, i);
1430
1431 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
1432 /* Name clash */
1433 name_ok = false;
1434 break;
1435 }
1436 }
1437
1438 if (name_ok) {
1439 /* No clash: we're done */
1440 break;
1441 }
1442
1443 /* Append suffix and try again */
1444 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
1445 suffix);
1446 suffix++;
1447 }
1448
1449 end:
1450 return ret;
1451 }
1452
1453 /*
1454 * This function recursively sets field refs of sequence and variant
1455 * field classes when they are immediately before, avoiding name clashes
1456 * with existing field class names.
1457 *
1458 * It can fail at this point if, for example, a sequence field class of
1459 * which to set the length's field ref has something else than a
1460 * structure field class as its parent: in this case, there's no
1461 * location to place the length field class immediately before the
1462 * sequence field class.
1463 */
1464 static
1465 int set_field_refs(struct fs_sink_ctf_field_class * const fc,
1466 const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
1467 {
1468 int ret = 0;
1469 enum fs_sink_ctf_field_class_type fc_type;
1470 BT_ASSERT(fc);
1471
1472 fc_type = fc->type;
1473
1474 switch (fc_type) {
1475 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1476 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1477 {
1478 uint64_t i;
1479 uint64_t len;
1480 struct fs_sink_ctf_field_class_struct *struct_fc;
1481 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
1482 struct fs_sink_ctf_named_field_class *named_fc;
1483
1484 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1485 struct_fc = (void *) fc;
1486 len = struct_fc->members->len;
1487 } else {
1488 var_fc = (void *) fc;
1489 len = var_fc->options->len;
1490 ret = set_field_ref(fc, fc_name, parent_fc);
1491 if (ret) {
1492 goto end;
1493 }
1494 }
1495
1496 for (i = 0; i < len; i++) {
1497 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1498 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1499 struct_fc, i);
1500 } else {
1501 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1502 var_fc, i);
1503 }
1504
1505 ret = set_field_refs(named_fc->fc, named_fc->name->str,
1506 fc);
1507 if (ret) {
1508 goto end;
1509 }
1510 }
1511
1512 break;
1513 }
1514 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
1515 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1516 {
1517 struct fs_sink_ctf_field_class_array_base *array_base_fc =
1518 (void *) fc;
1519
1520 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
1521 ret = set_field_ref(fc, fc_name, parent_fc);
1522 if (ret) {
1523 goto end;
1524 }
1525 }
1526
1527 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
1528 if (ret) {
1529 goto end;
1530 }
1531
1532 break;
1533 }
1534 default:
1535 break;
1536 }
1537
1538 end:
1539 return ret;
1540 }
1541
1542 /*
1543 * This function translates a root scope trace IR field class to
1544 * a CTF IR field class.
1545 *
1546 * The resulting CTF IR field class is written to `*fc` so that it
1547 * exists as the parent object's (stream class or event class) true root
1548 * field class during the recursive translation for resolving purposes.
1549 * This is also why this function creates the empty structure field
1550 * class and then calls translate_structure_field_class_members() to
1551 * fill it.
1552 */
1553 static
1554 int translate_scope_field_class(struct ctx *ctx, bt_scope scope,
1555 struct fs_sink_ctf_field_class **fc,
1556 const bt_field_class *ir_fc)
1557 {
1558 int ret = 0;
1559
1560 if (!ir_fc) {
1561 goto end;
1562 }
1563
1564 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
1565 BT_FIELD_CLASS_TYPE_STRUCTURE);
1566 BT_ASSERT(fc);
1567 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
1568 ir_fc, UINT64_C(-1));
1569 BT_ASSERT(*fc);
1570 ctx->cur_scope = scope;
1571 BT_ASSERT(ctx->cur_path->len == 0);
1572 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
1573 if (ret) {
1574 BT_COMP_LOGE("Cannot translate scope structure field class: "
1575 "scope=%d", scope);
1576 goto end;
1577 }
1578
1579 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
1580 if (ret) {
1581 BT_COMP_LOGE("Cannot translate scope structure field class: "
1582 "scope=%d", scope);
1583 goto end;
1584 }
1585
1586 cur_path_stack_pop(ctx);
1587
1588 /* Set field refs for preceding targets */
1589 ret = set_field_refs(*fc, NULL, NULL);
1590
1591 end:
1592 return ret;
1593 }
1594
1595 static inline
1596 void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
1597 {
1598 memset(ctx, 0, sizeof(struct ctx));
1599 ctx->cur_path = g_array_new(FALSE, TRUE,
1600 sizeof(struct field_path_elem));
1601 BT_ASSERT(ctx->cur_path);
1602 ctx->log_level = fs_sink->log_level;
1603 ctx->self_comp = fs_sink->self_comp;
1604 }
1605
1606 static inline
1607 void ctx_fini(struct ctx *ctx)
1608 {
1609 if (ctx->cur_path) {
1610 g_array_free(ctx->cur_path, TRUE);
1611 ctx->cur_path = NULL;
1612 }
1613 }
1614
1615 static
1616 int translate_event_class(struct fs_sink_comp *fs_sink,
1617 struct fs_sink_ctf_stream_class *sc,
1618 const bt_event_class *ir_ec,
1619 struct fs_sink_ctf_event_class **out_ec)
1620 {
1621 int ret = 0;
1622 struct ctx ctx;
1623 struct fs_sink_ctf_event_class *ec;
1624
1625 BT_ASSERT(sc);
1626 BT_ASSERT(ir_ec);
1627
1628 ctx_init(&ctx, fs_sink);
1629 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1630 BT_ASSERT(ec);
1631 ctx.cur_sc = sc;
1632 ctx.cur_ec = ec;
1633 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
1634 &ec->spec_context_fc,
1635 bt_event_class_borrow_specific_context_field_class_const(
1636 ir_ec));
1637 if (ret) {
1638 goto end;
1639 }
1640
1641 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_PAYLOAD,
1642 &ec->payload_fc,
1643 bt_event_class_borrow_payload_field_class_const(ir_ec));
1644 if (ret) {
1645 goto end;
1646 }
1647
1648 end:
1649 ctx_fini(&ctx);
1650 *out_ec = ec;
1651 return ret;
1652 }
1653
1654 BT_HIDDEN
1655 int try_translate_event_class_trace_ir_to_ctf_ir(
1656 struct fs_sink_comp *fs_sink,
1657 struct fs_sink_ctf_stream_class *sc,
1658 const bt_event_class *ir_ec,
1659 struct fs_sink_ctf_event_class **out_ec)
1660 {
1661 int ret = 0;
1662
1663 BT_ASSERT(sc);
1664 BT_ASSERT(ir_ec);
1665
1666 /* Check in hash table first */
1667 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
1668 if (G_LIKELY(*out_ec)) {
1669 goto end;
1670 }
1671
1672 ret = translate_event_class(fs_sink, sc, ir_ec, out_ec);
1673
1674 end:
1675 return ret;
1676 }
1677
1678 bool default_clock_class_name_exists(struct fs_sink_ctf_trace *trace,
1679 const char *name)
1680 {
1681 bool exists = false;
1682 uint64_t i;
1683
1684 for (i = 0; i < trace->stream_classes->len; i++) {
1685 struct fs_sink_ctf_stream_class *sc =
1686 trace->stream_classes->pdata[i];
1687
1688 if (sc->default_clock_class_name->len == 0) {
1689 /* No default clock class */
1690 continue;
1691 }
1692
1693 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1694 exists = true;
1695 goto end;
1696 }
1697 }
1698
1699 end:
1700 return exists;
1701 }
1702
1703 static
1704 void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1705 {
1706 unsigned int suffix = 0;
1707 char buf[16];
1708
1709 g_string_assign(sc->default_clock_class_name, "");
1710 sprintf(buf, "default");
1711
1712 while (default_clock_class_name_exists(sc->trace, buf)) {
1713 sprintf(buf, "default%u", suffix);
1714 suffix++;
1715 }
1716
1717 g_string_assign(sc->default_clock_class_name, buf);
1718 }
1719
1720 static
1721 int translate_stream_class(struct fs_sink_comp *fs_sink,
1722 struct fs_sink_ctf_trace *trace,
1723 const bt_stream_class *ir_sc,
1724 struct fs_sink_ctf_stream_class **out_sc)
1725 {
1726 int ret = 0;
1727 struct ctx ctx;
1728
1729 BT_ASSERT(trace);
1730 BT_ASSERT(ir_sc);
1731 ctx_init(&ctx, fs_sink);
1732 *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
1733 BT_ASSERT(*out_sc);
1734
1735 /* Set default clock class's protected name, if any */
1736 if ((*out_sc)->default_clock_class) {
1737 const char *name = bt_clock_class_get_name(
1738 (*out_sc)->default_clock_class);
1739
1740 if (name) {
1741 /* Try original name, protected */
1742 g_string_assign((*out_sc)->default_clock_class_name,
1743 "");
1744
1745 if (must_protect_identifier(name)) {
1746 g_string_assign(
1747 (*out_sc)->default_clock_class_name,
1748 "_");
1749 }
1750
1751 g_string_assign((*out_sc)->default_clock_class_name,
1752 name);
1753 if (!ist_valid_identifier(
1754 (*out_sc)->default_clock_class_name->str)) {
1755 /* Invalid: create a new name */
1756 make_unique_default_clock_class_name(*out_sc);
1757 ret = 0;
1758 }
1759 } else {
1760 /* No name: create a name */
1761 make_unique_default_clock_class_name(*out_sc);
1762 }
1763 }
1764
1765 ctx.cur_sc = *out_sc;
1766 ret = translate_scope_field_class(&ctx, BT_SCOPE_PACKET_CONTEXT,
1767 &(*out_sc)->packet_context_fc,
1768 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1769 if (ret) {
1770 goto error;
1771 }
1772
1773 if ((*out_sc)->packet_context_fc) {
1774 /*
1775 * Make sure the structure field class's alignment is
1776 * enough: 8 is what we use for our own special members
1777 * in the packet context.
1778 */
1779 fs_sink_ctf_field_class_struct_align_at_least(
1780 (void *) (*out_sc)->packet_context_fc, 8);
1781 }
1782
1783 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_COMMON_CONTEXT,
1784 &(*out_sc)->event_common_context_fc,
1785 bt_stream_class_borrow_event_common_context_field_class_const(
1786 ir_sc));
1787 if (ret) {
1788 goto error;
1789 }
1790
1791 goto end;
1792
1793 error:
1794 fs_sink_ctf_stream_class_destroy(*out_sc);
1795 *out_sc = NULL;
1796
1797 end:
1798 ctx_fini(&ctx);
1799 return ret;
1800 }
1801
1802 BT_HIDDEN
1803 int try_translate_stream_class_trace_ir_to_ctf_ir(
1804 struct fs_sink_comp *fs_sink,
1805 struct fs_sink_ctf_trace *trace,
1806 const bt_stream_class *ir_sc,
1807 struct fs_sink_ctf_stream_class **out_sc)
1808 {
1809 int ret = 0;
1810 uint64_t i;
1811
1812 BT_ASSERT(trace);
1813 BT_ASSERT(ir_sc);
1814
1815 for (i = 0; i < trace->stream_classes->len; i++) {
1816 *out_sc = trace->stream_classes->pdata[i];
1817
1818 if ((*out_sc)->ir_sc == ir_sc) {
1819 goto end;
1820 }
1821 }
1822
1823 ret = translate_stream_class(fs_sink, trace, ir_sc, out_sc);
1824
1825 end:
1826 return ret;
1827 }
1828
1829 BT_HIDDEN
1830 struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(
1831 struct fs_sink_comp *fs_sink, const bt_trace *ir_trace)
1832 {
1833 uint64_t count;
1834 uint64_t i;
1835 struct fs_sink_ctf_trace *trace = NULL;
1836
1837 /* Check that trace's environment is TSDL-compatible */
1838 count = bt_trace_get_environment_entry_count(ir_trace);
1839 for (i = 0; i < count; i++) {
1840 const char *name;
1841 const bt_value *val;
1842
1843 bt_trace_borrow_environment_entry_by_index_const(
1844 ir_trace, i, &name, &val);
1845
1846 if (!ist_valid_identifier(name)) {
1847 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1848 fs_sink->self_comp,
1849 "Unsupported trace class's environment entry name: "
1850 "name=\"%s\"", name);
1851 goto end;
1852 }
1853
1854 switch (bt_value_get_type(val)) {
1855 case BT_VALUE_TYPE_SIGNED_INTEGER:
1856 case BT_VALUE_TYPE_STRING:
1857 break;
1858 default:
1859 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1860 fs_sink->self_comp,
1861 "Unsupported trace class's environment entry value type: "
1862 "type=%s",
1863 bt_common_value_type_string(
1864 bt_value_get_type(val)));
1865 goto end;
1866 }
1867 }
1868
1869 trace = fs_sink_ctf_trace_create(ir_trace);
1870 BT_ASSERT(trace);
1871
1872 end:
1873 return trace;
1874 }
This page took 0.106761 seconds and 4 git commands to generate.