2 * SPDX-License-Identifier: MIT
4 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
13 #include <babeltrace2/babeltrace.h>
15 #include "common/assert.h"
16 #include "common/common.h"
17 #include "cpp-common/bt2/field-path.hpp"
18 #include "cpp-common/bt2c/fmt.hpp"
20 #include "fs-sink-ctf-meta.hpp"
21 #include "fs-sink.hpp"
22 #include "translate-trace-ir-to-ctf-ir.hpp"
24 struct field_path_elem
29 const bt_field_class
*ir_fc
;
32 struct fs_sink_ctf_field_class
*parent_fc
;
38 struct TraceIrToCtfIrCtx
40 explicit TraceIrToCtfIrCtx(const bt2c::Logger
& parentLogger
) :
41 logger
{parentLogger
, "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"}
48 struct fs_sink_ctf_stream_class
*cur_sc
= nullptr;
51 struct fs_sink_ctf_event_class
*cur_ec
= nullptr;
53 bt_field_path_scope cur_scope
= BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
;
56 * Array of `struct field_path_elem` */
57 GArray
*cur_path
= nullptr;
60 } /* namespace sink */
63 static inline struct field_path_elem
*cur_path_stack_at(ctf::sink::TraceIrToCtfIrCtx
*ctx
,
66 BT_ASSERT(i
< ctx
->cur_path
->len
);
67 return &bt_g_array_index(ctx
->cur_path
, struct field_path_elem
, i
);
70 static inline struct field_path_elem
*cur_path_stack_top(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
72 BT_ASSERT(ctx
->cur_path
->len
> 0);
73 return cur_path_stack_at(ctx
, ctx
->cur_path
->len
- 1);
76 static inline bool is_reserved_member_name(const char *name
, const char *reserved_name
)
78 bool is_reserved
= false;
80 if (strcmp(name
, reserved_name
) == 0) {
85 if (name
[0] == '_' && strcmp(&name
[1], reserved_name
) == 0) {
94 static const char *reserved_tsdl_keywords
[] = {
95 "align", "callsite", "const", "char", "clock", "double", "enum",
96 "env", "event", "floating_point", "float", "integer", "int", "long",
97 "short", "signed", "stream", "string", "struct", "trace", "typealias",
98 "typedef", "unsigned", "variant", "void", "_Bool", "_Complex", "_Imaginary",
101 static inline bool ist_valid_identifier(const char *name
)
105 bool ist_valid
= true;
107 /* Make sure the name is not a reserved keyword */
108 for (i
= 0; i
< sizeof(reserved_tsdl_keywords
) / sizeof(*reserved_tsdl_keywords
); i
++) {
109 if (strcmp(name
, reserved_tsdl_keywords
[i
]) == 0) {
115 /* Make sure the name is not an empty string */
116 if (strlen(name
) == 0) {
121 /* Make sure the name starts with a letter or `_` */
122 if (!isalpha((unsigned char) name
[0]) && name
[0] != '_') {
127 /* Make sure the name only contains letters, digits, and `_` */
128 for (at
= name
; *at
!= '\0'; at
++) {
129 if (!isalnum((unsigned char) *at
) && *at
!= '_') {
139 static inline bool must_protect_identifier(const char *name
)
142 bool must_protect
= false;
144 /* Protect a reserved keyword */
145 for (i
= 0; i
< sizeof(reserved_tsdl_keywords
) / sizeof(*reserved_tsdl_keywords
); i
++) {
146 if (strcmp(name
, reserved_tsdl_keywords
[i
]) == 0) {
152 /* Protect an identifier which already starts with `_` */
153 if (name
[0] == '_') {
162 static inline int cur_path_stack_push(ctf::sink::TraceIrToCtfIrCtx
*ctx
, const char *name
,
163 bool force_protect_name
, const bt_field_class
*ir_fc
,
164 struct fs_sink_ctf_field_class
*parent_fc
)
167 struct field_path_elem
*field_path_elem
;
169 g_array_set_size(ctx
->cur_path
, ctx
->cur_path
->len
+ 1);
170 field_path_elem
= cur_path_stack_top(ctx
);
171 field_path_elem
->name
= g_string_new(NULL
);
174 if (force_protect_name
) {
175 g_string_assign(field_path_elem
->name
, "_");
178 g_string_append(field_path_elem
->name
, name
);
180 if (ctx
->cur_scope
== BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
) {
181 if (is_reserved_member_name(name
, "packet_size") ||
182 is_reserved_member_name(name
, "content_size") ||
183 is_reserved_member_name(name
, "timestamp_begin") ||
184 is_reserved_member_name(name
, "timestamp_end") ||
185 is_reserved_member_name(name
, "events_discarded") ||
186 is_reserved_member_name(name
, "packet_seq_num")) {
187 BT_CPPLOGE_SPEC(ctx
->logger
,
188 "Unsupported reserved TSDL structure field class member "
189 "or variant field class option name: name=\"{}\"",
196 if (!ist_valid_identifier(field_path_elem
->name
->str
)) {
198 BT_CPPLOGE_SPEC(ctx
->logger
,
199 "Unsupported non-TSDL structure field class member "
200 "or variant field class option name: name=\"{}\"",
201 field_path_elem
->name
->str
);
206 field_path_elem
->ir_fc
= ir_fc
;
207 field_path_elem
->parent_fc
= parent_fc
;
213 static inline void cur_path_stack_pop(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
215 struct field_path_elem
*field_path_elem
;
217 BT_ASSERT(ctx
->cur_path
->len
> 0);
218 field_path_elem
= cur_path_stack_top(ctx
);
220 if (field_path_elem
->name
) {
221 g_string_free(field_path_elem
->name
, TRUE
);
222 field_path_elem
->name
= NULL
;
225 g_array_set_size(ctx
->cur_path
, ctx
->cur_path
->len
- 1);
229 * Creates a relative field ref (a single name) from IR field path
230 * `tgt_ir_field_path`.
232 * This function tries to locate the target field class recursively from
233 * the top to the bottom of the context's current path using only the
234 * target field class's own name. This is because many CTF reading tools
235 * do not support a relative field ref with more than one element, for
236 * example `prev_struct.len`.
238 * Returns a negative value if this resolving operation failed.
240 static int create_relative_field_ref(ctf::sink::TraceIrToCtfIrCtx
*ctx
,
241 const bt_field_path
*tgt_ir_field_path
, GString
*tgt_field_ref
,
242 struct fs_sink_ctf_field_class
**user_tgt_fc
)
245 struct fs_sink_ctf_field_class
*tgt_fc
= NULL
;
248 const char *tgt_fc_name
= NULL
;
249 struct field_path_elem
*field_path_elem
;
251 /* Get target field class's name */
252 switch (bt_field_path_get_root_scope(tgt_ir_field_path
)) {
253 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
254 BT_ASSERT(ctx
->cur_sc
);
255 tgt_fc
= ctx
->cur_sc
->packet_context_fc
;
257 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
258 BT_ASSERT(ctx
->cur_sc
);
259 tgt_fc
= ctx
->cur_sc
->event_common_context_fc
;
261 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
262 BT_ASSERT(ctx
->cur_ec
);
263 tgt_fc
= ctx
->cur_ec
->spec_context_fc
;
265 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
266 BT_ASSERT(ctx
->cur_ec
);
267 tgt_fc
= ctx
->cur_ec
->payload_fc
;
275 while (i
< bt_field_path_get_item_count(tgt_ir_field_path
)) {
276 const bt_field_path_item
*fp_item
=
277 bt_field_path_borrow_item_by_index_const(tgt_ir_field_path
, i
);
278 struct fs_sink_ctf_named_field_class
*named_fc
= NULL
;
283 if (bt_field_path_item_get_type(fp_item
) ==
284 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
) {
285 /* Not supported by CTF 1.8 */
290 switch (tgt_fc
->type
) {
291 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
292 BT_ASSERT(bt_field_path_item_get_type(fp_item
) == BT_FIELD_PATH_ITEM_TYPE_INDEX
);
293 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(
294 fs_sink_ctf_field_class_as_struct(tgt_fc
),
295 bt_field_path_item_index_get_index(fp_item
));
297 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
298 BT_ASSERT(bt_field_path_item_get_type(fp_item
) == BT_FIELD_PATH_ITEM_TYPE_INDEX
);
299 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(
300 fs_sink_ctf_field_class_as_variant(tgt_fc
),
301 bt_field_path_item_index_get_index(fp_item
));
303 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
304 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
306 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
307 fs_sink_ctf_field_class_as_array_base(tgt_fc
);
309 BT_ASSERT(bt_field_path_item_get_type(fp_item
) ==
310 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
311 tgt_fc
= array_base_fc
->elem_fc
;
319 tgt_fc
= named_fc
->fc
;
320 tgt_fc_name
= named_fc
->name
->str
;
326 BT_ASSERT(tgt_fc
->type
== FS_SINK_CTF_FIELD_CLASS_TYPE_INT
);
327 BT_ASSERT(tgt_fc_name
);
329 /* Find target field class having this name in current context */
330 for (si
= ctx
->cur_path
->len
- 1; si
>= 0; si
--) {
331 struct fs_sink_ctf_field_class
*fc
;
332 struct fs_sink_ctf_field_class_struct
*struct_fc
= NULL
;
333 struct fs_sink_ctf_field_class_variant
*var_fc
= NULL
;
334 struct fs_sink_ctf_named_field_class
*named_fc
;
337 field_path_elem
= cur_path_stack_at(ctx
, (uint64_t) si
);
338 fc
= field_path_elem
->parent_fc
;
340 /* Reached stack's bottom */
346 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
347 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
349 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
350 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
353 /* Not supported by TSDL 1.8 */
358 if (fc
->type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
359 struct_fc
= fs_sink_ctf_field_class_as_struct(fc
);
360 len
= struct_fc
->members
->len
;
362 var_fc
= fs_sink_ctf_field_class_as_variant(fc
);
363 len
= var_fc
->options
->len
;
366 for (i
= 0; i
< len
; i
++) {
367 if (fc
->type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
368 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(struct_fc
, i
);
370 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(var_fc
, i
);
373 if (strcmp(named_fc
->name
->str
, tgt_fc_name
) == 0) {
374 if (named_fc
->fc
== tgt_fc
) {
375 g_string_assign(tgt_field_ref
, tgt_fc_name
);
378 *user_tgt_fc
= tgt_fc
;
382 * Using only the target field
383 * class's name, we're not
384 * reaching the target field
385 * class. This is not supported
401 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
403 * Returns a negative value if this resolving operation failed.
405 static int create_absolute_field_ref(ctf::sink::TraceIrToCtfIrCtx
*ctx
,
406 const bt_field_path
*tgt_ir_field_path
, GString
*tgt_field_ref
,
407 struct fs_sink_ctf_field_class
**user_tgt_fc
)
410 struct fs_sink_ctf_field_class
*fc
= NULL
;
413 switch (bt_field_path_get_root_scope(tgt_ir_field_path
)) {
414 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
415 BT_ASSERT(ctx
->cur_sc
);
416 fc
= ctx
->cur_sc
->packet_context_fc
;
417 g_string_assign(tgt_field_ref
, "stream.packet.context");
419 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
420 BT_ASSERT(ctx
->cur_sc
);
421 fc
= ctx
->cur_sc
->event_common_context_fc
;
422 g_string_assign(tgt_field_ref
, "stream.event.context");
424 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
425 BT_ASSERT(ctx
->cur_ec
);
426 fc
= ctx
->cur_ec
->spec_context_fc
;
427 g_string_assign(tgt_field_ref
, "event.context");
429 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
430 BT_ASSERT(ctx
->cur_ec
);
431 fc
= ctx
->cur_ec
->payload_fc
;
432 g_string_assign(tgt_field_ref
, "event.fields");
440 for (i
= 0; i
< bt_field_path_get_item_count(tgt_ir_field_path
); i
++) {
441 const bt_field_path_item
*fp_item
=
442 bt_field_path_borrow_item_by_index_const(tgt_ir_field_path
, i
);
443 struct fs_sink_ctf_named_field_class
*named_fc
= NULL
;
445 if (bt_field_path_item_get_type(fp_item
) != BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
446 /* Not supported by TSDL 1.8 */
452 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
453 BT_ASSERT(bt_field_path_item_get_type(fp_item
) == BT_FIELD_PATH_ITEM_TYPE_INDEX
);
454 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(
455 fs_sink_ctf_field_class_as_struct(fc
), bt_field_path_item_index_get_index(fp_item
));
457 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
458 BT_ASSERT(bt_field_path_item_get_type(fp_item
) == BT_FIELD_PATH_ITEM_TYPE_INDEX
);
459 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(
460 fs_sink_ctf_field_class_as_variant(fc
),
461 bt_field_path_item_index_get_index(fp_item
));
468 g_string_append_c(tgt_field_ref
, '.');
469 g_string_append(tgt_field_ref
, named_fc
->name
->str
);
482 * Resolves a target field class located at `tgt_ir_field_path`, writing
483 * the resolved field ref to `tgt_field_ref` and setting
484 * `*create_before` according to whether or not the target field must be
485 * created immediately before (in which case `tgt_field_ref` is
488 static void resolve_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
,
489 const bt_field_path
*tgt_ir_field_path
, GString
*tgt_field_ref
,
490 bool *create_before
, struct fs_sink_ctf_field_class
**user_tgt_fc
)
493 bt_field_path_scope tgt_scope
;
495 *create_before
= false;
497 if (!tgt_ir_field_path
) {
498 *create_before
= true;
502 tgt_scope
= bt_field_path_get_root_scope(tgt_ir_field_path
);
504 if (tgt_scope
== ctx
->cur_scope
) {
506 * Try, in this order:
508 * 1. Use a relative path, using only the target field
509 * class's name. This is what is the most commonly
510 * supported by popular CTF reading tools.
512 * 2. Use an absolute path. This could fail if there's
513 * an array field class from the current root's field
514 * class to the target field class.
516 * 3. Create the target field class before the
517 * requesting field class (fallback).
519 ret
= create_relative_field_ref(ctx
, tgt_ir_field_path
, tgt_field_ref
, user_tgt_fc
);
521 ret
= create_absolute_field_ref(ctx
, tgt_ir_field_path
, tgt_field_ref
, user_tgt_fc
);
523 *create_before
= true;
528 ret
= create_absolute_field_ref(ctx
, tgt_ir_field_path
, tgt_field_ref
, user_tgt_fc
);
530 /* It must always work in previous scopes */
538 static int translate_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
);
540 static inline void append_to_parent_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
,
541 struct fs_sink_ctf_field_class
*fc
)
543 struct fs_sink_ctf_field_class
*parent_fc
= cur_path_stack_top(ctx
)->parent_fc
;
545 switch (parent_fc
->type
) {
546 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
547 fs_sink_ctf_field_class_struct_append_member(fs_sink_ctf_field_class_as_struct(parent_fc
),
548 cur_path_stack_top(ctx
)->name
->str
, fc
);
550 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION
:
552 struct fs_sink_ctf_field_class_option
*opt_fc
=
553 fs_sink_ctf_field_class_as_option(parent_fc
);
555 BT_ASSERT(!opt_fc
->content_fc
);
556 opt_fc
->content_fc
= fc
;
557 opt_fc
->base
.alignment
= fc
->alignment
;
560 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
561 fs_sink_ctf_field_class_variant_append_option(fs_sink_ctf_field_class_as_variant(parent_fc
),
562 cur_path_stack_top(ctx
)->name
->str
, fc
);
564 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
565 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
567 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
568 fs_sink_ctf_field_class_as_array_base(parent_fc
);
570 BT_ASSERT(!array_base_fc
->elem_fc
);
571 array_base_fc
->elem_fc
= fc
;
572 array_base_fc
->base
.alignment
= fc
->alignment
;
580 static inline void update_parent_field_class_alignment(ctf::sink::TraceIrToCtfIrCtx
*ctx
,
581 unsigned int alignment
)
583 struct fs_sink_ctf_field_class
*parent_fc
= cur_path_stack_top(ctx
)->parent_fc
;
585 switch (parent_fc
->type
) {
586 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
587 fs_sink_ctf_field_class_struct_align_at_least(fs_sink_ctf_field_class_as_struct(parent_fc
),
590 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
591 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
593 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
594 fs_sink_ctf_field_class_as_array_base(parent_fc
);
596 array_base_fc
->base
.alignment
= alignment
;
605 translate_structure_field_class_members(ctf::sink::TraceIrToCtfIrCtx
*ctx
,
606 struct fs_sink_ctf_field_class_struct
*struct_fc
,
607 const bt_field_class
*ir_fc
)
612 for (i
= 0; i
< bt_field_class_structure_get_member_count(ir_fc
); i
++) {
613 const bt_field_class_structure_member
*member
;
615 const bt_field_class
*memb_ir_fc
;
617 member
= bt_field_class_structure_borrow_member_by_index_const(ir_fc
, i
);
618 name
= bt_field_class_structure_member_get_name(member
);
619 memb_ir_fc
= bt_field_class_structure_member_borrow_field_class_const(member
);
620 ret
= cur_path_stack_push(ctx
, name
, true, memb_ir_fc
, &struct_fc
->base
);
622 BT_CPPLOGE_SPEC(ctx
->logger
,
623 "Cannot translate structure field class member: "
629 ret
= translate_field_class(ctx
);
631 BT_CPPLOGE_SPEC(ctx
->logger
,
632 "Cannot translate structure field class member: "
638 cur_path_stack_pop(ctx
);
645 static inline int translate_structure_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
648 struct fs_sink_ctf_field_class_struct
*fc
=
649 fs_sink_ctf_field_class_struct_create_empty(cur_path_stack_top(ctx
)->ir_fc
);
652 append_to_parent_field_class(ctx
, &fc
->base
);
653 ret
= translate_structure_field_class_members(ctx
, fc
, fc
->base
.ir_fc
);
658 update_parent_field_class_alignment(ctx
, fc
->base
.alignment
);
665 * This function protects a given variant FC option name (with the `_`
666 * prefix) if required. On success, `name_buf->str` contains the variant
667 * FC option name to use (original option name or protected if
670 * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
671 * close as possible to an original CTF trace as decoded by
674 * This scenario is valid in CTF 1.8:
686 * Once in trace IR, the enumeration FC mapping names and variant FC
687 * option names are kept as is. For this reason, we don't want to
688 * protect the variant FC option names here (by prepending `_`): this
689 * would make the variant FC option name and the enumeration FC mapping
692 * This scenario is also valid in CTF 1.8:
704 * Once in trace IR, the enumeration FC mapping names are kept as is,
705 * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
706 * for presentation, as recommended by CTF 1.8). When going back to
707 * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
708 * the corresponding enumeration FC mapping name.
710 * This scenario is also valid in CTF 1.8:
722 * Once in trace IR, the enumeration FC mapping names are kept as is,
723 * but the `__HELLO` variant FC option name becomes `_HELLO`
724 * (unprotected). When going back to TSDL, we need to protect `_HELLO`
725 * so that it becomes `__HELLO` to match the corresponding enumeration
728 * `src.ctf.fs` always uses the _same_ integer range sets for a selector
729 * FC mapping and a corresponding variant FC option. We can use that
730 * fact to find the original variant FC option names by matching variant
731 * FC options and enumeration FC mappings by range set.
733 static int maybe_protect_variant_option_name(const bt_field_class
*ir_var_fc
,
734 const bt_field_class
*ir_tag_fc
, uint64_t opt_i
,
739 bt_field_class_type ir_var_fc_type
;
740 const bt_integer_range_set_unsigned
*opt_ranges_unsigned
= NULL
;
741 const bt_integer_range_set_signed
*opt_ranges_signed
= NULL
;
742 const char *mapping_label
= NULL
;
743 const char *ir_opt_name
;
744 const bt_field_class_variant_option
*base_var_opt
;
745 bool force_protect
= false;
747 ir_var_fc_type
= bt_field_class_get_type(ir_var_fc
);
748 base_var_opt
= bt_field_class_variant_borrow_option_by_index_const(ir_var_fc
, opt_i
);
749 BT_ASSERT(base_var_opt
);
750 ir_opt_name
= bt_field_class_variant_option_get_name(base_var_opt
);
751 BT_ASSERT(ir_opt_name
);
754 * Check if the variant FC option name is required to be
755 * protected (reserved TSDL keyword or starts with `_`). In that
756 * case, the name of the selector FC mapping we find must match
757 * exactly the protected name.
759 force_protect
= must_protect_identifier(ir_opt_name
);
761 g_string_assign(name_buf
, "_");
762 g_string_append(name_buf
, ir_opt_name
);
764 g_string_assign(name_buf
, ir_opt_name
);
767 /* Borrow option's ranges */
768 if (ir_var_fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD
) {
769 /* No ranges: we're done */
772 if (ir_var_fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
773 const bt_field_class_variant_with_selector_field_integer_unsigned_option
*var_opt
=
774 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
776 opt_ranges_unsigned
=
777 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
780 const bt_field_class_variant_with_selector_field_integer_signed_option
*var_opt
=
781 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
784 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
788 /* Find corresponding mapping by range set in selector FC */
789 for (i
= 0; i
< bt_field_class_enumeration_get_mapping_count(ir_tag_fc
); i
++) {
790 if (ir_var_fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
791 const bt_field_class_enumeration_mapping
*mapping_base
;
792 const bt_field_class_enumeration_unsigned_mapping
*mapping
;
793 const bt_integer_range_set_unsigned
*mapping_ranges
;
796 bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(ir_tag_fc
, i
);
798 bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(mapping
);
800 if (bt_integer_range_set_unsigned_is_equal(opt_ranges_unsigned
, mapping_ranges
)) {
801 /* We have a winner */
803 bt_field_class_enumeration_unsigned_mapping_as_mapping_const(mapping
);
804 mapping_label
= bt_field_class_enumeration_mapping_get_label(mapping_base
);
808 const bt_field_class_enumeration_mapping
*mapping_base
;
809 const bt_field_class_enumeration_signed_mapping
*mapping
;
810 const bt_integer_range_set_signed
*mapping_ranges
;
812 mapping
= bt_field_class_enumeration_signed_borrow_mapping_by_index_const(ir_tag_fc
, i
);
813 mapping_ranges
= bt_field_class_enumeration_signed_mapping_borrow_ranges_const(mapping
);
815 if (bt_integer_range_set_signed_is_equal(opt_ranges_signed
, mapping_ranges
)) {
816 /* We have a winner */
817 mapping_base
= bt_field_class_enumeration_signed_mapping_as_mapping_const(mapping
);
818 mapping_label
= bt_field_class_enumeration_mapping_get_label(mapping_base
);
824 if (!mapping_label
) {
825 /* Range set not found: invalid selector for CTF 1.8 */
831 * If the enumeration FC mapping name is not the same as the
832 * variant FC option name and we didn't protect already, try
833 * protecting the option name and check again.
835 if (strcmp(mapping_label
, name_buf
->str
) != 0) {
841 if (mapping_label
[0] == '\0') {
846 g_string_assign(name_buf
, "_");
847 g_string_append(name_buf
, ir_opt_name
);
849 if (strcmp(mapping_label
, name_buf
->str
) != 0) {
859 static inline int translate_option_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
861 struct fs_sink_ctf_field_class_option
*fc
=
862 fs_sink_ctf_field_class_option_create_empty(cur_path_stack_top(ctx
)->ir_fc
);
863 const bt_field_class
*content_ir_fc
=
864 bt_field_class_option_borrow_field_class_const(fc
->base
.ir_fc
);
870 * CTF 1.8 does not support the option field class type. To
871 * write something anyway, this component translates this type
872 * to a variant field class where the options are:
874 * * An empty structure field class.
875 * * The optional field class itself.
877 * The "tag" is always generated/before in that case (an 8-bit
878 * unsigned enumeration field class).
880 append_to_parent_field_class(ctx
, &fc
->base
);
881 ret
= cur_path_stack_push(ctx
, NULL
, false, content_ir_fc
, &fc
->base
);
883 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate option field class content.");
887 ret
= translate_field_class(ctx
);
889 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate option field class content.");
893 cur_path_stack_pop(ctx
);
894 update_parent_field_class_alignment(ctx
, fc
->base
.alignment
);
900 static inline int translate_variant_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
904 struct fs_sink_ctf_field_class_variant
*fc
=
905 fs_sink_ctf_field_class_variant_create_empty(cur_path_stack_top(ctx
)->ir_fc
);
906 bt_field_class_type ir_fc_type
;
907 const bt_field_path
*ir_selector_field_path
= NULL
;
908 struct fs_sink_ctf_field_class
*tgt_fc
= NULL
;
909 GString
*name_buf
= g_string_new(NULL
);
910 bt_value
*prot_opt_names
= bt_value_array_create();
915 BT_ASSERT(prot_opt_names
);
916 ir_fc_type
= bt_field_class_get_type(fc
->base
.ir_fc
);
917 opt_count
= bt_field_class_variant_get_option_count(fc
->base
.ir_fc
);
919 if (bt_field_class_type_is(ir_fc_type
, BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
920 ir_selector_field_path
=
921 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
923 BT_ASSERT(ir_selector_field_path
);
926 /* Resolve tag field class before appending to parent */
927 resolve_field_class(ctx
, ir_selector_field_path
, fc
->tag_ref
, &fc
->tag_is_before
, &tgt_fc
);
929 if (ir_selector_field_path
&& tgt_fc
) {
930 uint64_t mapping_count
;
931 uint64_t option_count
;
933 /* CTF 1.8: selector FC must be an enumeration FC */
934 bt_field_class_type type
= bt_field_class_get_type(tgt_fc
->ir_fc
);
936 if (!bt_field_class_type_is(type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
937 fc
->tag_is_before
= true;
942 * Call maybe_protect_variant_option_name() for each
943 * option below. In that case we also want selector FC
944 * to contain as many mappings as the variant FC has
947 mapping_count
= bt_field_class_enumeration_get_mapping_count(tgt_fc
->ir_fc
);
948 option_count
= bt_field_class_variant_get_option_count(fc
->base
.ir_fc
);
950 if (mapping_count
!= option_count
) {
951 fc
->tag_is_before
= true;
956 * No compatible selector field class for CTF 1.8:
957 * create the appropriate selector field class.
959 fc
->tag_is_before
= true;
965 * First pass: detect any option name clash with option name
966 * protection. In that case, we don't fail: just create the
967 * selector field class before the variant field class.
969 * After this, `prot_opt_names` contains the final option names,
970 * potentially protected if needed. They can still be invalid
971 * TSDL identifiers however; this will be checked by
972 * cur_path_stack_push().
974 for (i
= 0; i
< opt_count
; i
++) {
975 if (!fc
->tag_is_before
) {
976 BT_ASSERT(tgt_fc
->ir_fc
);
977 ret
= maybe_protect_variant_option_name(fc
->base
.ir_fc
, tgt_fc
->ir_fc
, i
, name_buf
);
979 fc
->tag_is_before
= true;
983 ret
= bt_value_array_append_string_element(prot_opt_names
, name_buf
->str
);
989 for (i
= 0; i
< opt_count
; i
++) {
991 const bt_value
*opt_name_a
=
992 bt_value_array_borrow_element_by_index_const(prot_opt_names
, i
);
994 for (j
= 0; j
< opt_count
; j
++) {
995 const bt_value
*opt_name_b
;
1001 opt_name_b
= bt_value_array_borrow_element_by_index_const(prot_opt_names
, j
);
1002 if (bt_value_is_equal(opt_name_a
, opt_name_b
)) {
1004 * Variant FC option names are not
1005 * unique when protected.
1007 fc
->tag_is_before
= true;
1008 goto append_to_parent
;
1014 append_to_parent_field_class(ctx
, &fc
->base
);
1016 for (i
= 0; i
< opt_count
; i
++) {
1017 const bt_field_class_variant_option
*opt
;
1018 const bt_field_class
*opt_ir_fc
;
1019 const bt_value
*prot_opt_name_val
=
1020 bt_value_array_borrow_element_by_index_const(prot_opt_names
, i
);
1021 const char *prot_opt_name
= bt_value_string_get(prot_opt_name_val
);
1023 BT_ASSERT(prot_opt_name
);
1024 opt
= bt_field_class_variant_borrow_option_by_index_const(fc
->base
.ir_fc
, i
);
1025 opt_ir_fc
= bt_field_class_variant_option_borrow_field_class_const(opt
);
1028 * We don't ask cur_path_stack_push() to protect the
1029 * option name because it's already protected at this
1032 ret
= cur_path_stack_push(ctx
, prot_opt_name
, false, opt_ir_fc
, &fc
->base
);
1034 BT_CPPLOGE_SPEC(ctx
->logger
,
1035 "Cannot translate variant field class option: "
1041 ret
= translate_field_class(ctx
);
1043 BT_CPPLOGE_SPEC(ctx
->logger
,
1044 "Cannot translate variant field class option: "
1050 cur_path_stack_pop(ctx
);
1055 g_string_free(name_buf
, TRUE
);
1058 bt_value_put_ref(prot_opt_names
);
1062 static inline int translate_static_array_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1064 struct fs_sink_ctf_field_class_array
*fc
=
1065 fs_sink_ctf_field_class_array_create_empty(cur_path_stack_top(ctx
)->ir_fc
);
1066 const bt_field_class
*elem_ir_fc
=
1067 bt_field_class_array_borrow_element_field_class_const(fc
->base
.base
.ir_fc
);
1071 append_to_parent_field_class(ctx
, &fc
->base
.base
);
1072 ret
= cur_path_stack_push(ctx
, NULL
, false, elem_ir_fc
, &fc
->base
.base
);
1074 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate static array field class element.");
1078 ret
= translate_field_class(ctx
);
1080 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate static array field class element.");
1084 cur_path_stack_pop(ctx
);
1085 update_parent_field_class_alignment(ctx
, fc
->base
.base
.alignment
);
1091 static inline int translate_dynamic_array_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1093 struct fs_sink_ctf_field_class_sequence
*fc
=
1094 fs_sink_ctf_field_class_sequence_create_empty(cur_path_stack_top(ctx
)->ir_fc
);
1095 const bt_field_class
*elem_ir_fc
=
1096 bt_field_class_array_borrow_element_field_class_const(fc
->base
.base
.ir_fc
);
1101 /* Resolve length field class before appending to parent */
1102 if (bt_field_class_get_type(cur_path_stack_top(ctx
)->ir_fc
) ==
1103 BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
1104 resolve_field_class(
1106 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1107 fc
->base
.base
.ir_fc
),
1108 fc
->length_ref
, &fc
->length_is_before
, NULL
);
1111 append_to_parent_field_class(ctx
, &fc
->base
.base
);
1112 ret
= cur_path_stack_push(ctx
, NULL
, false, elem_ir_fc
, &fc
->base
.base
);
1114 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate dynamic array field class element.");
1118 ret
= translate_field_class(ctx
);
1120 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate dynamic array field class element.");
1124 cur_path_stack_pop(ctx
);
1125 update_parent_field_class_alignment(ctx
, fc
->base
.base
.alignment
);
1131 static inline int translate_bool_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1133 struct fs_sink_ctf_field_class_bool
*fc
=
1134 fs_sink_ctf_field_class_bool_create(cur_path_stack_top(ctx
)->ir_fc
);
1137 append_to_parent_field_class(ctx
, &fc
->base
.base
);
1141 static inline int translate_bit_array_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1143 struct fs_sink_ctf_field_class_bit_array
*fc
=
1144 fs_sink_ctf_field_class_bit_array_create(cur_path_stack_top(ctx
)->ir_fc
);
1147 append_to_parent_field_class(ctx
, &fc
->base
);
1151 static inline int translate_integer_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1153 struct fs_sink_ctf_field_class_int
*fc
=
1154 fs_sink_ctf_field_class_int_create(cur_path_stack_top(ctx
)->ir_fc
);
1157 append_to_parent_field_class(ctx
, &fc
->base
.base
);
1161 static inline int translate_real_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1163 struct fs_sink_ctf_field_class_float
*fc
=
1164 fs_sink_ctf_field_class_float_create(cur_path_stack_top(ctx
)->ir_fc
);
1167 append_to_parent_field_class(ctx
, &fc
->base
.base
);
1171 static inline int translate_string_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1173 struct fs_sink_ctf_field_class_string
*fc
=
1174 fs_sink_ctf_field_class_string_create(cur_path_stack_top(ctx
)->ir_fc
);
1177 append_to_parent_field_class(ctx
, &fc
->base
);
1182 * Translates a field class, recursively.
1184 * The field class's IR field class, parent field class, and index
1185 * within its parent are in the context's current path's top element
1186 * (cur_path_stack_top()).
1188 static int translate_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1191 bt_field_class_type ir_fc_type
= bt_field_class_get_type(cur_path_stack_top(ctx
)->ir_fc
);
1193 if (ir_fc_type
== BT_FIELD_CLASS_TYPE_BOOL
) {
1194 ret
= translate_bool_field_class(ctx
);
1195 } else if (ir_fc_type
== BT_FIELD_CLASS_TYPE_BIT_ARRAY
) {
1196 ret
= translate_bit_array_field_class(ctx
);
1197 } else if (bt_field_class_type_is(ir_fc_type
, BT_FIELD_CLASS_TYPE_INTEGER
)) {
1198 ret
= translate_integer_field_class(ctx
);
1199 } else if (bt_field_class_type_is(ir_fc_type
, BT_FIELD_CLASS_TYPE_REAL
)) {
1200 ret
= translate_real_field_class(ctx
);
1201 } else if (ir_fc_type
== BT_FIELD_CLASS_TYPE_STRING
) {
1202 ret
= translate_string_field_class(ctx
);
1203 } else if (ir_fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1204 ret
= translate_structure_field_class(ctx
);
1205 } else if (ir_fc_type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
) {
1206 ret
= translate_static_array_field_class(ctx
);
1207 } else if (bt_field_class_type_is(ir_fc_type
, BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
)) {
1208 ret
= translate_dynamic_array_field_class(ctx
);
1209 } else if (bt_field_class_type_is(ir_fc_type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
1210 ret
= translate_option_field_class(ctx
);
1211 } else if (bt_field_class_type_is(ir_fc_type
, BT_FIELD_CLASS_TYPE_VARIANT
)) {
1212 ret
= translate_variant_field_class(ctx
);
1220 static int set_field_ref(struct fs_sink_ctf_field_class
*fc
, const char *fc_name
,
1221 struct fs_sink_ctf_field_class
*parent_fc
)
1224 GString
*field_ref
= NULL
;
1226 const char *tgt_type
;
1227 struct fs_sink_ctf_field_class_struct
*parent_struct_fc
=
1228 fs_sink_ctf_field_class_as_struct(parent_fc
);
1230 unsigned int suffix
= 0;
1232 if (!fc_name
|| !parent_fc
|| parent_fc
->type
!= FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
1239 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION
:
1242 * CTF 1.8 does not support the option field class type.
1243 * To write something anyway, this component translates
1244 * this type to a variant field class where the options
1247 * * An empty structure field class.
1248 * * The optional field class itself.
1250 * Because the option field class becomes a CTF variant
1251 * field class, we use the term "tag" too here.
1253 * The "tag" is always generated/before in that case (an
1254 * 8-bit unsigned enumeration field class).
1256 struct fs_sink_ctf_field_class_option
*opt_fc
= fs_sink_ctf_field_class_as_option(fc
);
1258 field_ref
= opt_fc
->tag_ref
;
1263 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1265 struct fs_sink_ctf_field_class_sequence
*seq_fc
= fs_sink_ctf_field_class_as_sequence(fc
);
1267 field_ref
= seq_fc
->length_ref
;
1268 is_before
= seq_fc
->length_is_before
;
1272 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
1274 struct fs_sink_ctf_field_class_variant
*var_fc
= fs_sink_ctf_field_class_as_variant(fc
);
1276 field_ref
= var_fc
->tag_ref
;
1277 is_before
= var_fc
->tag_is_before
;
1285 BT_ASSERT(field_ref
);
1291 /* Initial field ref */
1292 g_string_printf(field_ref
, "__%s_%s", fc_name
, tgt_type
);
1295 * Make sure field ref does not clash with an existing field
1296 * class name within the same parent structure field class.
1299 bool name_ok
= true;
1301 for (i
= 0; i
< parent_struct_fc
->members
->len
; i
++) {
1302 struct fs_sink_ctf_named_field_class
*named_fc
=
1303 fs_sink_ctf_field_class_struct_borrow_member_by_index(parent_struct_fc
, i
);
1305 if (strcmp(field_ref
->str
, named_fc
->name
->str
) == 0) {
1313 /* No clash: we're done */
1317 /* Append suffix and try again */
1318 g_string_printf(field_ref
, "__%s_%s_%u", fc_name
, tgt_type
, suffix
);
1327 * This function recursively sets field refs of sequence and variant
1328 * field classes when they are immediately before, avoiding name clashes
1329 * with existing field class names.
1331 * It can fail at this point if, for example, a sequence field class of
1332 * which to set the length's field ref has something else than a
1333 * structure field class as its parent: in this case, there's no
1334 * location to place the length field class immediately before the
1335 * sequence field class.
1337 static int set_field_refs(struct fs_sink_ctf_field_class
* const fc
, const char *fc_name
,
1338 struct fs_sink_ctf_field_class
*parent_fc
)
1341 enum fs_sink_ctf_field_class_type fc_type
;
1347 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION
:
1349 struct fs_sink_ctf_field_class_option
*opt_fc
= fs_sink_ctf_field_class_as_option(fc
);
1351 ret
= set_field_ref(fc
, fc_name
, parent_fc
);
1356 ret
= set_field_refs(opt_fc
->content_fc
, NULL
, fc
);
1363 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
1364 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
1368 struct fs_sink_ctf_field_class_struct
*struct_fc
= NULL
;
1369 struct fs_sink_ctf_field_class_variant
*var_fc
= NULL
;
1370 struct fs_sink_ctf_named_field_class
*named_fc
;
1372 if (fc_type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
1373 struct_fc
= fs_sink_ctf_field_class_as_struct(fc
);
1374 len
= struct_fc
->members
->len
;
1376 var_fc
= fs_sink_ctf_field_class_as_variant(fc
);
1377 len
= var_fc
->options
->len
;
1378 ret
= set_field_ref(fc
, fc_name
, parent_fc
);
1384 for (i
= 0; i
< len
; i
++) {
1385 if (fc_type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
1386 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(struct_fc
, i
);
1388 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(var_fc
, i
);
1391 ret
= set_field_refs(named_fc
->fc
, named_fc
->name
->str
, fc
);
1399 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
1400 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1402 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
1403 fs_sink_ctf_field_class_as_array_base(fc
);
1405 if (fc_type
== FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
1406 ret
= set_field_ref(fc
, fc_name
, parent_fc
);
1412 ret
= set_field_refs(array_base_fc
->elem_fc
, NULL
, fc
);
1428 * This function translates a root scope trace IR field class to
1429 * a CTF IR field class.
1431 * The resulting CTF IR field class is written to `*fc` so that it
1432 * exists as the parent object's (stream class or event class) true root
1433 * field class during the recursive translation for resolving purposes.
1434 * This is also why this function creates the empty structure field
1435 * class and then calls translate_structure_field_class_members() to
1438 static int translate_scope_field_class(ctf::sink::TraceIrToCtfIrCtx
*ctx
, bt_field_path_scope scope
,
1439 struct fs_sink_ctf_field_class
**fc
,
1440 const bt_field_class
*ir_fc
)
1448 BT_ASSERT(bt_field_class_get_type(ir_fc
) == BT_FIELD_CLASS_TYPE_STRUCTURE
);
1450 *fc
= &fs_sink_ctf_field_class_struct_create_empty(ir_fc
)->base
;
1452 ctx
->cur_scope
= scope
;
1453 BT_ASSERT(ctx
->cur_path
->len
== 0);
1454 ret
= cur_path_stack_push(ctx
, NULL
, false, ir_fc
, NULL
);
1456 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate scope structure field class: scope={}",
1457 static_cast<bt2::FieldPathScope
>(scope
));
1462 translate_structure_field_class_members(ctx
, fs_sink_ctf_field_class_as_struct(*fc
), ir_fc
);
1464 BT_CPPLOGE_SPEC(ctx
->logger
, "Cannot translate scope structure field class: scope={}",
1465 static_cast<bt2::FieldPathScope
>(scope
));
1469 cur_path_stack_pop(ctx
);
1471 /* Set field refs for preceding targets */
1472 ret
= set_field_refs(*fc
, NULL
, NULL
);
1478 static inline void ctx_init(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1480 ctx
->cur_path
= g_array_new(FALSE
, TRUE
, sizeof(struct field_path_elem
));
1481 BT_ASSERT(ctx
->cur_path
);
1484 static inline void ctx_fini(ctf::sink::TraceIrToCtfIrCtx
*ctx
)
1486 if (ctx
->cur_path
) {
1487 g_array_free(ctx
->cur_path
, TRUE
);
1488 ctx
->cur_path
= NULL
;
1492 static int translate_event_class(struct fs_sink_comp
*fs_sink
, struct fs_sink_ctf_stream_class
*sc
,
1493 const bt_event_class
*ir_ec
,
1494 struct fs_sink_ctf_event_class
**out_ec
)
1497 ctf::sink::TraceIrToCtfIrCtx ctx
{fs_sink
->logger
};
1498 struct fs_sink_ctf_event_class
*ec
;
1504 ec
= fs_sink_ctf_event_class_create(sc
, ir_ec
);
1508 ret
= translate_scope_field_class(
1509 &ctx
, BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, &ec
->spec_context_fc
,
1510 bt_event_class_borrow_specific_context_field_class_const(ir_ec
));
1515 ret
= translate_scope_field_class(&ctx
, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
, &ec
->payload_fc
,
1516 bt_event_class_borrow_payload_field_class_const(ir_ec
));
1527 int try_translate_event_class_trace_ir_to_ctf_ir(struct fs_sink_comp
*fs_sink
,
1528 struct fs_sink_ctf_stream_class
*sc
,
1529 const bt_event_class
*ir_ec
,
1530 struct fs_sink_ctf_event_class
**out_ec
)
1537 /* Check in hash table first */
1538 *out_ec
= (fs_sink_ctf_event_class
*) g_hash_table_lookup(sc
->event_classes_from_ir
, ir_ec
);
1539 if (G_LIKELY(*out_ec
)) {
1543 ret
= translate_event_class(fs_sink
, sc
, ir_ec
, out_ec
);
1549 static bool default_clock_class_name_exists(struct fs_sink_ctf_trace
*trace
, const char *name
)
1551 bool exists
= false;
1554 for (i
= 0; i
< trace
->stream_classes
->len
; i
++) {
1555 struct fs_sink_ctf_stream_class
*sc
=
1556 (fs_sink_ctf_stream_class
*) trace
->stream_classes
->pdata
[i
];
1558 if (sc
->default_clock_class_name
->len
== 0) {
1559 /* No default clock class */
1563 if (strcmp(sc
->default_clock_class_name
->str
, name
) == 0) {
1573 static void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class
*sc
)
1575 unsigned int suffix
= 0;
1577 std::string name
= "default";
1579 while (default_clock_class_name_exists(sc
->trace
, name
.c_str())) {
1580 name
= "default" + std::to_string(suffix
);
1584 g_string_assign(sc
->default_clock_class_name
, name
.c_str());
1587 static int translate_stream_class(struct fs_sink_comp
*fs_sink
, struct fs_sink_ctf_trace
*trace
,
1588 const bt_stream_class
*ir_sc
,
1589 struct fs_sink_ctf_stream_class
**out_sc
)
1592 ctf::sink::TraceIrToCtfIrCtx ctx
{fs_sink
->logger
};
1597 *out_sc
= fs_sink_ctf_stream_class_create(trace
, ir_sc
);
1600 /* Set default clock class's protected name, if any */
1601 if ((*out_sc
)->default_clock_class
) {
1602 const char *name
= bt_clock_class_get_name((*out_sc
)->default_clock_class
);
1605 /* Try original name, protected */
1606 g_string_assign((*out_sc
)->default_clock_class_name
, "");
1608 if (must_protect_identifier(name
)) {
1609 g_string_assign((*out_sc
)->default_clock_class_name
, "_");
1612 g_string_assign((*out_sc
)->default_clock_class_name
, name
);
1613 if (!ist_valid_identifier((*out_sc
)->default_clock_class_name
->str
)) {
1614 /* Invalid: create a new name */
1615 make_unique_default_clock_class_name(*out_sc
);
1618 /* No name: create a name */
1619 make_unique_default_clock_class_name(*out_sc
);
1623 ctx
.cur_sc
= *out_sc
;
1624 ret
= translate_scope_field_class(
1625 &ctx
, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
, &(*out_sc
)->packet_context_fc
,
1626 bt_stream_class_borrow_packet_context_field_class_const(ir_sc
));
1631 if ((*out_sc
)->packet_context_fc
) {
1633 * Make sure the structure field class's alignment is
1634 * enough: 8 is what we use for our own special members
1635 * in the packet context.
1637 fs_sink_ctf_field_class_struct_align_at_least(
1638 fs_sink_ctf_field_class_as_struct((*out_sc
)->packet_context_fc
), 8);
1641 ret
= translate_scope_field_class(
1642 &ctx
, BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, &(*out_sc
)->event_common_context_fc
,
1643 bt_stream_class_borrow_event_common_context_field_class_const(ir_sc
));
1651 fs_sink_ctf_stream_class_destroy(*out_sc
);
1659 int try_translate_stream_class_trace_ir_to_ctf_ir(struct fs_sink_comp
*fs_sink
,
1660 struct fs_sink_ctf_trace
*trace
,
1661 const bt_stream_class
*ir_sc
,
1662 struct fs_sink_ctf_stream_class
**out_sc
)
1670 for (i
= 0; i
< trace
->stream_classes
->len
; i
++) {
1671 *out_sc
= (fs_sink_ctf_stream_class
*) trace
->stream_classes
->pdata
[i
];
1673 if ((*out_sc
)->ir_sc
== ir_sc
) {
1678 ret
= translate_stream_class(fs_sink
, trace
, ir_sc
, out_sc
);
1684 struct fs_sink_ctf_trace
*translate_trace_trace_ir_to_ctf_ir(struct fs_sink_comp
*fs_sink
,
1685 const bt_trace
*ir_trace
)
1689 struct fs_sink_ctf_trace
*trace
= NULL
;
1691 /* Check that trace's environment is TSDL-compatible */
1692 count
= bt_trace_get_environment_entry_count(ir_trace
);
1693 for (i
= 0; i
< count
; i
++) {
1695 const bt_value
*val
;
1697 bt_trace_borrow_environment_entry_by_index_const(ir_trace
, i
, &name
, &val
);
1699 if (!ist_valid_identifier(name
)) {
1700 BT_CPPLOGE_SPEC(fs_sink
->logger
,
1701 "Unsupported trace class's environment entry name: "
1707 switch (bt_value_get_type(val
)) {
1708 case BT_VALUE_TYPE_SIGNED_INTEGER
:
1709 case BT_VALUE_TYPE_STRING
:
1712 BT_CPPLOGE_SPEC(fs_sink
->logger
,
1713 "Unsupported trace class's environment entry value type: "
1715 static_cast<bt2::ValueType
>(bt_value_get_type(val
)));
1720 trace
= fs_sink_ctf_trace_create(ir_trace
);