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