2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
23 #define BT_LOG_OUTPUT_LEVEL (ctx->log_level)
24 #define BT_LOG_TAG "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"
25 #include "logging/log.h"
27 #include <babeltrace2/babeltrace.h>
28 #include "common/macros.h"
29 #include "common/common.h"
30 #include "common/assert.h"
36 #include "fs-sink-ctf-meta.h"
38 struct field_path_elem
{
39 uint64_t index_in_parent
;
43 const bt_field_class
*ir_fc
;
46 struct fs_sink_ctf_field_class
*parent_fc
;
50 bt_logging_level log_level
;
53 struct fs_sink_ctf_stream_class
*cur_sc
;
56 struct fs_sink_ctf_event_class
*cur_ec
;
61 * Array of `struct field_path_elem` */
66 struct field_path_elem
*cur_path_stack_at(struct ctx
*ctx
, uint64_t i
)
68 BT_ASSERT(i
< ctx
->cur_path
->len
);
69 return &g_array_index(ctx
->cur_path
, struct field_path_elem
, i
);
73 struct field_path_elem
*cur_path_stack_top(struct ctx
*ctx
)
75 BT_ASSERT(ctx
->cur_path
->len
> 0);
76 return cur_path_stack_at(ctx
, ctx
->cur_path
->len
- 1);
80 bool is_reserved_member_name(const char *name
, const char *reserved_name
)
82 bool is_reserved
= false;
84 if (strcmp(name
, reserved_name
) == 0) {
89 if (name
[0] == '_' && strcmp(&name
[1], reserved_name
) == 0) {
99 int cur_path_stack_push(struct ctx
*ctx
,
100 uint64_t index_in_parent
, const char *ir_name
,
101 const bt_field_class
*ir_fc
,
102 struct fs_sink_ctf_field_class
*parent_fc
)
105 struct field_path_elem
*field_path_elem
;
107 g_array_set_size(ctx
->cur_path
, ctx
->cur_path
->len
+ 1);
108 field_path_elem
= cur_path_stack_top(ctx
);
109 field_path_elem
->index_in_parent
= index_in_parent
;
110 field_path_elem
->name
= g_string_new(ir_name
);
113 if (ctx
->cur_scope
== BT_SCOPE_PACKET_CONTEXT
) {
114 if (is_reserved_member_name(ir_name
, "packet_size") ||
115 is_reserved_member_name(ir_name
, "content_size") ||
116 is_reserved_member_name(ir_name
, "timestamp_begin") ||
117 is_reserved_member_name(ir_name
, "timestamp_end") ||
118 is_reserved_member_name(ir_name
, "events_discarded") ||
119 is_reserved_member_name(ir_name
, "packet_seq_num")) {
120 BT_LOGE("Unsupported reserved TSDL structure field class member "
121 "or variant field class option name: name=\"%s\"",
128 ret
= fs_sink_ctf_protect_name(field_path_elem
->name
);
130 BT_LOGE("Unsupported non-TSDL structure field class member "
131 "or variant field class option name: name=\"%s\"",
137 field_path_elem
->ir_fc
= ir_fc
;
138 field_path_elem
->parent_fc
= parent_fc
;
145 void cur_path_stack_pop(struct ctx
*ctx
)
147 struct field_path_elem
*field_path_elem
;
149 BT_ASSERT(ctx
->cur_path
->len
> 0);
150 field_path_elem
= cur_path_stack_top(ctx
);
152 if (field_path_elem
->name
) {
153 g_string_free(field_path_elem
->name
, TRUE
);
154 field_path_elem
->name
= NULL
;
157 g_array_set_size(ctx
->cur_path
, ctx
->cur_path
->len
- 1);
161 * Creates a relative field ref (a single name) from IR field path
162 * `tgt_ir_field_path`.
164 * This function tries to locate the target field class recursively from
165 * the top to the bottom of the context's current path using only the
166 * target field class's own name. This is because many CTF reading tools
167 * do not support a relative field ref with more than one element, for
168 * example `prev_struct.len`.
170 * Returns a negative value if this resolving operation failed.
173 int create_relative_field_ref(struct ctx
*ctx
,
174 const bt_field_path
*tgt_ir_field_path
, GString
*tgt_field_ref
)
177 struct fs_sink_ctf_field_class
*tgt_fc
= NULL
;
180 const char *tgt_fc_name
= NULL
;
181 struct field_path_elem
*field_path_elem
;
183 /* Get target field class's name */
184 switch (bt_field_path_get_root_scope(tgt_ir_field_path
)) {
185 case BT_SCOPE_PACKET_CONTEXT
:
186 BT_ASSERT(ctx
->cur_sc
);
187 tgt_fc
= ctx
->cur_sc
->packet_context_fc
;
189 case BT_SCOPE_EVENT_COMMON_CONTEXT
:
190 BT_ASSERT(ctx
->cur_sc
);
191 tgt_fc
= ctx
->cur_sc
->event_common_context_fc
;
193 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT
:
194 BT_ASSERT(ctx
->cur_ec
);
195 tgt_fc
= ctx
->cur_ec
->spec_context_fc
;
197 case BT_SCOPE_EVENT_PAYLOAD
:
198 BT_ASSERT(ctx
->cur_ec
);
199 tgt_fc
= ctx
->cur_ec
->payload_fc
;
207 while (i
< bt_field_path_get_item_count(tgt_ir_field_path
)) {
208 const bt_field_path_item
*fp_item
=
209 bt_field_path_borrow_item_by_index_const(
210 tgt_ir_field_path
, i
);
211 struct fs_sink_ctf_named_field_class
*named_fc
= NULL
;
216 switch (tgt_fc
->type
) {
217 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
218 BT_ASSERT(bt_field_path_item_get_type(fp_item
) ==
219 BT_FIELD_PATH_ITEM_TYPE_INDEX
);
220 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(
222 bt_field_path_item_index_get_index(fp_item
));
224 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
225 BT_ASSERT(bt_field_path_item_get_type(fp_item
) ==
226 BT_FIELD_PATH_ITEM_TYPE_INDEX
);
227 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(
229 bt_field_path_item_index_get_index(fp_item
));
231 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
232 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
234 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
237 BT_ASSERT(bt_field_path_item_get_type(fp_item
) ==
238 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
239 tgt_fc
= array_base_fc
->elem_fc
;
247 tgt_fc
= named_fc
->fc
;
248 tgt_fc_name
= named_fc
->name
->str
;
254 BT_ASSERT(tgt_fc
->type
== FS_SINK_CTF_FIELD_CLASS_TYPE_INT
);
255 BT_ASSERT(tgt_fc_name
);
257 /* Find target field class having this name in current context */
258 for (si
= ctx
->cur_path
->len
- 1; si
>= 0; si
--) {
259 struct fs_sink_ctf_field_class
*fc
;
260 struct fs_sink_ctf_field_class_struct
*struct_fc
;
261 struct fs_sink_ctf_field_class_variant
*var_fc
;
262 struct fs_sink_ctf_named_field_class
*named_fc
;
265 field_path_elem
= cur_path_stack_at(ctx
, (uint64_t) si
);
266 fc
= field_path_elem
->parent_fc
;
268 /* Reached stack's bottom */
274 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
275 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
277 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
278 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
281 /* Not supported by TSDL 1.8 */
286 if (fc
->type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
287 struct_fc
= (void *) fc
;
288 len
= struct_fc
->members
->len
;
290 var_fc
= (void *) fc
;
291 len
= var_fc
->options
->len
;
294 for (i
= 0; i
< len
; i
++) {
295 if (fc
->type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
296 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(
299 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(
303 if (strcmp(named_fc
->name
->str
, tgt_fc_name
) == 0) {
304 if (named_fc
->fc
== tgt_fc
) {
305 g_string_assign(tgt_field_ref
,
309 * Using only the target field
310 * class's name, we're not
311 * reaching the target field
312 * class. This is not supported
328 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
330 * Returns a negative value if this resolving operation failed.
333 int create_absolute_field_ref(struct ctx
*ctx
,
334 const bt_field_path
*tgt_ir_field_path
, GString
*tgt_field_ref
)
337 struct fs_sink_ctf_field_class
*fc
= NULL
;
340 switch (bt_field_path_get_root_scope(tgt_ir_field_path
)) {
341 case BT_SCOPE_PACKET_CONTEXT
:
342 BT_ASSERT(ctx
->cur_sc
);
343 fc
= ctx
->cur_sc
->packet_context_fc
;
344 g_string_assign(tgt_field_ref
, "stream.packet.context");
346 case BT_SCOPE_EVENT_COMMON_CONTEXT
:
347 BT_ASSERT(ctx
->cur_sc
);
348 fc
= ctx
->cur_sc
->event_common_context_fc
;
349 g_string_assign(tgt_field_ref
, "stream.event.context");
351 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT
:
352 BT_ASSERT(ctx
->cur_ec
);
353 fc
= ctx
->cur_ec
->spec_context_fc
;
354 g_string_assign(tgt_field_ref
, "event.context");
356 case BT_SCOPE_EVENT_PAYLOAD
:
357 BT_ASSERT(ctx
->cur_ec
);
358 fc
= ctx
->cur_ec
->payload_fc
;
359 g_string_assign(tgt_field_ref
, "event.fields");
367 for (i
= 0; i
< bt_field_path_get_item_count(tgt_ir_field_path
); i
++) {
368 const bt_field_path_item
*fp_item
=
369 bt_field_path_borrow_item_by_index_const(
370 tgt_ir_field_path
, i
);
371 struct fs_sink_ctf_named_field_class
*named_fc
= NULL
;
373 if (bt_field_path_item_get_type(fp_item
) !=
374 BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
375 /* Not supported by TSDL 1.8 */
381 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
382 BT_ASSERT(bt_field_path_item_get_type(fp_item
) ==
383 BT_FIELD_PATH_ITEM_TYPE_INDEX
);
384 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(
386 bt_field_path_item_index_get_index(fp_item
));
388 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
389 BT_ASSERT(bt_field_path_item_get_type(fp_item
) ==
390 BT_FIELD_PATH_ITEM_TYPE_INDEX
);
391 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(
393 bt_field_path_item_index_get_index(fp_item
));
400 g_string_append_c(tgt_field_ref
, '.');
401 g_string_append(tgt_field_ref
, named_fc
->name
->str
);
410 * Resolves a target field class located at `tgt_ir_field_path`, writing
411 * the resolved field ref to `tgt_field_ref` and setting
412 * `*create_before` according to whether or not the target field must be
413 * created immediately before (in which case `tgt_field_ref` is
417 void resolve_field_class(struct ctx
*ctx
,
418 const bt_field_path
*tgt_ir_field_path
,
419 GString
*tgt_field_ref
, bool *create_before
)
424 *create_before
= false;
426 if (!tgt_ir_field_path
) {
427 *create_before
= true;
431 tgt_scope
= bt_field_path_get_root_scope(tgt_ir_field_path
);
433 if (tgt_scope
== ctx
->cur_scope
) {
435 * Try, in this order:
437 * 1. Use a relative path, using only the target field
438 * class's name. This is what is the most commonly
439 * supported by popular CTF reading tools.
441 * 2. Use an absolute path. This could fail if there's
442 * an array field class from the current root's field
443 * class to the target field class.
445 * 3. Create the target field class before the
446 * requesting field class (fallback).
448 ret
= create_relative_field_ref(ctx
, tgt_ir_field_path
,
451 ret
= create_absolute_field_ref(ctx
, tgt_ir_field_path
,
454 *create_before
= true;
460 ret
= create_absolute_field_ref(ctx
, tgt_ir_field_path
,
463 /* It must always work in previous scopes */
472 int translate_field_class(struct ctx
*ctx
);
475 void append_to_parent_field_class(struct ctx
*ctx
,
476 struct fs_sink_ctf_field_class
*fc
)
478 struct fs_sink_ctf_field_class
*parent_fc
=
479 cur_path_stack_top(ctx
)->parent_fc
;
481 switch (parent_fc
->type
) {
482 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
483 fs_sink_ctf_field_class_struct_append_member((void *) parent_fc
,
484 cur_path_stack_top(ctx
)->name
->str
, fc
);
486 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
487 fs_sink_ctf_field_class_variant_append_option((void *) parent_fc
,
488 cur_path_stack_top(ctx
)->name
->str
, fc
);
490 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
491 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
493 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
496 BT_ASSERT(!array_base_fc
->elem_fc
);
497 array_base_fc
->elem_fc
= fc
;
498 array_base_fc
->base
.alignment
= fc
->alignment
;
507 void update_parent_field_class_alignment(struct ctx
*ctx
,
508 unsigned int alignment
)
510 struct fs_sink_ctf_field_class
*parent_fc
=
511 cur_path_stack_top(ctx
)->parent_fc
;
513 switch (parent_fc
->type
) {
514 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
515 fs_sink_ctf_field_class_struct_align_at_least(
516 (void *) parent_fc
, alignment
);
518 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
519 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
521 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
524 array_base_fc
->base
.alignment
= alignment
;
533 int translate_structure_field_class_members(struct ctx
*ctx
,
534 struct fs_sink_ctf_field_class_struct
*struct_fc
,
535 const bt_field_class
*ir_fc
)
540 for (i
= 0; i
< bt_field_class_structure_get_member_count(ir_fc
); i
++) {
541 const bt_field_class_structure_member
*member
;
543 const bt_field_class
*memb_ir_fc
;
546 bt_field_class_structure_borrow_member_by_index_const(
548 name
= bt_field_class_structure_member_get_name(member
);
549 memb_ir_fc
= bt_field_class_structure_member_borrow_field_class_const(
551 ret
= cur_path_stack_push(ctx
, i
, name
, memb_ir_fc
,
554 BT_LOGE("Cannot translate structure field class member: "
555 "name=\"%s\"", name
);
559 ret
= translate_field_class(ctx
);
561 BT_LOGE("Cannot translate structure field class member: "
562 "name=\"%s\"", name
);
566 cur_path_stack_pop(ctx
);
574 int translate_structure_field_class(struct ctx
*ctx
)
577 struct fs_sink_ctf_field_class_struct
*fc
=
578 fs_sink_ctf_field_class_struct_create_empty(
579 cur_path_stack_top(ctx
)->ir_fc
,
580 cur_path_stack_top(ctx
)->index_in_parent
);
583 append_to_parent_field_class(ctx
, (void *) fc
);
584 ret
= translate_structure_field_class_members(ctx
, fc
, fc
->base
.ir_fc
);
589 update_parent_field_class_alignment(ctx
, fc
->base
.alignment
);
596 int translate_variant_field_class(struct ctx
*ctx
)
600 struct fs_sink_ctf_field_class_variant
*fc
=
601 fs_sink_ctf_field_class_variant_create_empty(
602 cur_path_stack_top(ctx
)->ir_fc
,
603 cur_path_stack_top(ctx
)->index_in_parent
);
607 /* Resolve tag field class before appending to parent */
608 resolve_field_class(ctx
,
609 bt_field_class_variant_borrow_selector_field_path_const(
610 fc
->base
.ir_fc
), fc
->tag_ref
, &fc
->tag_is_before
);
612 append_to_parent_field_class(ctx
, (void *) fc
);
614 for (i
= 0; i
< bt_field_class_variant_get_option_count(fc
->base
.ir_fc
);
616 const bt_field_class_variant_option
*opt
;
618 const bt_field_class
*opt_ir_fc
;
620 opt
= bt_field_class_variant_borrow_option_by_index_const(
622 name
= bt_field_class_variant_option_get_name(opt
);
623 opt_ir_fc
= bt_field_class_variant_option_borrow_field_class_const(
625 ret
= cur_path_stack_push(ctx
, i
, name
, opt_ir_fc
, (void *) fc
);
627 BT_LOGE("Cannot translate variant field class option: "
628 "name=\"%s\"", name
);
632 ret
= translate_field_class(ctx
);
634 BT_LOGE("Cannot translate variant field class option: "
635 "name=\"%s\"", name
);
639 cur_path_stack_pop(ctx
);
647 int translate_static_array_field_class(struct ctx
*ctx
)
649 struct fs_sink_ctf_field_class_array
*fc
=
650 fs_sink_ctf_field_class_array_create_empty(
651 cur_path_stack_top(ctx
)->ir_fc
,
652 cur_path_stack_top(ctx
)->index_in_parent
);
653 const bt_field_class
*elem_ir_fc
=
654 bt_field_class_array_borrow_element_field_class_const(
655 fc
->base
.base
.ir_fc
);
659 append_to_parent_field_class(ctx
, (void *) fc
);
660 ret
= cur_path_stack_push(ctx
, UINT64_C(-1), NULL
, elem_ir_fc
,
663 BT_LOGE_STR("Cannot translate static array field class element.");
667 ret
= translate_field_class(ctx
);
669 BT_LOGE_STR("Cannot translate static array field class element.");
673 cur_path_stack_pop(ctx
);
674 update_parent_field_class_alignment(ctx
, fc
->base
.base
.alignment
);
681 int translate_dynamic_array_field_class(struct ctx
*ctx
)
683 struct fs_sink_ctf_field_class_sequence
*fc
=
684 fs_sink_ctf_field_class_sequence_create_empty(
685 cur_path_stack_top(ctx
)->ir_fc
,
686 cur_path_stack_top(ctx
)->index_in_parent
);
687 const bt_field_class
*elem_ir_fc
=
688 bt_field_class_array_borrow_element_field_class_const(
689 fc
->base
.base
.ir_fc
);
694 /* Resolve length field class before appending to parent */
695 resolve_field_class(ctx
,
696 bt_field_class_dynamic_array_borrow_length_field_path_const(
697 fc
->base
.base
.ir_fc
),
698 fc
->length_ref
, &fc
->length_is_before
);
700 append_to_parent_field_class(ctx
, (void *) fc
);
701 ret
= cur_path_stack_push(ctx
, UINT64_C(-1), NULL
, elem_ir_fc
,
704 BT_LOGE_STR("Cannot translate dynamic array field class element.");
708 ret
= translate_field_class(ctx
);
710 BT_LOGE_STR("Cannot translate dynamic array field class element.");
714 cur_path_stack_pop(ctx
);
715 update_parent_field_class_alignment(ctx
, fc
->base
.base
.alignment
);
722 int translate_integer_field_class(struct ctx
*ctx
)
724 struct fs_sink_ctf_field_class_int
*fc
=
725 fs_sink_ctf_field_class_int_create(
726 cur_path_stack_top(ctx
)->ir_fc
,
727 cur_path_stack_top(ctx
)->index_in_parent
);
730 append_to_parent_field_class(ctx
, (void *) fc
);
735 int translate_real_field_class(struct ctx
*ctx
)
737 struct fs_sink_ctf_field_class_float
*fc
=
738 fs_sink_ctf_field_class_float_create(
739 cur_path_stack_top(ctx
)->ir_fc
,
740 cur_path_stack_top(ctx
)->index_in_parent
);
743 append_to_parent_field_class(ctx
, (void *) fc
);
748 int translate_string_field_class(struct ctx
*ctx
)
750 struct fs_sink_ctf_field_class_string
*fc
=
751 fs_sink_ctf_field_class_string_create(
752 cur_path_stack_top(ctx
)->ir_fc
,
753 cur_path_stack_top(ctx
)->index_in_parent
);
756 append_to_parent_field_class(ctx
, (void *) fc
);
761 * Translates a field class, recursively.
763 * The field class's IR field class, parent field class, and index
764 * within its parent are in the context's current path's top element
765 * (cur_path_stack_top()).
768 int translate_field_class(struct ctx
*ctx
)
772 switch (bt_field_class_get_type(cur_path_stack_top(ctx
)->ir_fc
)) {
773 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
:
774 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER
:
775 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION
:
776 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
:
777 ret
= translate_integer_field_class(ctx
);
779 case BT_FIELD_CLASS_TYPE_REAL
:
780 ret
= translate_real_field_class(ctx
);
782 case BT_FIELD_CLASS_TYPE_STRING
:
783 ret
= translate_string_field_class(ctx
);
785 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
786 ret
= translate_structure_field_class(ctx
);
788 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
789 ret
= translate_static_array_field_class(ctx
);
791 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
792 ret
= translate_dynamic_array_field_class(ctx
);
794 case BT_FIELD_CLASS_TYPE_VARIANT
:
795 ret
= translate_variant_field_class(ctx
);
805 int set_field_ref(struct fs_sink_ctf_field_class
*fc
, const char *fc_name
,
806 struct fs_sink_ctf_field_class
*parent_fc
)
809 GString
*field_ref
= NULL
;
811 const char *tgt_type
;
812 struct fs_sink_ctf_field_class_struct
*parent_struct_fc
=
815 unsigned int suffix
= 0;
817 if (!fc_name
|| !parent_fc
||
818 parent_fc
->type
!= FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
825 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
827 struct fs_sink_ctf_field_class_sequence
*seq_fc
= (void *) fc
;
829 field_ref
= seq_fc
->length_ref
;
830 is_before
= seq_fc
->length_is_before
;
834 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
836 struct fs_sink_ctf_field_class_variant
*var_fc
= (void *) fc
;
838 field_ref
= var_fc
->tag_ref
;
839 is_before
= var_fc
->tag_is_before
;
847 BT_ASSERT(field_ref
);
853 /* Initial field ref */
854 g_string_printf(field_ref
, "__%s_%s", fc_name
, tgt_type
);
857 * Make sure field ref does not clash with an existing field
858 * class name within the same parent structure field class.
863 for (i
= 0; i
< parent_struct_fc
->members
->len
; i
++) {
864 struct fs_sink_ctf_named_field_class
*named_fc
=
865 fs_sink_ctf_field_class_struct_borrow_member_by_index(
866 parent_struct_fc
, i
);
868 if (strcmp(field_ref
->str
, named_fc
->name
->str
) == 0) {
876 /* No clash: we're done */
880 /* Append suffix and try again */
881 g_string_printf(field_ref
, "__%s_%s_%u", fc_name
, tgt_type
,
891 * This function recursively sets field refs of sequence and variant
892 * field classes when they are immediately before, avoiding name clashes
893 * with existing field class names.
895 * It can fail at this point if, for example, a sequence field class of
896 * which to set the length's field ref has something else than a
897 * structure field class as its parent: in this case, there's no
898 * location to place the length field class immediately before the
899 * sequence field class.
902 int set_field_refs(struct fs_sink_ctf_field_class
* const fc
,
903 const char *fc_name
, struct fs_sink_ctf_field_class
*parent_fc
)
906 enum fs_sink_ctf_field_class_type fc_type
;
912 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
:
913 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT
:
917 struct fs_sink_ctf_field_class_struct
*struct_fc
;
918 struct fs_sink_ctf_field_class_variant
*var_fc
= NULL
;
919 struct fs_sink_ctf_named_field_class
*named_fc
;
921 if (fc_type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
922 struct_fc
= (void *) fc
;
923 len
= struct_fc
->members
->len
;
925 var_fc
= (void *) fc
;
926 len
= var_fc
->options
->len
;
927 ret
= set_field_ref(fc
, fc_name
, parent_fc
);
933 for (i
= 0; i
< len
; i
++) {
934 if (fc_type
== FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT
) {
935 named_fc
= fs_sink_ctf_field_class_struct_borrow_member_by_index(
938 named_fc
= fs_sink_ctf_field_class_variant_borrow_option_by_index(
942 ret
= set_field_refs(named_fc
->fc
, named_fc
->name
->str
,
951 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY
:
952 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
:
954 struct fs_sink_ctf_field_class_array_base
*array_base_fc
=
957 if (fc_type
== FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
958 ret
= set_field_ref(fc
, fc_name
, parent_fc
);
964 ret
= set_field_refs(array_base_fc
->elem_fc
, NULL
, fc
);
980 * This function translates a root scope trace IR field class to
981 * a CTF IR field class.
983 * The resulting CTF IR field class is written to `*fc` so that it
984 * exists as the parent object's (stream class or event class) true root
985 * field class during the recursive translation for resolving purposes.
986 * This is also why this function creates the empty structure field
987 * class and then calls translate_structure_field_class_members() to
991 int translate_scope_field_class(struct ctx
*ctx
, bt_scope scope
,
992 struct fs_sink_ctf_field_class
**fc
,
993 const bt_field_class
*ir_fc
)
1001 BT_ASSERT(bt_field_class_get_type(ir_fc
) ==
1002 BT_FIELD_CLASS_TYPE_STRUCTURE
);
1004 *fc
= (void *) fs_sink_ctf_field_class_struct_create_empty(
1005 ir_fc
, UINT64_C(-1));
1007 ctx
->cur_scope
= scope
;
1008 BT_ASSERT(ctx
->cur_path
->len
== 0);
1009 ret
= cur_path_stack_push(ctx
, UINT64_C(-1), NULL
, ir_fc
, NULL
);
1011 BT_LOGE("Cannot translate scope structure field class: "
1016 ret
= translate_structure_field_class_members(ctx
, (void *) *fc
, ir_fc
);
1018 BT_LOGE("Cannot translate scope structure field class: "
1023 cur_path_stack_pop(ctx
);
1025 /* Set field refs for preceding targets */
1026 ret
= set_field_refs(*fc
, NULL
, NULL
);
1033 void ctx_init(struct ctx
*ctx
, bt_logging_level log_level
)
1035 memset(ctx
, 0, sizeof(struct ctx
));
1036 ctx
->cur_path
= g_array_new(FALSE
, TRUE
,
1037 sizeof(struct field_path_elem
));
1038 BT_ASSERT(ctx
->cur_path
);
1039 ctx
->log_level
= log_level
;
1043 void ctx_fini(struct ctx
*ctx
)
1045 if (ctx
->cur_path
) {
1046 g_array_free(ctx
->cur_path
, TRUE
);
1047 ctx
->cur_path
= NULL
;
1052 int translate_event_class(struct fs_sink_ctf_stream_class
*sc
,
1053 const bt_event_class
*ir_ec
,
1054 struct fs_sink_ctf_event_class
**out_ec
,
1055 bt_logging_level log_level
)
1059 struct fs_sink_ctf_event_class
*ec
;
1064 ctx_init(&ctx
, log_level
);
1065 ec
= fs_sink_ctf_event_class_create(sc
, ir_ec
);
1069 ret
= translate_scope_field_class(&ctx
, BT_SCOPE_EVENT_SPECIFIC_CONTEXT
,
1070 &ec
->spec_context_fc
,
1071 bt_event_class_borrow_specific_context_field_class_const(
1077 ret
= translate_scope_field_class(&ctx
, BT_SCOPE_EVENT_PAYLOAD
,
1079 bt_event_class_borrow_payload_field_class_const(ir_ec
));
1091 int try_translate_event_class_trace_ir_to_ctf_ir(
1092 struct fs_sink_ctf_stream_class
*sc
,
1093 const bt_event_class
*ir_ec
,
1094 struct fs_sink_ctf_event_class
**out_ec
,
1095 bt_logging_level log_level
)
1102 /* Check in hash table first */
1103 *out_ec
= g_hash_table_lookup(sc
->event_classes_from_ir
, ir_ec
);
1104 if (G_LIKELY(*out_ec
)) {
1108 ret
= translate_event_class(sc
, ir_ec
, out_ec
, log_level
);
1114 bool default_clock_class_name_exists(struct fs_sink_ctf_trace_class
*tc
,
1117 bool exists
= false;
1120 for (i
= 0; i
< tc
->stream_classes
->len
; i
++) {
1121 struct fs_sink_ctf_stream_class
*sc
=
1122 tc
->stream_classes
->pdata
[i
];
1124 if (sc
->default_clock_class_name
->len
== 0) {
1125 /* No default clock class */
1129 if (strcmp(sc
->default_clock_class_name
->str
, name
) == 0) {
1140 void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class
*sc
)
1142 unsigned int suffix
= 0;
1145 g_string_assign(sc
->default_clock_class_name
, "");
1146 sprintf(buf
, "default");
1148 while (default_clock_class_name_exists(sc
->tc
, buf
)) {
1149 sprintf(buf
, "default%u", suffix
);
1153 g_string_assign(sc
->default_clock_class_name
, buf
);
1157 int translate_stream_class(struct fs_sink_ctf_trace_class
*tc
,
1158 const bt_stream_class
*ir_sc
,
1159 struct fs_sink_ctf_stream_class
**out_sc
,
1160 bt_logging_level log_level
)
1167 ctx_init(&ctx
, log_level
);
1168 *out_sc
= fs_sink_ctf_stream_class_create(tc
, ir_sc
);
1171 /* Set default clock class's protected name, if any */
1172 if ((*out_sc
)->default_clock_class
) {
1173 const char *name
= bt_clock_class_get_name(
1174 (*out_sc
)->default_clock_class
);
1177 /* Try original name, protected */
1178 g_string_assign((*out_sc
)->default_clock_class_name
,
1180 ret
= fs_sink_ctf_protect_name(
1181 (*out_sc
)->default_clock_class_name
);
1183 /* Invalid: create a new name */
1184 make_unique_default_clock_class_name(*out_sc
);
1188 /* No name: create a name */
1189 make_unique_default_clock_class_name(*out_sc
);
1193 ctx
.cur_sc
= *out_sc
;
1194 ret
= translate_scope_field_class(&ctx
, BT_SCOPE_PACKET_CONTEXT
,
1195 &(*out_sc
)->packet_context_fc
,
1196 bt_stream_class_borrow_packet_context_field_class_const(ir_sc
));
1201 if ((*out_sc
)->packet_context_fc
) {
1203 * Make sure the structure field class's alignment is
1204 * enough: 8 is what we use for our own special members
1205 * in the packet context.
1207 fs_sink_ctf_field_class_struct_align_at_least(
1208 (void *) (*out_sc
)->packet_context_fc
, 8);
1211 ret
= translate_scope_field_class(&ctx
, BT_SCOPE_EVENT_COMMON_CONTEXT
,
1212 &(*out_sc
)->event_common_context_fc
,
1213 bt_stream_class_borrow_event_common_context_field_class_const(
1222 fs_sink_ctf_stream_class_destroy(*out_sc
);
1231 int try_translate_stream_class_trace_ir_to_ctf_ir(
1232 struct fs_sink_ctf_trace_class
*tc
,
1233 const bt_stream_class
*ir_sc
,
1234 struct fs_sink_ctf_stream_class
**out_sc
,
1235 bt_logging_level log_level
)
1243 for (i
= 0; i
< tc
->stream_classes
->len
; i
++) {
1244 *out_sc
= tc
->stream_classes
->pdata
[i
];
1246 if ((*out_sc
)->ir_sc
== ir_sc
) {
1251 ret
= translate_stream_class(tc
, ir_sc
, out_sc
, log_level
);
1258 struct fs_sink_ctf_trace_class
*translate_trace_class_trace_ir_to_ctf_ir(
1259 const bt_trace_class
*ir_tc
, bt_logging_level log_level
)
1263 struct fs_sink_ctf_trace_class
*tc
= NULL
;
1265 /* Check that trace class's environment is TSDL-compatible */
1266 count
= bt_trace_class_get_environment_entry_count(ir_tc
);
1267 for (i
= 0; i
< count
; i
++) {
1269 const bt_value
*val
;
1271 bt_trace_class_borrow_environment_entry_by_index_const(
1272 ir_tc
, i
, &name
, &val
);
1274 if (!fs_sink_ctf_ist_valid_identifier(name
)) {
1275 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
,
1277 "Unsupported trace class's environment entry name: "
1278 "name=\"%s\"", name
);
1282 switch (bt_value_get_type(val
)) {
1283 case BT_VALUE_TYPE_SIGNED_INTEGER
:
1284 case BT_VALUE_TYPE_STRING
:
1287 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
,
1289 "Unsupported trace class's environment entry value type: "
1291 bt_common_value_type_string(
1292 bt_value_get_type(val
)));
1297 tc
= fs_sink_ctf_trace_class_create(ir_tc
);