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