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