sink.ctf.fs: write boolean field classes and fields
[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 protects a given variant FC option name (with the `_`
713 * prefix) if required. On success, `name_buf->str` contains the variant
714 * FC option name to use (original option name or protected if
715 * required).
716 *
717 * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
718 * close as possible to an original CTF trace as decoded by
719 * `src.ctf.fs`.
720 *
721 * This scenario is valid in CTF 1.8:
722 *
723 * enum {
724 * HELLO,
725 * MEOW
726 * } tag;
727 *
728 * variant <tag> {
729 * int HELLO;
730 * string MEOW;
731 * };
732 *
733 * Once in trace IR, the enumeration FC mapping names and variant FC
734 * option names are kept as is. For this reason, we don't want to
735 * protect the variant FC option names here (by prepending `_`): this
736 * would make the variant FC option name and the enumeration FC mapping
737 * name not match.
738 *
739 * This scenario is also valid in CTF 1.8:
740 *
741 * enum {
742 * _HELLO,
743 * MEOW
744 * } tag;
745 *
746 * variant <tag> {
747 * int _HELLO;
748 * string MEOW;
749 * };
750 *
751 * Once in trace IR, the enumeration FC mapping names are kept as is,
752 * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
753 * for presentation, as recommended by CTF 1.8). When going back to
754 * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
755 * the corresponding enumeration FC mapping name.
756 *
757 * This scenario is also valid in CTF 1.8:
758 *
759 * enum {
760 * __HELLO,
761 * MEOW
762 * } tag;
763 *
764 * variant <tag> {
765 * int __HELLO;
766 * string MEOW;
767 * };
768 *
769 * Once in trace IR, the enumeration FC mapping names are kept as is,
770 * but the `__HELLO` variant FC option name becomes `_HELLO`
771 * (unprotected). When going back to TSDL, we need to protect `_HELLO`
772 * so that it becomes `__HELLO` to match the corresponding enumeration
773 * FC mapping name.
774 *
775 * `src.ctf.fs` always uses the _same_ integer range sets for a selector
776 * FC mapping and a corresponding variant FC option. We can use that
777 * fact to find the original variant FC option names by matching variant
778 * FC options and enumeration FC mappings by range set.
779 */
780 static
781 int maybe_protect_variant_option_name(const bt_field_class *ir_var_fc,
782 const bt_field_class *ir_tag_fc, uint64_t opt_i,
783 GString *name_buf)
784 {
785 int ret = 0;
786 uint64_t i;
787 bt_field_class_type ir_var_fc_type;
788 const void *opt_ranges = NULL;
789 const char *mapping_label = NULL;
790 const char *ir_opt_name;
791 const bt_field_class_variant_option *base_var_opt;
792 bool force_protect = false;
793
794 ir_var_fc_type = bt_field_class_get_type(ir_var_fc);
795 base_var_opt = bt_field_class_variant_borrow_option_by_index_const(
796 ir_var_fc, opt_i);
797 BT_ASSERT(base_var_opt);
798 ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt);
799 BT_ASSERT(ir_opt_name);
800
801 /*
802 * Check if the variant FC option name is required to be
803 * protected (reserved TSDL keyword or starts with `_`). In that
804 * case, the name of the selector FC mapping we find must match
805 * exactly the protected name.
806 */
807 force_protect = must_protect_identifier(ir_opt_name);
808 if (force_protect) {
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 end:
915 return ret;
916 }
917
918 static inline
919 int translate_variant_field_class(struct ctx *ctx)
920 {
921 int ret = 0;
922 uint64_t i;
923 struct fs_sink_ctf_field_class_variant *fc =
924 fs_sink_ctf_field_class_variant_create_empty(
925 cur_path_stack_top(ctx)->ir_fc,
926 cur_path_stack_top(ctx)->index_in_parent);
927 bt_field_class_type ir_fc_type;
928 const bt_field_path *ir_selector_field_path = NULL;
929 struct fs_sink_ctf_field_class *tgt_fc = NULL;
930 GString *name_buf = g_string_new(NULL);
931 bt_value *prot_opt_names = bt_value_array_create();
932 uint64_t opt_count;
933
934 BT_ASSERT(fc);
935 BT_ASSERT(name_buf);
936 BT_ASSERT(prot_opt_names);
937 ir_fc_type = bt_field_class_get_type(fc->base.ir_fc);
938 opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc);
939
940 if (ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR ||
941 ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) {
942 ir_selector_field_path = bt_field_class_variant_with_selector_borrow_selector_field_path_const(
943 fc->base.ir_fc);
944 BT_ASSERT(ir_selector_field_path);
945 }
946
947 /* Resolve tag field class before appending to parent */
948 resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref,
949 &fc->tag_is_before, &tgt_fc);
950
951 if (ir_selector_field_path && tgt_fc) {
952 uint64_t mapping_count;
953 uint64_t option_count;
954
955 /* CTF 1.8: selector FC must be an enumeration FC */
956 bt_field_class_type type = bt_field_class_get_type(
957 tgt_fc->ir_fc);
958
959 if (type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION &&
960 type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
961 fc->tag_is_before = true;
962 goto validate_opts;
963 }
964
965 /*
966 * Call maybe_protect_variant_option_name() for each
967 * option below. In that case we also want selector FC
968 * to contain as many mappings as the variant FC has
969 * options.
970 */
971 mapping_count = bt_field_class_enumeration_get_mapping_count(
972 tgt_fc->ir_fc);
973 option_count = bt_field_class_variant_get_option_count(
974 fc->base.ir_fc);
975
976 if (mapping_count != option_count) {
977 fc->tag_is_before = true;
978 goto validate_opts;
979 }
980 } else {
981 /*
982 * No compatible selector field class for CTF 1.8:
983 * create the appropriate selector field class.
984 */
985 fc->tag_is_before = true;
986 goto validate_opts;
987 }
988
989 validate_opts:
990 /*
991 * First pass: detect any option name clash with option name
992 * protection. In that case, we don't fail: just create the
993 * selector field class before the variant field class.
994 *
995 * After this, `prot_opt_names` contains the final option names,
996 * potentially protected if needed. They can still be invalid
997 * TSDL identifiers however; this will be checked by
998 * cur_path_stack_push().
999 */
1000 for (i = 0; i < opt_count; i++) {
1001 if (!fc->tag_is_before) {
1002 BT_ASSERT(tgt_fc->ir_fc);
1003 ret = maybe_protect_variant_option_name(fc->base.ir_fc,
1004 tgt_fc->ir_fc, i, name_buf);
1005 if (ret) {
1006 fc->tag_is_before = true;
1007 }
1008 }
1009
1010 ret = bt_value_array_append_string_element(prot_opt_names,
1011 name_buf->str);
1012 if (ret) {
1013 goto end;
1014 }
1015 }
1016
1017 for (i = 0; i < opt_count; i++) {
1018 uint64_t j;
1019 const bt_value *opt_name_a =
1020 bt_value_array_borrow_element_by_index_const(
1021 prot_opt_names, i);
1022
1023 for (j = 0; j < opt_count; j++) {
1024 const bt_value *opt_name_b;
1025
1026 if (i == j) {
1027 continue;
1028 }
1029
1030 opt_name_b =
1031 bt_value_array_borrow_element_by_index_const(
1032 prot_opt_names, j);
1033 if (bt_value_compare(opt_name_a, opt_name_b)) {
1034 /*
1035 * Variant FC option names are not
1036 * unique when protected.
1037 */
1038 fc->tag_is_before = true;
1039 goto append_to_parent;
1040 }
1041 }
1042 }
1043
1044 append_to_parent:
1045 append_to_parent_field_class(ctx, (void *) fc);
1046
1047 for (i = 0; i < opt_count; i++) {
1048 const bt_field_class_variant_option *opt;
1049 const bt_field_class *opt_ir_fc;
1050 const bt_value *prot_opt_name_val =
1051 bt_value_array_borrow_element_by_index_const(
1052 prot_opt_names, i);
1053 const char *prot_opt_name = bt_value_string_get(
1054 prot_opt_name_val);
1055
1056 BT_ASSERT(prot_opt_name);
1057 opt = bt_field_class_variant_borrow_option_by_index_const(
1058 fc->base.ir_fc, i);
1059 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
1060 opt);
1061
1062 /*
1063 * We don't ask cur_path_stack_push() to protect the
1064 * option name because it's already protected at this
1065 * point.
1066 */
1067 ret = cur_path_stack_push(ctx, i, prot_opt_name, false,
1068 opt_ir_fc, (void *) fc);
1069 if (ret) {
1070 BT_COMP_LOGE("Cannot translate variant field class option: "
1071 "name=\"%s\"", prot_opt_name);
1072 goto end;
1073 }
1074
1075 ret = translate_field_class(ctx);
1076 if (ret) {
1077 BT_COMP_LOGE("Cannot translate variant field class option: "
1078 "name=\"%s\"", prot_opt_name);
1079 goto end;
1080 }
1081
1082 cur_path_stack_pop(ctx);
1083 }
1084
1085 end:
1086 if (name_buf) {
1087 g_string_free(name_buf, TRUE);
1088 }
1089
1090 bt_value_put_ref(prot_opt_names);
1091 return ret;
1092 }
1093
1094 static inline
1095 int translate_static_array_field_class(struct ctx *ctx)
1096 {
1097 struct fs_sink_ctf_field_class_array *fc =
1098 fs_sink_ctf_field_class_array_create_empty(
1099 cur_path_stack_top(ctx)->ir_fc,
1100 cur_path_stack_top(ctx)->index_in_parent);
1101 const bt_field_class *elem_ir_fc =
1102 bt_field_class_array_borrow_element_field_class_const(
1103 fc->base.base.ir_fc);
1104 int ret;
1105
1106 BT_ASSERT(fc);
1107 append_to_parent_field_class(ctx, (void *) fc);
1108 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
1109 (void *) fc);
1110 if (ret) {
1111 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
1112 goto end;
1113 }
1114
1115 ret = translate_field_class(ctx);
1116 if (ret) {
1117 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
1118 goto end;
1119 }
1120
1121 cur_path_stack_pop(ctx);
1122 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1123
1124 end:
1125 return ret;
1126 }
1127
1128 static inline
1129 int translate_dynamic_array_field_class(struct ctx *ctx)
1130 {
1131 struct fs_sink_ctf_field_class_sequence *fc =
1132 fs_sink_ctf_field_class_sequence_create_empty(
1133 cur_path_stack_top(ctx)->ir_fc,
1134 cur_path_stack_top(ctx)->index_in_parent);
1135 const bt_field_class *elem_ir_fc =
1136 bt_field_class_array_borrow_element_field_class_const(
1137 fc->base.base.ir_fc);
1138 int ret;
1139
1140 BT_ASSERT(fc);
1141
1142 /* Resolve length field class before appending to parent */
1143 resolve_field_class(ctx,
1144 bt_field_class_array_dynamic_borrow_length_field_path_const(
1145 fc->base.base.ir_fc),
1146 fc->length_ref, &fc->length_is_before, NULL);
1147
1148 append_to_parent_field_class(ctx, (void *) fc);
1149 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
1150 (void *) fc);
1151 if (ret) {
1152 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
1153 goto end;
1154 }
1155
1156 ret = translate_field_class(ctx);
1157 if (ret) {
1158 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
1159 goto end;
1160 }
1161
1162 cur_path_stack_pop(ctx);
1163 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1164
1165 end:
1166 return ret;
1167 }
1168
1169 static inline
1170 int translate_bool_field_class(struct ctx *ctx)
1171 {
1172 struct fs_sink_ctf_field_class_bool *fc =
1173 fs_sink_ctf_field_class_bool_create(
1174 cur_path_stack_top(ctx)->ir_fc,
1175 cur_path_stack_top(ctx)->index_in_parent);
1176
1177 BT_ASSERT(fc);
1178 append_to_parent_field_class(ctx, (void *) fc);
1179 return 0;
1180 }
1181
1182 static inline
1183 int translate_integer_field_class(struct ctx *ctx)
1184 {
1185 struct fs_sink_ctf_field_class_int *fc =
1186 fs_sink_ctf_field_class_int_create(
1187 cur_path_stack_top(ctx)->ir_fc,
1188 cur_path_stack_top(ctx)->index_in_parent);
1189
1190 BT_ASSERT(fc);
1191 append_to_parent_field_class(ctx, (void *) fc);
1192 return 0;
1193 }
1194
1195 static inline
1196 int translate_real_field_class(struct ctx *ctx)
1197 {
1198 struct fs_sink_ctf_field_class_float *fc =
1199 fs_sink_ctf_field_class_float_create(
1200 cur_path_stack_top(ctx)->ir_fc,
1201 cur_path_stack_top(ctx)->index_in_parent);
1202
1203 BT_ASSERT(fc);
1204 append_to_parent_field_class(ctx, (void *) fc);
1205 return 0;
1206 }
1207
1208 static inline
1209 int translate_string_field_class(struct ctx *ctx)
1210 {
1211 struct fs_sink_ctf_field_class_string *fc =
1212 fs_sink_ctf_field_class_string_create(
1213 cur_path_stack_top(ctx)->ir_fc,
1214 cur_path_stack_top(ctx)->index_in_parent);
1215
1216 BT_ASSERT(fc);
1217 append_to_parent_field_class(ctx, (void *) fc);
1218 return 0;
1219 }
1220
1221 /*
1222 * Translates a field class, recursively.
1223 *
1224 * The field class's IR field class, parent field class, and index
1225 * within its parent are in the context's current path's top element
1226 * (cur_path_stack_top()).
1227 */
1228 static
1229 int translate_field_class(struct ctx *ctx)
1230 {
1231 int ret;
1232
1233 switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
1234 case BT_FIELD_CLASS_TYPE_BOOL:
1235 ret = translate_bool_field_class(ctx);
1236 break;
1237 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
1238 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
1239 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1240 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1241 ret = translate_integer_field_class(ctx);
1242 break;
1243 case BT_FIELD_CLASS_TYPE_REAL:
1244 ret = translate_real_field_class(ctx);
1245 break;
1246 case BT_FIELD_CLASS_TYPE_STRING:
1247 ret = translate_string_field_class(ctx);
1248 break;
1249 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1250 ret = translate_structure_field_class(ctx);
1251 break;
1252 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1253 ret = translate_static_array_field_class(ctx);
1254 break;
1255 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1256 ret = translate_dynamic_array_field_class(ctx);
1257 break;
1258 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
1259 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
1260 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
1261 ret = translate_variant_field_class(ctx);
1262 break;
1263 default:
1264 abort();
1265 }
1266
1267 return ret;
1268 }
1269
1270 static
1271 int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
1272 struct fs_sink_ctf_field_class *parent_fc)
1273 {
1274 int ret = 0;
1275 GString *field_ref = NULL;
1276 bool is_before;
1277 const char *tgt_type;
1278 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
1279 (void *) parent_fc;
1280 uint64_t i;
1281 unsigned int suffix = 0;
1282
1283 if (!fc_name || !parent_fc ||
1284 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1285 /* Not supported */
1286 ret = -1;
1287 goto end;
1288 }
1289
1290 switch (fc->type) {
1291 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1292 {
1293 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
1294
1295 field_ref = seq_fc->length_ref;
1296 is_before = seq_fc->length_is_before;
1297 tgt_type = "len";
1298 break;
1299 }
1300 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1301 {
1302 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
1303
1304 field_ref = var_fc->tag_ref;
1305 is_before = var_fc->tag_is_before;
1306 tgt_type = "tag";
1307 break;
1308 }
1309 default:
1310 abort();
1311 }
1312
1313 BT_ASSERT(field_ref);
1314
1315 if (!is_before) {
1316 goto end;
1317 }
1318
1319 /* Initial field ref */
1320 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
1321
1322 /*
1323 * Make sure field ref does not clash with an existing field
1324 * class name within the same parent structure field class.
1325 */
1326 while (true) {
1327 bool name_ok = true;
1328
1329 for (i = 0; i < parent_struct_fc->members->len; i++) {
1330 struct fs_sink_ctf_named_field_class *named_fc =
1331 fs_sink_ctf_field_class_struct_borrow_member_by_index(
1332 parent_struct_fc, i);
1333
1334 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
1335 /* Name clash */
1336 name_ok = false;
1337 break;
1338 }
1339 }
1340
1341 if (name_ok) {
1342 /* No clash: we're done */
1343 break;
1344 }
1345
1346 /* Append suffix and try again */
1347 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
1348 suffix);
1349 suffix++;
1350 }
1351
1352 end:
1353 return ret;
1354 }
1355
1356 /*
1357 * This function recursively sets field refs of sequence and variant
1358 * field classes when they are immediately before, avoiding name clashes
1359 * with existing field class names.
1360 *
1361 * It can fail at this point if, for example, a sequence field class of
1362 * which to set the length's field ref has something else than a
1363 * structure field class as its parent: in this case, there's no
1364 * location to place the length field class immediately before the
1365 * sequence field class.
1366 */
1367 static
1368 int set_field_refs(struct fs_sink_ctf_field_class * const fc,
1369 const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
1370 {
1371 int ret = 0;
1372 enum fs_sink_ctf_field_class_type fc_type;
1373 BT_ASSERT(fc);
1374
1375 fc_type = fc->type;
1376
1377 switch (fc_type) {
1378 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1379 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1380 {
1381 uint64_t i;
1382 uint64_t len;
1383 struct fs_sink_ctf_field_class_struct *struct_fc;
1384 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
1385 struct fs_sink_ctf_named_field_class *named_fc;
1386
1387 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1388 struct_fc = (void *) fc;
1389 len = struct_fc->members->len;
1390 } else {
1391 var_fc = (void *) fc;
1392 len = var_fc->options->len;
1393 ret = set_field_ref(fc, fc_name, parent_fc);
1394 if (ret) {
1395 goto end;
1396 }
1397 }
1398
1399 for (i = 0; i < len; i++) {
1400 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1401 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1402 struct_fc, i);
1403 } else {
1404 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1405 var_fc, i);
1406 }
1407
1408 ret = set_field_refs(named_fc->fc, named_fc->name->str,
1409 fc);
1410 if (ret) {
1411 goto end;
1412 }
1413 }
1414
1415 break;
1416 }
1417 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
1418 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1419 {
1420 struct fs_sink_ctf_field_class_array_base *array_base_fc =
1421 (void *) fc;
1422
1423 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
1424 ret = set_field_ref(fc, fc_name, parent_fc);
1425 if (ret) {
1426 goto end;
1427 }
1428 }
1429
1430 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
1431 if (ret) {
1432 goto end;
1433 }
1434
1435 break;
1436 }
1437 default:
1438 break;
1439 }
1440
1441 end:
1442 return ret;
1443 }
1444
1445 /*
1446 * This function translates a root scope trace IR field class to
1447 * a CTF IR field class.
1448 *
1449 * The resulting CTF IR field class is written to `*fc` so that it
1450 * exists as the parent object's (stream class or event class) true root
1451 * field class during the recursive translation for resolving purposes.
1452 * This is also why this function creates the empty structure field
1453 * class and then calls translate_structure_field_class_members() to
1454 * fill it.
1455 */
1456 static
1457 int translate_scope_field_class(struct ctx *ctx, bt_field_path_scope scope,
1458 struct fs_sink_ctf_field_class **fc,
1459 const bt_field_class *ir_fc)
1460 {
1461 int ret = 0;
1462
1463 if (!ir_fc) {
1464 goto end;
1465 }
1466
1467 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
1468 BT_FIELD_CLASS_TYPE_STRUCTURE);
1469 BT_ASSERT(fc);
1470 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
1471 ir_fc, UINT64_C(-1));
1472 BT_ASSERT(*fc);
1473 ctx->cur_scope = scope;
1474 BT_ASSERT(ctx->cur_path->len == 0);
1475 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
1476 if (ret) {
1477 BT_COMP_LOGE("Cannot translate scope structure field class: "
1478 "scope=%d", scope);
1479 goto end;
1480 }
1481
1482 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
1483 if (ret) {
1484 BT_COMP_LOGE("Cannot translate scope structure field class: "
1485 "scope=%d", scope);
1486 goto end;
1487 }
1488
1489 cur_path_stack_pop(ctx);
1490
1491 /* Set field refs for preceding targets */
1492 ret = set_field_refs(*fc, NULL, NULL);
1493
1494 end:
1495 return ret;
1496 }
1497
1498 static inline
1499 void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
1500 {
1501 memset(ctx, 0, sizeof(struct ctx));
1502 ctx->cur_path = g_array_new(FALSE, TRUE,
1503 sizeof(struct field_path_elem));
1504 BT_ASSERT(ctx->cur_path);
1505 ctx->log_level = fs_sink->log_level;
1506 ctx->self_comp = fs_sink->self_comp;
1507 }
1508
1509 static inline
1510 void ctx_fini(struct ctx *ctx)
1511 {
1512 if (ctx->cur_path) {
1513 g_array_free(ctx->cur_path, TRUE);
1514 ctx->cur_path = NULL;
1515 }
1516 }
1517
1518 static
1519 int translate_event_class(struct fs_sink_comp *fs_sink,
1520 struct fs_sink_ctf_stream_class *sc,
1521 const bt_event_class *ir_ec,
1522 struct fs_sink_ctf_event_class **out_ec)
1523 {
1524 int ret = 0;
1525 struct ctx ctx;
1526 struct fs_sink_ctf_event_class *ec;
1527
1528 BT_ASSERT(sc);
1529 BT_ASSERT(ir_ec);
1530
1531 ctx_init(&ctx, fs_sink);
1532 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1533 BT_ASSERT(ec);
1534 ctx.cur_sc = sc;
1535 ctx.cur_ec = ec;
1536 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT,
1537 &ec->spec_context_fc,
1538 bt_event_class_borrow_specific_context_field_class_const(
1539 ir_ec));
1540 if (ret) {
1541 goto end;
1542 }
1543
1544 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD,
1545 &ec->payload_fc,
1546 bt_event_class_borrow_payload_field_class_const(ir_ec));
1547 if (ret) {
1548 goto end;
1549 }
1550
1551 end:
1552 ctx_fini(&ctx);
1553 *out_ec = ec;
1554 return ret;
1555 }
1556
1557 BT_HIDDEN
1558 int try_translate_event_class_trace_ir_to_ctf_ir(
1559 struct fs_sink_comp *fs_sink,
1560 struct fs_sink_ctf_stream_class *sc,
1561 const bt_event_class *ir_ec,
1562 struct fs_sink_ctf_event_class **out_ec)
1563 {
1564 int ret = 0;
1565
1566 BT_ASSERT(sc);
1567 BT_ASSERT(ir_ec);
1568
1569 /* Check in hash table first */
1570 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
1571 if (G_LIKELY(*out_ec)) {
1572 goto end;
1573 }
1574
1575 ret = translate_event_class(fs_sink, sc, ir_ec, out_ec);
1576
1577 end:
1578 return ret;
1579 }
1580
1581 bool default_clock_class_name_exists(struct fs_sink_ctf_trace *trace,
1582 const char *name)
1583 {
1584 bool exists = false;
1585 uint64_t i;
1586
1587 for (i = 0; i < trace->stream_classes->len; i++) {
1588 struct fs_sink_ctf_stream_class *sc =
1589 trace->stream_classes->pdata[i];
1590
1591 if (sc->default_clock_class_name->len == 0) {
1592 /* No default clock class */
1593 continue;
1594 }
1595
1596 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1597 exists = true;
1598 goto end;
1599 }
1600 }
1601
1602 end:
1603 return exists;
1604 }
1605
1606 static
1607 void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1608 {
1609 unsigned int suffix = 0;
1610 char buf[16];
1611
1612 g_string_assign(sc->default_clock_class_name, "");
1613 sprintf(buf, "default");
1614
1615 while (default_clock_class_name_exists(sc->trace, buf)) {
1616 sprintf(buf, "default%u", suffix);
1617 suffix++;
1618 }
1619
1620 g_string_assign(sc->default_clock_class_name, buf);
1621 }
1622
1623 static
1624 int translate_stream_class(struct fs_sink_comp *fs_sink,
1625 struct fs_sink_ctf_trace *trace,
1626 const bt_stream_class *ir_sc,
1627 struct fs_sink_ctf_stream_class **out_sc)
1628 {
1629 int ret = 0;
1630 struct ctx ctx;
1631
1632 BT_ASSERT(trace);
1633 BT_ASSERT(ir_sc);
1634 ctx_init(&ctx, fs_sink);
1635 *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
1636 BT_ASSERT(*out_sc);
1637
1638 /* Set default clock class's protected name, if any */
1639 if ((*out_sc)->default_clock_class) {
1640 const char *name = bt_clock_class_get_name(
1641 (*out_sc)->default_clock_class);
1642
1643 if (name) {
1644 /* Try original name, protected */
1645 g_string_assign((*out_sc)->default_clock_class_name,
1646 "");
1647
1648 if (must_protect_identifier(name)) {
1649 g_string_assign(
1650 (*out_sc)->default_clock_class_name,
1651 "_");
1652 }
1653
1654 g_string_assign((*out_sc)->default_clock_class_name,
1655 name);
1656 if (!ist_valid_identifier(
1657 (*out_sc)->default_clock_class_name->str)) {
1658 /* Invalid: create a new name */
1659 make_unique_default_clock_class_name(*out_sc);
1660 ret = 0;
1661 }
1662 } else {
1663 /* No name: create a name */
1664 make_unique_default_clock_class_name(*out_sc);
1665 }
1666 }
1667
1668 ctx.cur_sc = *out_sc;
1669 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT,
1670 &(*out_sc)->packet_context_fc,
1671 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1672 if (ret) {
1673 goto error;
1674 }
1675
1676 if ((*out_sc)->packet_context_fc) {
1677 /*
1678 * Make sure the structure field class's alignment is
1679 * enough: 8 is what we use for our own special members
1680 * in the packet context.
1681 */
1682 fs_sink_ctf_field_class_struct_align_at_least(
1683 (void *) (*out_sc)->packet_context_fc, 8);
1684 }
1685
1686 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT,
1687 &(*out_sc)->event_common_context_fc,
1688 bt_stream_class_borrow_event_common_context_field_class_const(
1689 ir_sc));
1690 if (ret) {
1691 goto error;
1692 }
1693
1694 goto end;
1695
1696 error:
1697 fs_sink_ctf_stream_class_destroy(*out_sc);
1698 *out_sc = NULL;
1699
1700 end:
1701 ctx_fini(&ctx);
1702 return ret;
1703 }
1704
1705 BT_HIDDEN
1706 int try_translate_stream_class_trace_ir_to_ctf_ir(
1707 struct fs_sink_comp *fs_sink,
1708 struct fs_sink_ctf_trace *trace,
1709 const bt_stream_class *ir_sc,
1710 struct fs_sink_ctf_stream_class **out_sc)
1711 {
1712 int ret = 0;
1713 uint64_t i;
1714
1715 BT_ASSERT(trace);
1716 BT_ASSERT(ir_sc);
1717
1718 for (i = 0; i < trace->stream_classes->len; i++) {
1719 *out_sc = trace->stream_classes->pdata[i];
1720
1721 if ((*out_sc)->ir_sc == ir_sc) {
1722 goto end;
1723 }
1724 }
1725
1726 ret = translate_stream_class(fs_sink, trace, ir_sc, out_sc);
1727
1728 end:
1729 return ret;
1730 }
1731
1732 BT_HIDDEN
1733 struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(
1734 struct fs_sink_comp *fs_sink, const bt_trace *ir_trace)
1735 {
1736 uint64_t count;
1737 uint64_t i;
1738 struct fs_sink_ctf_trace *trace = NULL;
1739
1740 /* Check that trace's environment is TSDL-compatible */
1741 count = bt_trace_get_environment_entry_count(ir_trace);
1742 for (i = 0; i < count; i++) {
1743 const char *name;
1744 const bt_value *val;
1745
1746 bt_trace_borrow_environment_entry_by_index_const(
1747 ir_trace, i, &name, &val);
1748
1749 if (!ist_valid_identifier(name)) {
1750 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1751 fs_sink->self_comp,
1752 "Unsupported trace class's environment entry name: "
1753 "name=\"%s\"", name);
1754 goto end;
1755 }
1756
1757 switch (bt_value_get_type(val)) {
1758 case BT_VALUE_TYPE_SIGNED_INTEGER:
1759 case BT_VALUE_TYPE_STRING:
1760 break;
1761 default:
1762 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1763 fs_sink->self_comp,
1764 "Unsupported trace class's environment entry value type: "
1765 "type=%s",
1766 bt_common_value_type_string(
1767 bt_value_get_type(val)));
1768 goto end;
1769 }
1770 }
1771
1772 trace = fs_sink_ctf_trace_create(ir_trace);
1773 BT_ASSERT(trace);
1774
1775 end:
1776 return trace;
1777 }
This page took 0.101078 seconds and 5 git commands to generate.