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