6e45bebc7ff72feed5ebf9af0f9d9c5d4a91e002
[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 if (bt_field_path_item_get_type(fp_item) ==
323 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT) {
324 /* Not supported by CTF 1.8 */
325 ret = -1;
326 goto end;
327 }
328
329 switch (tgt_fc->type) {
330 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
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_struct_borrow_member_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_VARIANT:
338 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
339 BT_FIELD_PATH_ITEM_TYPE_INDEX);
340 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
341 (void *) tgt_fc,
342 bt_field_path_item_index_get_index(fp_item));
343 break;
344 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
345 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
346 {
347 struct fs_sink_ctf_field_class_array_base *array_base_fc =
348 (void *) tgt_fc;
349
350 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
351 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
352 tgt_fc = array_base_fc->elem_fc;
353 break;
354 }
355 default:
356 abort();
357 }
358
359 if (named_fc) {
360 tgt_fc = named_fc->fc;
361 tgt_fc_name = named_fc->name->str;
362 i++;
363 }
364 }
365
366 BT_ASSERT(tgt_fc);
367 BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
368 BT_ASSERT(tgt_fc_name);
369
370 /* Find target field class having this name in current context */
371 for (si = ctx->cur_path->len - 1; si >= 0; si--) {
372 struct fs_sink_ctf_field_class *fc;
373 struct fs_sink_ctf_field_class_struct *struct_fc = NULL;
374 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
375 struct fs_sink_ctf_named_field_class *named_fc;
376 uint64_t len;
377
378 field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
379 fc = field_path_elem->parent_fc;
380 if (!fc) {
381 /* Reached stack's bottom */
382 ret = -1;
383 goto end;
384 }
385
386 switch (fc->type) {
387 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
388 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
389 break;
390 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
391 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
392 continue;
393 default:
394 /* Not supported by TSDL 1.8 */
395 ret = -1;
396 goto end;
397 }
398
399 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
400 struct_fc = (void *) fc;
401 len = struct_fc->members->len;
402 } else {
403 var_fc = (void *) fc;
404 len = var_fc->options->len;
405 }
406
407 for (i = 0; i < len; i++) {
408 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
409 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
410 struct_fc, i);
411 } else {
412 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
413 var_fc, i);
414 }
415
416 if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
417 if (named_fc->fc == tgt_fc) {
418 g_string_assign(tgt_field_ref,
419 tgt_fc_name);
420
421 if (user_tgt_fc) {
422 *user_tgt_fc = tgt_fc;
423 }
424 } else {
425 /*
426 * Using only the target field
427 * class's name, we're not
428 * reaching the target field
429 * class. This is not supported
430 * by TSDL 1.8.
431 */
432 ret = -1;
433 }
434
435 goto end;
436 }
437 }
438 }
439
440 end:
441 return ret;
442 }
443
444 /*
445 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
446 *
447 * Returns a negative value if this resolving operation failed.
448 */
449 static
450 int create_absolute_field_ref(struct ctx *ctx,
451 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
452 struct fs_sink_ctf_field_class **user_tgt_fc)
453 {
454 int ret = 0;
455 struct fs_sink_ctf_field_class *fc = NULL;
456 uint64_t i;
457
458 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
459 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
460 BT_ASSERT(ctx->cur_sc);
461 fc = ctx->cur_sc->packet_context_fc;
462 g_string_assign(tgt_field_ref, "stream.packet.context");
463 break;
464 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
465 BT_ASSERT(ctx->cur_sc);
466 fc = ctx->cur_sc->event_common_context_fc;
467 g_string_assign(tgt_field_ref, "stream.event.context");
468 break;
469 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
470 BT_ASSERT(ctx->cur_ec);
471 fc = ctx->cur_ec->spec_context_fc;
472 g_string_assign(tgt_field_ref, "event.context");
473 break;
474 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
475 BT_ASSERT(ctx->cur_ec);
476 fc = ctx->cur_ec->payload_fc;
477 g_string_assign(tgt_field_ref, "event.fields");
478 break;
479 default:
480 abort();
481 }
482
483 BT_ASSERT(fc);
484
485 for (i = 0; i < bt_field_path_get_item_count(tgt_ir_field_path); i++) {
486 const bt_field_path_item *fp_item =
487 bt_field_path_borrow_item_by_index_const(
488 tgt_ir_field_path, i);
489 struct fs_sink_ctf_named_field_class *named_fc = NULL;
490
491 if (bt_field_path_item_get_type(fp_item) !=
492 BT_FIELD_PATH_ITEM_TYPE_INDEX) {
493 /* Not supported by TSDL 1.8 */
494 ret = -1;
495 goto end;
496 }
497
498 switch (fc->type) {
499 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
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_struct_borrow_member_by_index(
503 (void *) fc,
504 bt_field_path_item_index_get_index(fp_item));
505 break;
506 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
507 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
508 BT_FIELD_PATH_ITEM_TYPE_INDEX);
509 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
510 (void *) fc,
511 bt_field_path_item_index_get_index(fp_item));
512 break;
513 default:
514 abort();
515 }
516
517 BT_ASSERT(named_fc);
518 g_string_append_c(tgt_field_ref, '.');
519 g_string_append(tgt_field_ref, named_fc->name->str);
520 fc = named_fc->fc;
521 }
522
523 if (user_tgt_fc) {
524 *user_tgt_fc = fc;
525 }
526
527 end:
528 return ret;
529 }
530
531 /*
532 * Resolves a target field class located at `tgt_ir_field_path`, writing
533 * the resolved field ref to `tgt_field_ref` and setting
534 * `*create_before` according to whether or not the target field must be
535 * created immediately before (in which case `tgt_field_ref` is
536 * irrelevant).
537 */
538 static
539 void resolve_field_class(struct ctx *ctx,
540 const bt_field_path *tgt_ir_field_path,
541 GString *tgt_field_ref, bool *create_before,
542 struct fs_sink_ctf_field_class **user_tgt_fc)
543 {
544 int ret;
545 bt_field_path_scope tgt_scope;
546
547 *create_before = false;
548
549 if (!tgt_ir_field_path) {
550 *create_before = true;
551 goto end;
552 }
553
554 tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
555
556 if (tgt_scope == ctx->cur_scope) {
557 /*
558 * Try, in this order:
559 *
560 * 1. Use a relative path, using only the target field
561 * class's name. This is what is the most commonly
562 * supported by popular CTF reading tools.
563 *
564 * 2. Use an absolute path. This could fail if there's
565 * an array field class from the current root's field
566 * class to the target field class.
567 *
568 * 3. Create the target field class before the
569 * requesting field class (fallback).
570 */
571 ret = create_relative_field_ref(ctx, tgt_ir_field_path,
572 tgt_field_ref, user_tgt_fc);
573 if (ret) {
574 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
575 tgt_field_ref, user_tgt_fc);
576 if (ret) {
577 *create_before = true;
578 ret = 0;
579 goto end;
580 }
581 }
582 } else {
583 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
584 tgt_field_ref, user_tgt_fc);
585
586 /* It must always work in previous scopes */
587 BT_ASSERT(ret == 0);
588 }
589
590 end:
591 return;
592 }
593
594 static
595 int translate_field_class(struct ctx *ctx);
596
597 static inline
598 void append_to_parent_field_class(struct ctx *ctx,
599 struct fs_sink_ctf_field_class *fc)
600 {
601 struct fs_sink_ctf_field_class *parent_fc =
602 cur_path_stack_top(ctx)->parent_fc;
603
604 switch (parent_fc->type) {
605 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
606 fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
607 cur_path_stack_top(ctx)->name->str, fc);
608 break;
609 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
610 {
611 struct fs_sink_ctf_field_class_option *opt_fc =
612 (void *) parent_fc;
613
614 BT_ASSERT(!opt_fc->content_fc);
615 opt_fc->content_fc = fc;
616 opt_fc->base.alignment = fc->alignment;
617 break;
618 }
619 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
620 fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
621 cur_path_stack_top(ctx)->name->str, fc);
622 break;
623 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
624 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
625 {
626 struct fs_sink_ctf_field_class_array_base *array_base_fc =
627 (void *) parent_fc;
628
629 BT_ASSERT(!array_base_fc->elem_fc);
630 array_base_fc->elem_fc = fc;
631 array_base_fc->base.alignment = fc->alignment;
632 break;
633 }
634 default:
635 abort();
636 }
637 }
638
639 static inline
640 void update_parent_field_class_alignment(struct ctx *ctx,
641 unsigned int alignment)
642 {
643 struct fs_sink_ctf_field_class *parent_fc =
644 cur_path_stack_top(ctx)->parent_fc;
645
646 switch (parent_fc->type) {
647 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
648 fs_sink_ctf_field_class_struct_align_at_least(
649 (void *) parent_fc, alignment);
650 break;
651 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
652 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
653 {
654 struct fs_sink_ctf_field_class_array_base *array_base_fc =
655 (void *) parent_fc;
656
657 array_base_fc->base.alignment = alignment;
658 break;
659 }
660 default:
661 break;
662 }
663 }
664
665 static inline
666 int translate_structure_field_class_members(struct ctx *ctx,
667 struct fs_sink_ctf_field_class_struct *struct_fc,
668 const bt_field_class *ir_fc)
669 {
670 int ret = 0;
671 uint64_t i;
672
673 for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
674 const bt_field_class_structure_member *member;
675 const char *name;
676 const bt_field_class *memb_ir_fc;
677
678 member =
679 bt_field_class_structure_borrow_member_by_index_const(
680 ir_fc, i);
681 name = bt_field_class_structure_member_get_name(member);
682 memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
683 member);
684 ret = cur_path_stack_push(ctx, i, name, true, memb_ir_fc,
685 (void *) struct_fc);
686 if (ret) {
687 BT_COMP_LOGE("Cannot translate structure field class member: "
688 "name=\"%s\"", name);
689 goto end;
690 }
691
692 ret = translate_field_class(ctx);
693 if (ret) {
694 BT_COMP_LOGE("Cannot translate structure field class member: "
695 "name=\"%s\"", name);
696 goto end;
697 }
698
699 cur_path_stack_pop(ctx);
700 }
701
702 end:
703 return ret;
704 }
705
706 static inline
707 int translate_structure_field_class(struct ctx *ctx)
708 {
709 int ret;
710 struct fs_sink_ctf_field_class_struct *fc =
711 fs_sink_ctf_field_class_struct_create_empty(
712 cur_path_stack_top(ctx)->ir_fc,
713 cur_path_stack_top(ctx)->index_in_parent);
714
715 BT_ASSERT(fc);
716 append_to_parent_field_class(ctx, (void *) fc);
717 ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
718 if (ret) {
719 goto end;
720 }
721
722 update_parent_field_class_alignment(ctx, fc->base.alignment);
723
724 end:
725 return ret;
726 }
727
728 /*
729 * This function protects a given variant FC option name (with the `_`
730 * prefix) if required. On success, `name_buf->str` contains the variant
731 * FC option name to use (original option name or protected if
732 * required).
733 *
734 * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
735 * close as possible to an original CTF trace as decoded by
736 * `src.ctf.fs`.
737 *
738 * This scenario is valid in CTF 1.8:
739 *
740 * enum {
741 * HELLO,
742 * MEOW
743 * } tag;
744 *
745 * variant <tag> {
746 * int HELLO;
747 * string MEOW;
748 * };
749 *
750 * Once in trace IR, the enumeration FC mapping names and variant FC
751 * option names are kept as is. For this reason, we don't want to
752 * protect the variant FC option names here (by prepending `_`): this
753 * would make the variant FC option name and the enumeration FC mapping
754 * name not match.
755 *
756 * This scenario is also valid in CTF 1.8:
757 *
758 * enum {
759 * _HELLO,
760 * MEOW
761 * } tag;
762 *
763 * variant <tag> {
764 * int _HELLO;
765 * string MEOW;
766 * };
767 *
768 * Once in trace IR, the enumeration FC mapping names are kept as is,
769 * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
770 * for presentation, as recommended by CTF 1.8). When going back to
771 * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
772 * the corresponding enumeration FC mapping name.
773 *
774 * This scenario is also valid in CTF 1.8:
775 *
776 * enum {
777 * __HELLO,
778 * MEOW
779 * } tag;
780 *
781 * variant <tag> {
782 * int __HELLO;
783 * string MEOW;
784 * };
785 *
786 * Once in trace IR, the enumeration FC mapping names are kept as is,
787 * but the `__HELLO` variant FC option name becomes `_HELLO`
788 * (unprotected). When going back to TSDL, we need to protect `_HELLO`
789 * so that it becomes `__HELLO` to match the corresponding enumeration
790 * FC mapping name.
791 *
792 * `src.ctf.fs` always uses the _same_ integer range sets for a selector
793 * FC mapping and a corresponding variant FC option. We can use that
794 * fact to find the original variant FC option names by matching variant
795 * FC options and enumeration FC mappings by range set.
796 */
797 static
798 int maybe_protect_variant_option_name(const bt_field_class *ir_var_fc,
799 const bt_field_class *ir_tag_fc, uint64_t opt_i,
800 GString *name_buf)
801 {
802 int ret = 0;
803 uint64_t i;
804 bt_field_class_type ir_var_fc_type;
805 const void *opt_ranges = NULL;
806 const char *mapping_label = NULL;
807 const char *ir_opt_name;
808 const bt_field_class_variant_option *base_var_opt;
809 bool force_protect = false;
810
811 ir_var_fc_type = bt_field_class_get_type(ir_var_fc);
812 base_var_opt = bt_field_class_variant_borrow_option_by_index_const(
813 ir_var_fc, opt_i);
814 BT_ASSERT(base_var_opt);
815 ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt);
816 BT_ASSERT(ir_opt_name);
817
818 /*
819 * Check if the variant FC option name is required to be
820 * protected (reserved TSDL keyword or starts with `_`). In that
821 * case, the name of the selector FC mapping we find must match
822 * exactly the protected name.
823 */
824 force_protect = must_protect_identifier(ir_opt_name);
825 if (force_protect) {
826 g_string_assign(name_buf, "_");
827 g_string_append(name_buf, ir_opt_name);
828 } else {
829 g_string_assign(name_buf, ir_opt_name);
830 }
831
832 /* Borrow option's ranges */
833 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD) {
834 /* No ranges: we're done */
835 goto end;
836 } if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
837 const bt_field_class_variant_with_selector_field_integer_unsigned_option *var_opt =
838 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
839 ir_var_fc, opt_i);
840 opt_ranges =
841 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
842 var_opt);
843 } else {
844 const bt_field_class_variant_with_selector_field_integer_signed_option *var_opt =
845 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
846 ir_var_fc, opt_i);
847 opt_ranges =
848 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
849 var_opt);
850 }
851
852 /* Find corresponding mapping by range set in selector FC */
853 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_tag_fc);
854 i++) {
855 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
856 const bt_field_class_enumeration_mapping *mapping_base;
857 const bt_field_class_enumeration_unsigned_mapping *mapping;
858 const bt_integer_range_set_unsigned *mapping_ranges;
859
860 mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
861 ir_tag_fc, i);
862 mapping_ranges = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
863 mapping);
864
865 if (bt_integer_range_set_unsigned_is_equal(opt_ranges,
866 mapping_ranges)) {
867 /* We have a winner */
868 mapping_base =
869 bt_field_class_enumeration_unsigned_mapping_as_mapping_const(
870 mapping);
871 mapping_label =
872 bt_field_class_enumeration_mapping_get_label(
873 mapping_base);
874 break;
875 }
876 } else {
877 const bt_field_class_enumeration_mapping *mapping_base;
878 const bt_field_class_enumeration_signed_mapping *mapping;
879 const bt_integer_range_set_signed *mapping_ranges;
880
881 mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
882 ir_tag_fc, i);
883 mapping_ranges = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
884 mapping);
885
886 if (bt_integer_range_set_signed_is_equal(opt_ranges,
887 mapping_ranges)) {
888 /* We have a winner */
889 mapping_base =
890 bt_field_class_enumeration_signed_mapping_as_mapping_const(
891 mapping);
892 mapping_label =
893 bt_field_class_enumeration_mapping_get_label(
894 mapping_base);
895 break;
896 }
897 }
898 }
899
900 if (!mapping_label) {
901 /* Range set not found: invalid selector for CTF 1.8 */
902 ret = -1;
903 goto end;
904 }
905
906 /*
907 * If the enumeration FC mapping name is not the same as the
908 * variant FC option name and we didn't protect already, try
909 * protecting the option name and check again.
910 */
911 if (strcmp(mapping_label, name_buf->str) != 0) {
912 if (force_protect) {
913 ret = -1;
914 goto end;
915 }
916
917 if (mapping_label[0] == '\0') {
918 ret = -1;
919 goto end;
920 }
921
922 g_string_assign(name_buf, "_");
923 g_string_append(name_buf, ir_opt_name);
924
925 if (strcmp(mapping_label, name_buf->str) != 0) {
926 ret = -1;
927 goto end;
928 }
929 }
930
931 end:
932 return ret;
933 }
934
935 static inline
936 int translate_option_field_class(struct ctx *ctx)
937 {
938 struct fs_sink_ctf_field_class_option *fc =
939 fs_sink_ctf_field_class_option_create_empty(
940 cur_path_stack_top(ctx)->ir_fc,
941 cur_path_stack_top(ctx)->index_in_parent);
942 const bt_field_class *content_ir_fc =
943 bt_field_class_option_borrow_field_class_const(fc->base.ir_fc);
944 int ret;
945
946 BT_ASSERT(fc);
947
948 /*
949 * CTF 1.8 does not support the option field class type. To
950 * write something anyway, this component translates this type
951 * to a variant field class where the options are:
952 *
953 * * An empty structure field class.
954 * * The optional field class itself.
955 *
956 * The "tag" is always generated/before in that case (an 8-bit
957 * unsigned enumeration field class).
958 */
959 append_to_parent_field_class(ctx, (void *) fc);
960 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, content_ir_fc,
961 (void *) fc);
962 if (ret) {
963 BT_COMP_LOGE_STR("Cannot translate option field class content.");
964 goto end;
965 }
966
967 ret = translate_field_class(ctx);
968 if (ret) {
969 BT_COMP_LOGE_STR("Cannot translate option field class content.");
970 goto end;
971 }
972
973 cur_path_stack_pop(ctx);
974 update_parent_field_class_alignment(ctx, fc->base.alignment);
975
976 end:
977 return ret;
978 }
979
980 static inline
981 int translate_variant_field_class(struct ctx *ctx)
982 {
983 int ret = 0;
984 uint64_t i;
985 struct fs_sink_ctf_field_class_variant *fc =
986 fs_sink_ctf_field_class_variant_create_empty(
987 cur_path_stack_top(ctx)->ir_fc,
988 cur_path_stack_top(ctx)->index_in_parent);
989 bt_field_class_type ir_fc_type;
990 const bt_field_path *ir_selector_field_path = NULL;
991 struct fs_sink_ctf_field_class *tgt_fc = NULL;
992 GString *name_buf = g_string_new(NULL);
993 bt_value *prot_opt_names = bt_value_array_create();
994 uint64_t opt_count;
995
996 BT_ASSERT(fc);
997 BT_ASSERT(name_buf);
998 BT_ASSERT(prot_opt_names);
999 ir_fc_type = bt_field_class_get_type(fc->base.ir_fc);
1000 opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc);
1001
1002 if (bt_field_class_type_is(ir_fc_type,
1003 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) {
1004 ir_selector_field_path = bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
1005 fc->base.ir_fc);
1006 BT_ASSERT(ir_selector_field_path);
1007 }
1008
1009 /* Resolve tag field class before appending to parent */
1010 resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref,
1011 &fc->tag_is_before, &tgt_fc);
1012
1013 if (ir_selector_field_path && tgt_fc) {
1014 uint64_t mapping_count;
1015 uint64_t option_count;
1016
1017 /* CTF 1.8: selector FC must be an enumeration FC */
1018 bt_field_class_type type = bt_field_class_get_type(
1019 tgt_fc->ir_fc);
1020
1021 if (!bt_field_class_type_is(type,
1022 BT_FIELD_CLASS_TYPE_ENUMERATION)) {
1023 fc->tag_is_before = true;
1024 goto validate_opts;
1025 }
1026
1027 /*
1028 * Call maybe_protect_variant_option_name() for each
1029 * option below. In that case we also want selector FC
1030 * to contain as many mappings as the variant FC has
1031 * options.
1032 */
1033 mapping_count = bt_field_class_enumeration_get_mapping_count(
1034 tgt_fc->ir_fc);
1035 option_count = bt_field_class_variant_get_option_count(
1036 fc->base.ir_fc);
1037
1038 if (mapping_count != option_count) {
1039 fc->tag_is_before = true;
1040 goto validate_opts;
1041 }
1042 } else {
1043 /*
1044 * No compatible selector field class for CTF 1.8:
1045 * create the appropriate selector field class.
1046 */
1047 fc->tag_is_before = true;
1048 goto validate_opts;
1049 }
1050
1051 validate_opts:
1052 /*
1053 * First pass: detect any option name clash with option name
1054 * protection. In that case, we don't fail: just create the
1055 * selector field class before the variant field class.
1056 *
1057 * After this, `prot_opt_names` contains the final option names,
1058 * potentially protected if needed. They can still be invalid
1059 * TSDL identifiers however; this will be checked by
1060 * cur_path_stack_push().
1061 */
1062 for (i = 0; i < opt_count; i++) {
1063 if (!fc->tag_is_before) {
1064 BT_ASSERT(tgt_fc->ir_fc);
1065 ret = maybe_protect_variant_option_name(fc->base.ir_fc,
1066 tgt_fc->ir_fc, i, name_buf);
1067 if (ret) {
1068 fc->tag_is_before = true;
1069 }
1070 }
1071
1072 ret = bt_value_array_append_string_element(prot_opt_names,
1073 name_buf->str);
1074 if (ret) {
1075 goto end;
1076 }
1077 }
1078
1079 for (i = 0; i < opt_count; i++) {
1080 uint64_t j;
1081 const bt_value *opt_name_a =
1082 bt_value_array_borrow_element_by_index_const(
1083 prot_opt_names, i);
1084
1085 for (j = 0; j < opt_count; j++) {
1086 const bt_value *opt_name_b;
1087
1088 if (i == j) {
1089 continue;
1090 }
1091
1092 opt_name_b =
1093 bt_value_array_borrow_element_by_index_const(
1094 prot_opt_names, j);
1095 if (bt_value_is_equal(opt_name_a, opt_name_b)) {
1096 /*
1097 * Variant FC option names are not
1098 * unique when protected.
1099 */
1100 fc->tag_is_before = true;
1101 goto append_to_parent;
1102 }
1103 }
1104 }
1105
1106 append_to_parent:
1107 append_to_parent_field_class(ctx, (void *) fc);
1108
1109 for (i = 0; i < opt_count; i++) {
1110 const bt_field_class_variant_option *opt;
1111 const bt_field_class *opt_ir_fc;
1112 const bt_value *prot_opt_name_val =
1113 bt_value_array_borrow_element_by_index_const(
1114 prot_opt_names, i);
1115 const char *prot_opt_name = bt_value_string_get(
1116 prot_opt_name_val);
1117
1118 BT_ASSERT(prot_opt_name);
1119 opt = bt_field_class_variant_borrow_option_by_index_const(
1120 fc->base.ir_fc, i);
1121 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
1122 opt);
1123
1124 /*
1125 * We don't ask cur_path_stack_push() to protect the
1126 * option name because it's already protected at this
1127 * point.
1128 */
1129 ret = cur_path_stack_push(ctx, i, prot_opt_name, false,
1130 opt_ir_fc, (void *) fc);
1131 if (ret) {
1132 BT_COMP_LOGE("Cannot translate variant field class option: "
1133 "name=\"%s\"", prot_opt_name);
1134 goto end;
1135 }
1136
1137 ret = translate_field_class(ctx);
1138 if (ret) {
1139 BT_COMP_LOGE("Cannot translate variant field class option: "
1140 "name=\"%s\"", prot_opt_name);
1141 goto end;
1142 }
1143
1144 cur_path_stack_pop(ctx);
1145 }
1146
1147 end:
1148 if (name_buf) {
1149 g_string_free(name_buf, TRUE);
1150 }
1151
1152 bt_value_put_ref(prot_opt_names);
1153 return ret;
1154 }
1155
1156 static inline
1157 int translate_static_array_field_class(struct ctx *ctx)
1158 {
1159 struct fs_sink_ctf_field_class_array *fc =
1160 fs_sink_ctf_field_class_array_create_empty(
1161 cur_path_stack_top(ctx)->ir_fc,
1162 cur_path_stack_top(ctx)->index_in_parent);
1163 const bt_field_class *elem_ir_fc =
1164 bt_field_class_array_borrow_element_field_class_const(
1165 fc->base.base.ir_fc);
1166 int ret;
1167
1168 BT_ASSERT(fc);
1169 append_to_parent_field_class(ctx, (void *) fc);
1170 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
1171 (void *) fc);
1172 if (ret) {
1173 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
1174 goto end;
1175 }
1176
1177 ret = translate_field_class(ctx);
1178 if (ret) {
1179 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
1180 goto end;
1181 }
1182
1183 cur_path_stack_pop(ctx);
1184 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1185
1186 end:
1187 return ret;
1188 }
1189
1190 static inline
1191 int translate_dynamic_array_field_class(struct ctx *ctx)
1192 {
1193 struct fs_sink_ctf_field_class_sequence *fc =
1194 fs_sink_ctf_field_class_sequence_create_empty(
1195 cur_path_stack_top(ctx)->ir_fc,
1196 cur_path_stack_top(ctx)->index_in_parent);
1197 const bt_field_class *elem_ir_fc =
1198 bt_field_class_array_borrow_element_field_class_const(
1199 fc->base.base.ir_fc);
1200 int ret;
1201
1202 BT_ASSERT(fc);
1203
1204 /* Resolve length field class before appending to parent */
1205 if (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc) ==
1206 BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) {
1207 resolve_field_class(ctx,
1208 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1209 fc->base.base.ir_fc),
1210 fc->length_ref, &fc->length_is_before, NULL);
1211 }
1212
1213 append_to_parent_field_class(ctx, (void *) fc);
1214 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
1215 (void *) fc);
1216 if (ret) {
1217 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
1218 goto end;
1219 }
1220
1221 ret = translate_field_class(ctx);
1222 if (ret) {
1223 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
1224 goto end;
1225 }
1226
1227 cur_path_stack_pop(ctx);
1228 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1229
1230 end:
1231 return ret;
1232 }
1233
1234 static inline
1235 int translate_bool_field_class(struct ctx *ctx)
1236 {
1237 struct fs_sink_ctf_field_class_bool *fc =
1238 fs_sink_ctf_field_class_bool_create(
1239 cur_path_stack_top(ctx)->ir_fc,
1240 cur_path_stack_top(ctx)->index_in_parent);
1241
1242 BT_ASSERT(fc);
1243 append_to_parent_field_class(ctx, (void *) fc);
1244 return 0;
1245 }
1246
1247 static inline
1248 int translate_bit_array_field_class(struct ctx *ctx)
1249 {
1250 struct fs_sink_ctf_field_class_bit_array *fc =
1251 fs_sink_ctf_field_class_bit_array_create(
1252 cur_path_stack_top(ctx)->ir_fc,
1253 cur_path_stack_top(ctx)->index_in_parent);
1254
1255 BT_ASSERT(fc);
1256 append_to_parent_field_class(ctx, (void *) fc);
1257 return 0;
1258 }
1259
1260 static inline
1261 int translate_integer_field_class(struct ctx *ctx)
1262 {
1263 struct fs_sink_ctf_field_class_int *fc =
1264 fs_sink_ctf_field_class_int_create(
1265 cur_path_stack_top(ctx)->ir_fc,
1266 cur_path_stack_top(ctx)->index_in_parent);
1267
1268 BT_ASSERT(fc);
1269 append_to_parent_field_class(ctx, (void *) fc);
1270 return 0;
1271 }
1272
1273 static inline
1274 int translate_real_field_class(struct ctx *ctx)
1275 {
1276 struct fs_sink_ctf_field_class_float *fc =
1277 fs_sink_ctf_field_class_float_create(
1278 cur_path_stack_top(ctx)->ir_fc,
1279 cur_path_stack_top(ctx)->index_in_parent);
1280
1281 BT_ASSERT(fc);
1282 append_to_parent_field_class(ctx, (void *) fc);
1283 return 0;
1284 }
1285
1286 static inline
1287 int translate_string_field_class(struct ctx *ctx)
1288 {
1289 struct fs_sink_ctf_field_class_string *fc =
1290 fs_sink_ctf_field_class_string_create(
1291 cur_path_stack_top(ctx)->ir_fc,
1292 cur_path_stack_top(ctx)->index_in_parent);
1293
1294 BT_ASSERT(fc);
1295 append_to_parent_field_class(ctx, (void *) fc);
1296 return 0;
1297 }
1298
1299 /*
1300 * Translates a field class, recursively.
1301 *
1302 * The field class's IR field class, parent field class, and index
1303 * within its parent are in the context's current path's top element
1304 * (cur_path_stack_top()).
1305 */
1306 static
1307 int translate_field_class(struct ctx *ctx)
1308 {
1309 int ret;
1310 bt_field_class_type ir_fc_type =
1311 bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc);
1312
1313 if (ir_fc_type == BT_FIELD_CLASS_TYPE_BOOL) {
1314 ret = translate_bool_field_class(ctx);
1315 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) {
1316 ret = translate_bit_array_field_class(ctx);
1317 } else if (bt_field_class_type_is(ir_fc_type,
1318 BT_FIELD_CLASS_TYPE_INTEGER)) {
1319 ret = translate_integer_field_class(ctx);
1320 } else if (bt_field_class_type_is(ir_fc_type,
1321 BT_FIELD_CLASS_TYPE_REAL)) {
1322 ret = translate_real_field_class(ctx);
1323 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_STRING) {
1324 ret = translate_string_field_class(ctx);
1325 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
1326 ret = translate_structure_field_class(ctx);
1327 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) {
1328 ret = translate_static_array_field_class(ctx);
1329 } else if (bt_field_class_type_is(ir_fc_type,
1330 BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) {
1331 ret = translate_dynamic_array_field_class(ctx);
1332 } else if (bt_field_class_type_is(ir_fc_type,
1333 BT_FIELD_CLASS_TYPE_OPTION)) {
1334 ret = translate_option_field_class(ctx);
1335 } else if (bt_field_class_type_is(ir_fc_type,
1336 BT_FIELD_CLASS_TYPE_VARIANT)) {
1337 ret = translate_variant_field_class(ctx);
1338 } else {
1339 abort();
1340 }
1341
1342 return ret;
1343 }
1344
1345 static
1346 int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
1347 struct fs_sink_ctf_field_class *parent_fc)
1348 {
1349 int ret = 0;
1350 GString *field_ref = NULL;
1351 bool is_before;
1352 const char *tgt_type;
1353 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
1354 (void *) parent_fc;
1355 uint64_t i;
1356 unsigned int suffix = 0;
1357
1358 if (!fc_name || !parent_fc ||
1359 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1360 /* Not supported */
1361 ret = -1;
1362 goto end;
1363 }
1364
1365 switch (fc->type) {
1366 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
1367 {
1368 /*
1369 * CTF 1.8 does not support the option field class type.
1370 * To write something anyway, this component translates
1371 * this type to a variant field class where the options
1372 * are:
1373 *
1374 * * An empty structure field class.
1375 * * The optional field class itself.
1376 *
1377 * Because the option field class becomes a CTF variant
1378 * field class, we use the term "tag" too here.
1379 *
1380 * The "tag" is always generated/before in that case (an
1381 * 8-bit unsigned enumeration field class).
1382 */
1383 struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc;
1384
1385 field_ref = opt_fc->tag_ref;
1386 is_before = true;
1387 tgt_type = "tag";
1388 break;
1389 }
1390 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1391 {
1392 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
1393
1394 field_ref = seq_fc->length_ref;
1395 is_before = seq_fc->length_is_before;
1396 tgt_type = "len";
1397 break;
1398 }
1399 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1400 {
1401 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
1402
1403 field_ref = var_fc->tag_ref;
1404 is_before = var_fc->tag_is_before;
1405 tgt_type = "tag";
1406 break;
1407 }
1408 default:
1409 abort();
1410 }
1411
1412 BT_ASSERT(field_ref);
1413
1414 if (!is_before) {
1415 goto end;
1416 }
1417
1418 /* Initial field ref */
1419 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
1420
1421 /*
1422 * Make sure field ref does not clash with an existing field
1423 * class name within the same parent structure field class.
1424 */
1425 while (true) {
1426 bool name_ok = true;
1427
1428 for (i = 0; i < parent_struct_fc->members->len; i++) {
1429 struct fs_sink_ctf_named_field_class *named_fc =
1430 fs_sink_ctf_field_class_struct_borrow_member_by_index(
1431 parent_struct_fc, i);
1432
1433 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
1434 /* Name clash */
1435 name_ok = false;
1436 break;
1437 }
1438 }
1439
1440 if (name_ok) {
1441 /* No clash: we're done */
1442 break;
1443 }
1444
1445 /* Append suffix and try again */
1446 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
1447 suffix);
1448 suffix++;
1449 }
1450
1451 end:
1452 return ret;
1453 }
1454
1455 /*
1456 * This function recursively sets field refs of sequence and variant
1457 * field classes when they are immediately before, avoiding name clashes
1458 * with existing field class names.
1459 *
1460 * It can fail at this point if, for example, a sequence field class of
1461 * which to set the length's field ref has something else than a
1462 * structure field class as its parent: in this case, there's no
1463 * location to place the length field class immediately before the
1464 * sequence field class.
1465 */
1466 static
1467 int set_field_refs(struct fs_sink_ctf_field_class * const fc,
1468 const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
1469 {
1470 int ret = 0;
1471 enum fs_sink_ctf_field_class_type fc_type;
1472 BT_ASSERT(fc);
1473
1474 fc_type = fc->type;
1475
1476 switch (fc_type) {
1477 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
1478 {
1479 struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc;
1480
1481 ret = set_field_ref(fc, fc_name, parent_fc);
1482 if (ret) {
1483 goto end;
1484 }
1485
1486 ret = set_field_refs(opt_fc->content_fc, NULL, fc);
1487 if (ret) {
1488 goto end;
1489 }
1490
1491 break;
1492 }
1493 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1494 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1495 {
1496 uint64_t i;
1497 uint64_t len;
1498 struct fs_sink_ctf_field_class_struct *struct_fc = NULL;
1499 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
1500 struct fs_sink_ctf_named_field_class *named_fc;
1501
1502 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1503 struct_fc = (void *) fc;
1504 len = struct_fc->members->len;
1505 } else {
1506 var_fc = (void *) fc;
1507 len = var_fc->options->len;
1508 ret = set_field_ref(fc, fc_name, parent_fc);
1509 if (ret) {
1510 goto end;
1511 }
1512 }
1513
1514 for (i = 0; i < len; i++) {
1515 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1516 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1517 struct_fc, i);
1518 } else {
1519 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1520 var_fc, i);
1521 }
1522
1523 ret = set_field_refs(named_fc->fc, named_fc->name->str,
1524 fc);
1525 if (ret) {
1526 goto end;
1527 }
1528 }
1529
1530 break;
1531 }
1532 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
1533 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1534 {
1535 struct fs_sink_ctf_field_class_array_base *array_base_fc =
1536 (void *) fc;
1537
1538 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
1539 ret = set_field_ref(fc, fc_name, parent_fc);
1540 if (ret) {
1541 goto end;
1542 }
1543 }
1544
1545 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
1546 if (ret) {
1547 goto end;
1548 }
1549
1550 break;
1551 }
1552 default:
1553 break;
1554 }
1555
1556 end:
1557 return ret;
1558 }
1559
1560 /*
1561 * This function translates a root scope trace IR field class to
1562 * a CTF IR field class.
1563 *
1564 * The resulting CTF IR field class is written to `*fc` so that it
1565 * exists as the parent object's (stream class or event class) true root
1566 * field class during the recursive translation for resolving purposes.
1567 * This is also why this function creates the empty structure field
1568 * class and then calls translate_structure_field_class_members() to
1569 * fill it.
1570 */
1571 static
1572 int translate_scope_field_class(struct ctx *ctx, bt_field_path_scope scope,
1573 struct fs_sink_ctf_field_class **fc,
1574 const bt_field_class *ir_fc)
1575 {
1576 int ret = 0;
1577
1578 if (!ir_fc) {
1579 goto end;
1580 }
1581
1582 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
1583 BT_FIELD_CLASS_TYPE_STRUCTURE);
1584 BT_ASSERT(fc);
1585 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
1586 ir_fc, UINT64_C(-1));
1587 BT_ASSERT(*fc);
1588 ctx->cur_scope = scope;
1589 BT_ASSERT(ctx->cur_path->len == 0);
1590 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
1591 if (ret) {
1592 BT_COMP_LOGE("Cannot translate scope structure field class: "
1593 "scope=%d", scope);
1594 goto end;
1595 }
1596
1597 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
1598 if (ret) {
1599 BT_COMP_LOGE("Cannot translate scope structure field class: "
1600 "scope=%d", scope);
1601 goto end;
1602 }
1603
1604 cur_path_stack_pop(ctx);
1605
1606 /* Set field refs for preceding targets */
1607 ret = set_field_refs(*fc, NULL, NULL);
1608
1609 end:
1610 return ret;
1611 }
1612
1613 static inline
1614 void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
1615 {
1616 memset(ctx, 0, sizeof(struct ctx));
1617 ctx->cur_path = g_array_new(FALSE, TRUE,
1618 sizeof(struct field_path_elem));
1619 BT_ASSERT(ctx->cur_path);
1620 ctx->log_level = fs_sink->log_level;
1621 ctx->self_comp = fs_sink->self_comp;
1622 }
1623
1624 static inline
1625 void ctx_fini(struct ctx *ctx)
1626 {
1627 if (ctx->cur_path) {
1628 g_array_free(ctx->cur_path, TRUE);
1629 ctx->cur_path = NULL;
1630 }
1631 }
1632
1633 static
1634 int translate_event_class(struct fs_sink_comp *fs_sink,
1635 struct fs_sink_ctf_stream_class *sc,
1636 const bt_event_class *ir_ec,
1637 struct fs_sink_ctf_event_class **out_ec)
1638 {
1639 int ret = 0;
1640 struct ctx ctx;
1641 struct fs_sink_ctf_event_class *ec;
1642
1643 BT_ASSERT(sc);
1644 BT_ASSERT(ir_ec);
1645
1646 ctx_init(&ctx, fs_sink);
1647 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1648 BT_ASSERT(ec);
1649 ctx.cur_sc = sc;
1650 ctx.cur_ec = ec;
1651 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT,
1652 &ec->spec_context_fc,
1653 bt_event_class_borrow_specific_context_field_class_const(
1654 ir_ec));
1655 if (ret) {
1656 goto end;
1657 }
1658
1659 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD,
1660 &ec->payload_fc,
1661 bt_event_class_borrow_payload_field_class_const(ir_ec));
1662 if (ret) {
1663 goto end;
1664 }
1665
1666 end:
1667 ctx_fini(&ctx);
1668 *out_ec = ec;
1669 return ret;
1670 }
1671
1672 BT_HIDDEN
1673 int try_translate_event_class_trace_ir_to_ctf_ir(
1674 struct fs_sink_comp *fs_sink,
1675 struct fs_sink_ctf_stream_class *sc,
1676 const bt_event_class *ir_ec,
1677 struct fs_sink_ctf_event_class **out_ec)
1678 {
1679 int ret = 0;
1680
1681 BT_ASSERT(sc);
1682 BT_ASSERT(ir_ec);
1683
1684 /* Check in hash table first */
1685 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
1686 if (G_LIKELY(*out_ec)) {
1687 goto end;
1688 }
1689
1690 ret = translate_event_class(fs_sink, sc, ir_ec, out_ec);
1691
1692 end:
1693 return ret;
1694 }
1695
1696 bool default_clock_class_name_exists(struct fs_sink_ctf_trace *trace,
1697 const char *name)
1698 {
1699 bool exists = false;
1700 uint64_t i;
1701
1702 for (i = 0; i < trace->stream_classes->len; i++) {
1703 struct fs_sink_ctf_stream_class *sc =
1704 trace->stream_classes->pdata[i];
1705
1706 if (sc->default_clock_class_name->len == 0) {
1707 /* No default clock class */
1708 continue;
1709 }
1710
1711 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1712 exists = true;
1713 goto end;
1714 }
1715 }
1716
1717 end:
1718 return exists;
1719 }
1720
1721 static
1722 void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1723 {
1724 unsigned int suffix = 0;
1725 char buf[16];
1726
1727 g_string_assign(sc->default_clock_class_name, "");
1728 sprintf(buf, "default");
1729
1730 while (default_clock_class_name_exists(sc->trace, buf)) {
1731 sprintf(buf, "default%u", suffix);
1732 suffix++;
1733 }
1734
1735 g_string_assign(sc->default_clock_class_name, buf);
1736 }
1737
1738 static
1739 int translate_stream_class(struct fs_sink_comp *fs_sink,
1740 struct fs_sink_ctf_trace *trace,
1741 const bt_stream_class *ir_sc,
1742 struct fs_sink_ctf_stream_class **out_sc)
1743 {
1744 int ret = 0;
1745 struct ctx ctx;
1746
1747 BT_ASSERT(trace);
1748 BT_ASSERT(ir_sc);
1749 ctx_init(&ctx, fs_sink);
1750 *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
1751 BT_ASSERT(*out_sc);
1752
1753 /* Set default clock class's protected name, if any */
1754 if ((*out_sc)->default_clock_class) {
1755 const char *name = bt_clock_class_get_name(
1756 (*out_sc)->default_clock_class);
1757
1758 if (name) {
1759 /* Try original name, protected */
1760 g_string_assign((*out_sc)->default_clock_class_name,
1761 "");
1762
1763 if (must_protect_identifier(name)) {
1764 g_string_assign(
1765 (*out_sc)->default_clock_class_name,
1766 "_");
1767 }
1768
1769 g_string_assign((*out_sc)->default_clock_class_name,
1770 name);
1771 if (!ist_valid_identifier(
1772 (*out_sc)->default_clock_class_name->str)) {
1773 /* Invalid: create a new name */
1774 make_unique_default_clock_class_name(*out_sc);
1775 ret = 0;
1776 }
1777 } else {
1778 /* No name: create a name */
1779 make_unique_default_clock_class_name(*out_sc);
1780 }
1781 }
1782
1783 ctx.cur_sc = *out_sc;
1784 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT,
1785 &(*out_sc)->packet_context_fc,
1786 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1787 if (ret) {
1788 goto error;
1789 }
1790
1791 if ((*out_sc)->packet_context_fc) {
1792 /*
1793 * Make sure the structure field class's alignment is
1794 * enough: 8 is what we use for our own special members
1795 * in the packet context.
1796 */
1797 fs_sink_ctf_field_class_struct_align_at_least(
1798 (void *) (*out_sc)->packet_context_fc, 8);
1799 }
1800
1801 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT,
1802 &(*out_sc)->event_common_context_fc,
1803 bt_stream_class_borrow_event_common_context_field_class_const(
1804 ir_sc));
1805 if (ret) {
1806 goto error;
1807 }
1808
1809 goto end;
1810
1811 error:
1812 fs_sink_ctf_stream_class_destroy(*out_sc);
1813 *out_sc = NULL;
1814
1815 end:
1816 ctx_fini(&ctx);
1817 return ret;
1818 }
1819
1820 BT_HIDDEN
1821 int try_translate_stream_class_trace_ir_to_ctf_ir(
1822 struct fs_sink_comp *fs_sink,
1823 struct fs_sink_ctf_trace *trace,
1824 const bt_stream_class *ir_sc,
1825 struct fs_sink_ctf_stream_class **out_sc)
1826 {
1827 int ret = 0;
1828 uint64_t i;
1829
1830 BT_ASSERT(trace);
1831 BT_ASSERT(ir_sc);
1832
1833 for (i = 0; i < trace->stream_classes->len; i++) {
1834 *out_sc = trace->stream_classes->pdata[i];
1835
1836 if ((*out_sc)->ir_sc == ir_sc) {
1837 goto end;
1838 }
1839 }
1840
1841 ret = translate_stream_class(fs_sink, trace, ir_sc, out_sc);
1842
1843 end:
1844 return ret;
1845 }
1846
1847 BT_HIDDEN
1848 struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(
1849 struct fs_sink_comp *fs_sink, const bt_trace *ir_trace)
1850 {
1851 uint64_t count;
1852 uint64_t i;
1853 struct fs_sink_ctf_trace *trace = NULL;
1854
1855 /* Check that trace's environment is TSDL-compatible */
1856 count = bt_trace_get_environment_entry_count(ir_trace);
1857 for (i = 0; i < count; i++) {
1858 const char *name;
1859 const bt_value *val;
1860
1861 bt_trace_borrow_environment_entry_by_index_const(
1862 ir_trace, i, &name, &val);
1863
1864 if (!ist_valid_identifier(name)) {
1865 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1866 fs_sink->self_comp,
1867 "Unsupported trace class's environment entry name: "
1868 "name=\"%s\"", name);
1869 goto end;
1870 }
1871
1872 switch (bt_value_get_type(val)) {
1873 case BT_VALUE_TYPE_SIGNED_INTEGER:
1874 case BT_VALUE_TYPE_STRING:
1875 break;
1876 default:
1877 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1878 fs_sink->self_comp,
1879 "Unsupported trace class's environment entry value type: "
1880 "type=%s",
1881 bt_common_value_type_string(
1882 bt_value_get_type(val)));
1883 goto end;
1884 }
1885 }
1886
1887 trace = fs_sink_ctf_trace_create(ir_trace);
1888 BT_ASSERT(trace);
1889
1890 end:
1891 return trace;
1892 }
This page took 0.087549 seconds and 3 git commands to generate.