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