2 * SPDX-License-Identifier: MIT
4 * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
16 #include <babeltrace2/babeltrace.h>
18 #define BT_COMP_LOG_SELF_COMP (ctx->self_comp)
19 #define BT_COMP_LOG_SELF_COMP_CLASS (ctx->self_comp_class)
20 #define BT_LOG_OUTPUT_LEVEL (ctx->log_level)
21 #define BT_LOG_TAG "PLUGIN/CTF/META/RESOLVE"
22 #include "logging.hpp"
23 #include "logging/comp-logging.h"
25 #include "common/assert.h"
26 #include "common/common.h"
27 #include "common/macros.h"
29 #include "ctf-meta-visitors.hpp"
31 using field_class_stack_t
= GPtrArray
;
36 * `fc` contains a compound field class (structure, variant, array,
37 * or sequence) and `index` indicates the index of the field class in
38 * the upper frame (-1 for array and sequence field classes). `name`
39 * indicates the name of the field class in the upper frame (empty
40 * string for array and sequence field classes).
42 struct field_class_stack_frame
44 struct ctf_field_class
*fc
;
49 * The current context of the resolving engine.
51 struct resolve_context
53 bt_logging_level log_level
;
55 /* Weak, exactly one of these must be set */
56 bt_self_component
*self_comp
;
57 bt_self_component_class
*self_comp_class
;
59 struct ctf_trace_class
*tc
;
60 struct ctf_stream_class
*sc
;
61 struct ctf_event_class
*ec
;
65 struct ctf_field_class
*packet_header
;
66 struct ctf_field_class
*packet_context
;
67 struct ctf_field_class
*event_header
;
68 struct ctf_field_class
*event_common_context
;
69 struct ctf_field_class
*event_spec_context
;
70 struct ctf_field_class
*event_payload
;
73 /* Root scope being visited */
74 enum ctf_scope root_scope
;
75 field_class_stack_t
*field_class_stack
;
76 struct ctf_field_class
*cur_fc
;
79 /* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
80 static const char * const absolute_path_prefixes
[] = {
81 /* CTF_SCOPE_PACKET_HEADER */ "trace.packet.header.",
82 /* CTF_SCOPE_PACKET_CONTEXT */ "stream.packet.context.",
83 /* CTF_SCOPE_EVENT_HEADER */ "stream.event.header.",
84 /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ "stream.event.context.",
85 /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ "event.context.",
86 /* CTF_SCOPE_EVENT_PAYLOAD */ "event.fields.",
89 /* Number of path tokens used for the absolute prefixes */
90 static const uint64_t absolute_path_prefix_ptoken_counts
[] = {
91 /* CTF_SCOPE_PACKET_HEADER */ 3,
92 /* CTF_SCOPE_PACKET_CONTEXT */ 3,
93 /* CTF_SCOPE_EVENT_HEADER */ 3,
94 /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ 3,
95 /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ 2,
96 /* CTF_SCOPE_EVENT_PAYLOAD */ 2,
99 static void destroy_field_class_stack_frame(struct field_class_stack_frame
*frame
)
109 * Creates a class stack.
111 static field_class_stack_t
*field_class_stack_create(void)
113 return g_ptr_array_new_with_free_func((GDestroyNotify
) destroy_field_class_stack_frame
);
117 * Destroys a class stack.
119 static void field_class_stack_destroy(field_class_stack_t
*stack
)
122 g_ptr_array_free(stack
, TRUE
);
127 * Pushes a field class onto a class stack.
129 static int field_class_stack_push(field_class_stack_t
*stack
, struct ctf_field_class
*fc
,
130 struct resolve_context
*ctx
)
133 struct field_class_stack_frame
*frame
= NULL
;
136 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
137 "Invalid parameter: stack or field class is `NULL`.");
142 frame
= g_new0(struct field_class_stack_frame
, 1);
144 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one field class stack frame.");
149 BT_COMP_LOGD("Pushing field class on context's stack: "
150 "fc-addr=%p, stack-size-before=%u",
153 g_ptr_array_add(stack
, frame
);
160 * Checks whether or not `stack` is empty.
162 static bool field_class_stack_empty(field_class_stack_t
*stack
)
164 return stack
->len
== 0;
168 * Returns the number of frames in `stack`.
170 static size_t field_class_stack_size(field_class_stack_t
*stack
)
176 * Returns the top frame of `stack`.
178 static struct field_class_stack_frame
*field_class_stack_peek(field_class_stack_t
*stack
)
181 BT_ASSERT(!field_class_stack_empty(stack
));
183 return (field_class_stack_frame
*) g_ptr_array_index(stack
, stack
->len
- 1);
187 * Returns the frame at index `index` in `stack`.
189 static struct field_class_stack_frame
*field_class_stack_at(field_class_stack_t
*stack
,
193 BT_ASSERT(index
< stack
->len
);
195 return (field_class_stack_frame
*) g_ptr_array_index(stack
, index
);
199 * Removes the top frame of `stack`.
201 static void field_class_stack_pop(field_class_stack_t
*stack
, struct resolve_context
*ctx
)
203 if (!field_class_stack_empty(stack
)) {
205 * This will call the frame's destructor and free it, as
206 * well as put its contained field class.
208 BT_COMP_LOGD("Popping context's stack: stack-size-before=%u", stack
->len
);
209 g_ptr_array_set_size(stack
, stack
->len
- 1);
214 * Returns the scope field class of `scope` in the context `ctx`.
216 static struct ctf_field_class
*borrow_class_from_ctx(struct resolve_context
*ctx
,
217 enum ctf_scope scope
)
220 case CTF_SCOPE_PACKET_HEADER
:
221 return ctx
->scopes
.packet_header
;
222 case CTF_SCOPE_PACKET_CONTEXT
:
223 return ctx
->scopes
.packet_context
;
224 case CTF_SCOPE_EVENT_HEADER
:
225 return ctx
->scopes
.event_header
;
226 case CTF_SCOPE_EVENT_COMMON_CONTEXT
:
227 return ctx
->scopes
.event_common_context
;
228 case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT
:
229 return ctx
->scopes
.event_spec_context
;
230 case CTF_SCOPE_EVENT_PAYLOAD
:
231 return ctx
->scopes
.event_payload
;
240 * Returns the CTF scope from a path string. May return -1 if the path
241 * is found to be relative.
243 static enum ctf_scope
get_root_scope_from_absolute_pathstr(const char *pathstr
,
244 struct resolve_context
*ctx
)
246 enum ctf_scope scope
;
247 enum ctf_scope ret
= CTF_SCOPE_PACKET_UNKNOWN
;
248 const size_t prefixes_count
= sizeof(absolute_path_prefixes
) / sizeof(*absolute_path_prefixes
);
250 for (scope
= CTF_SCOPE_PACKET_HEADER
; scope
< CTF_SCOPE_PACKET_HEADER
+ prefixes_count
;
251 scope
= (ctf_scope
) (scope
+ 1)) {
253 * Check if path string starts with a known absolute
256 * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
258 if (strncmp(pathstr
, absolute_path_prefixes
[scope
],
259 strlen(absolute_path_prefixes
[scope
]))) {
260 /* Prefix does not match: try the next one */
261 BT_COMP_LOGD("Prefix does not match: trying the next one: "
262 "path=\"%s\", path-prefix=\"%s\", scope=%s",
263 pathstr
, absolute_path_prefixes
[scope
], ctf_scope_string(scope
));
269 BT_COMP_LOGD("Found root scope from absolute path: "
270 "path=\"%s\", scope=%s",
271 pathstr
, ctf_scope_string(scope
));
280 * Destroys a path token.
282 static void ptokens_destroy_func(gpointer ptoken
, gpointer
)
284 g_string_free((GString
*) ptoken
, TRUE
);
288 * Destroys a path token list.
290 static void ptokens_destroy(GList
*ptokens
)
296 g_list_foreach(ptokens
, ptokens_destroy_func
, NULL
);
297 g_list_free(ptokens
);
301 * Returns the string contained in a path token.
303 static const char *ptoken_get_string(GList
*ptoken
)
305 GString
*tokenstr
= (GString
*) ptoken
->data
;
307 return tokenstr
->str
;
311 * Converts a path string to a path token list, that is, splits the
312 * individual words of a path string into a list of individual
315 static GList
*pathstr_to_ptokens(const char *pathstr
, struct resolve_context
*ctx
)
317 const char *at
= pathstr
;
318 const char *last
= at
;
319 GList
*ptokens
= NULL
;
322 if (*at
== '.' || *at
== '\0') {
326 /* Error: empty token */
327 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Empty path token: path=\"%s\", pos=%u",
328 pathstr
, (unsigned int) (at
- pathstr
));
332 tokenstr
= g_string_new(NULL
);
333 g_string_append_len(tokenstr
, last
, at
- last
);
334 ptokens
= g_list_append(ptokens
, tokenstr
);
348 ptokens_destroy(ptokens
);
353 * Converts a path token list to a field path object. The path token
354 * list is relative from `fc`. The index of the source looking for its
355 * target within `fc` is indicated by `src_index`. This can be
356 * `INT64_MAX` if the source is contained in `fc`.
358 * `field_path` is an output parameter owned by the caller that must be
361 static int ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
362 struct ctf_field_class
*fc
, int64_t src_index
,
363 struct resolve_context
*ctx
)
366 GList
*cur_ptoken
= ptokens
;
367 bool first_level_done
= false;
372 struct ctf_field_class
*child_fc
;
373 const char *ft_name
= ptoken_get_string(cur_ptoken
);
375 BT_COMP_LOGD("Current path token: token=\"%s\"", ft_name
);
377 /* Find to which index corresponds the current path token */
378 if (fc
->type
== CTF_FIELD_CLASS_TYPE_ARRAY
|| fc
->type
== CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
382 ctf_field_class_compound_get_field_class_index_from_orig_name(fc
, ft_name
);
383 if (child_index
< 0) {
385 * Error: field name does not exist or
386 * wrong current class.
388 BT_COMP_LOGD("Cannot get index of field class: "
389 "field-name=\"%s\", "
390 "src-index=%" PRId64
", "
391 "child-index=%" PRId64
", "
392 "first-level-done=%d",
393 ft_name
, src_index
, child_index
, first_level_done
);
396 } else if (child_index
> src_index
&& !first_level_done
) {
397 BT_COMP_LOGD("Child field class is located after source field class: "
398 "field-name=\"%s\", "
399 "src-index=%" PRId64
", "
400 "child-index=%" PRId64
", "
401 "first-level-done=%d",
402 ft_name
, src_index
, child_index
, first_level_done
);
407 /* Next path token */
408 cur_ptoken
= g_list_next(cur_ptoken
);
409 first_level_done
= true;
412 /* Create new field path entry */
413 ctf_field_path_append_index(field_path
, child_index
);
415 /* Get child field class */
416 child_fc
= ctf_field_class_compound_borrow_field_class_by_index(fc
, child_index
);
419 /* Move child class to current class */
428 * Converts a known absolute path token list to a field path object
429 * within the resolving context `ctx`.
431 * `field_path` is an output parameter owned by the caller that must be
434 static int absolute_ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
435 struct resolve_context
*ctx
)
439 struct ctf_field_class
*fc
;
442 * Make sure we're not referring to a scope within a translated
445 switch (field_path
->root
) {
446 case CTF_SCOPE_PACKET_HEADER
:
447 if (ctx
->tc
->is_translated
) {
448 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Trace class is already translated: "
450 ctf_scope_string(field_path
->root
));
456 case CTF_SCOPE_PACKET_CONTEXT
:
457 case CTF_SCOPE_EVENT_HEADER
:
458 case CTF_SCOPE_EVENT_COMMON_CONTEXT
:
460 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current stream class: "
462 ctf_scope_string(field_path
->root
));
467 if (ctx
->sc
->is_translated
) {
468 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class is already translated: "
470 ctf_scope_string(field_path
->root
));
476 case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT
:
477 case CTF_SCOPE_EVENT_PAYLOAD
:
479 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current event class: "
481 ctf_scope_string(field_path
->root
));
486 if (ctx
->ec
->is_translated
) {
487 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Event class is already translated: "
489 ctf_scope_string(field_path
->root
));
500 /* Skip absolute path tokens */
501 cur_ptoken
= g_list_nth(ptokens
, absolute_path_prefix_ptoken_counts
[field_path
->root
]);
503 /* Start with root class */
504 fc
= borrow_class_from_ctx(ctx
, field_path
->root
);
506 /* Error: root class is not available */
507 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: "
509 ctf_scope_string(field_path
->root
));
515 ret
= ptokens_to_field_path(cur_ptoken
, field_path
, fc
, INT64_MAX
, ctx
);
522 * Converts a known relative path token list to a field path object
523 * within the resolving context `ctx`.
525 * `field_path` is an output parameter owned by the caller that must be
528 static int relative_ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
529 struct resolve_context
*ctx
)
532 int64_t parent_pos_in_stack
;
533 struct ctf_field_path tail_field_path
;
535 ctf_field_path_init(&tail_field_path
);
536 parent_pos_in_stack
= field_class_stack_size(ctx
->field_class_stack
) - 1;
538 while (parent_pos_in_stack
>= 0) {
539 struct ctf_field_class
*parent_class
=
540 field_class_stack_at(ctx
->field_class_stack
, parent_pos_in_stack
)->fc
;
542 field_class_stack_at(ctx
->field_class_stack
, parent_pos_in_stack
)->index
;
544 BT_COMP_LOGD("Locating target field class from current parent field class: "
545 "parent-pos=%" PRId64
", parent-fc-addr=%p, "
546 "cur-index=%" PRId64
,
547 parent_pos_in_stack
, parent_class
, cur_index
);
549 /* Locate target from current parent class */
550 ret
= ptokens_to_field_path(ptokens
, &tail_field_path
, parent_class
, cur_index
, ctx
);
552 /* Not found... yet */
553 BT_COMP_LOGD_STR("Not found at this point.");
554 ctf_field_path_clear(&tail_field_path
);
556 /* Found: stitch tail field path to head field path */
558 size_t tail_field_path_len
= tail_field_path
.path
->len
;
561 struct ctf_field_class
*cur_class
=
562 field_class_stack_at(ctx
->field_class_stack
, i
)->fc
;
563 int64_t index
= field_class_stack_at(ctx
->field_class_stack
, i
)->index
;
565 if (cur_class
== parent_class
) {
569 ctf_field_path_append_index(field_path
, index
);
573 for (i
= 0; i
< tail_field_path_len
; i
++) {
574 int64_t index
= ctf_field_path_borrow_index_by_index(&tail_field_path
, i
);
576 ctf_field_path_append_index(field_path
, (int64_t) index
);
581 parent_pos_in_stack
--;
584 if (parent_pos_in_stack
< 0) {
589 ctf_field_path_fini(&tail_field_path
);
594 * Converts a path string to a field path object within the resolving
597 static int pathstr_to_field_path(const char *pathstr
, struct ctf_field_path
*field_path
,
598 struct resolve_context
*ctx
)
601 enum ctf_scope root_scope
;
602 GList
*ptokens
= NULL
;
604 /* Convert path string to path tokens */
605 ptokens
= pathstr_to_ptokens(pathstr
, ctx
);
607 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot convert path string to path tokens: "
614 /* Absolute or relative path? */
615 root_scope
= get_root_scope_from_absolute_pathstr(pathstr
, ctx
);
617 if (root_scope
== CTF_SCOPE_PACKET_UNKNOWN
) {
618 /* Relative path: start with current root scope */
619 field_path
->root
= ctx
->root_scope
;
620 BT_COMP_LOGD("Detected relative path: starting with current root scope: "
622 ctf_scope_string(field_path
->root
));
623 ret
= relative_ptokens_to_field_path(ptokens
, field_path
, ctx
);
625 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
626 "Cannot get relative field path of path string: "
627 "path=\"%s\", start-scope=%s, end-scope=%s",
628 pathstr
, ctf_scope_string(ctx
->root_scope
), ctf_scope_string(field_path
->root
));
632 /* Absolute path: use found root scope */
633 field_path
->root
= root_scope
;
634 BT_COMP_LOGD("Detected absolute path: using root scope: "
636 ctf_scope_string(field_path
->root
));
637 ret
= absolute_ptokens_to_field_path(ptokens
, field_path
, ctx
);
639 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
640 "Cannot get absolute field path of path string: "
641 "path=\"%s\", root-scope=%s",
642 pathstr
, ctf_scope_string(root_scope
));
647 if (BT_LOG_ON_TRACE
&& ret
== 0) {
648 GString
*field_path_pretty
= ctf_field_path_string(field_path
);
649 const char *field_path_pretty_str
= field_path_pretty
? field_path_pretty
->str
: "(null)";
651 BT_COMP_LOGD("Found field path: path=\"%s\", field-path=\"%s\"", pathstr
,
652 field_path_pretty_str
);
654 if (field_path_pretty
) {
655 g_string_free(field_path_pretty
, TRUE
);
660 ptokens_destroy(ptokens
);
665 * Retrieves a field class by following the field path `field_path` in
666 * the resolving context `ctx`.
668 static struct ctf_field_class
*field_path_to_field_class(struct ctf_field_path
*field_path
,
669 struct resolve_context
*ctx
)
672 struct ctf_field_class
*fc
;
674 /* Start with root class */
675 fc
= borrow_class_from_ctx(ctx
, field_path
->root
);
677 /* Error: root class is not available */
678 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: root-scope=%s",
679 ctf_scope_string(field_path
->root
));
684 for (i
= 0; i
< field_path
->path
->len
; i
++) {
685 struct ctf_field_class
*child_fc
;
686 int64_t child_index
= ctf_field_path_borrow_index_by_index(field_path
, i
);
688 /* Get child field class */
689 child_fc
= ctf_field_class_compound_borrow_field_class_by_index(fc
, child_index
);
692 /* Move child class to current class */
701 * Fills the equivalent field path object of the context class stack.
703 static void get_ctx_stack_field_path(struct resolve_context
*ctx
, struct ctf_field_path
*field_path
)
707 BT_ASSERT(field_path
);
708 field_path
->root
= ctx
->root_scope
;
709 ctf_field_path_clear(field_path
);
711 for (i
= 0; i
< field_class_stack_size(ctx
->field_class_stack
); i
++) {
712 struct field_class_stack_frame
*frame
= field_class_stack_at(ctx
->field_class_stack
, i
);
714 ctf_field_path_append_index(field_path
, frame
->index
);
719 * Returns the index of the lowest common ancestor of two field path
720 * objects having the same root scope.
722 static int64_t get_field_paths_lca_index(struct ctf_field_path
*field_path1
,
723 struct ctf_field_path
*field_path2
,
724 struct resolve_context
*ctx
)
726 int64_t lca_index
= 0;
727 uint64_t field_path1_len
, field_path2_len
;
729 if (BT_LOG_ON_TRACE
) {
730 GString
*field_path1_pretty
= ctf_field_path_string(field_path1
);
731 GString
*field_path2_pretty
= ctf_field_path_string(field_path2
);
732 const char *field_path1_pretty_str
=
733 field_path1_pretty
? field_path1_pretty
->str
: "(null)";
734 const char *field_path2_pretty_str
=
735 field_path2_pretty
? field_path2_pretty
->str
: "(null)";
737 BT_COMP_LOGD("Finding lowest common ancestor (LCA) between two field paths: "
738 "field-path-1=\"%s\", field-path-2=\"%s\"",
739 field_path1_pretty_str
, field_path2_pretty_str
);
741 if (field_path1_pretty
) {
742 g_string_free(field_path1_pretty
, TRUE
);
745 if (field_path2_pretty
) {
746 g_string_free(field_path2_pretty
, TRUE
);
751 * Start from both roots and find the first mismatch.
753 BT_ASSERT(field_path1
->root
== field_path2
->root
);
754 field_path1_len
= field_path1
->path
->len
;
755 field_path2_len
= field_path2
->path
->len
;
758 int64_t target_index
, ctx_index
;
760 if (lca_index
== (int64_t) field_path2_len
|| lca_index
== (int64_t) field_path1_len
) {
762 * This means that both field paths never split.
763 * This is invalid because the target cannot be
764 * an ancestor of the source.
766 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
767 "Source field class is an ancestor of target field class or vice versa: "
768 "lca-index=%" PRId64
", "
769 "field-path-1-len=%" PRIu64
", "
770 "field-path-2-len=%" PRIu64
,
771 lca_index
, field_path1_len
, field_path2_len
);
776 target_index
= ctf_field_path_borrow_index_by_index(field_path1
, lca_index
);
777 ctx_index
= ctf_field_path_borrow_index_by_index(field_path2
, lca_index
);
779 if (target_index
!= ctx_index
) {
780 /* LCA index is the previous */
787 BT_COMP_LOGD("Found LCA: lca-index=%" PRId64
, lca_index
);
792 * Validates a target field path.
794 static int validate_target_field_path(struct ctf_field_path
*target_field_path
,
795 struct ctf_field_class
*target_fc
,
796 struct resolve_context
*ctx
)
799 struct ctf_field_path ctx_field_path
;
800 uint64_t target_field_path_len
= target_field_path
->path
->len
;
803 /* Get context field path */
804 ctf_field_path_init(&ctx_field_path
);
805 get_ctx_stack_field_path(ctx
, &ctx_field_path
);
808 * Make sure the target is not a root.
810 if (target_field_path_len
== 0) {
811 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
812 "Target field path's length is 0 (targeting the root).");
818 * Make sure the root of the target field path is not located
819 * after the context field path's root.
821 if (target_field_path
->root
> ctx_field_path
.root
) {
822 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
823 "Target field class is located after source field class: "
824 "target-root=%s, source-root=%s",
825 ctf_scope_string(target_field_path
->root
), ctf_scope_string(ctx_field_path
.root
));
830 if (target_field_path
->root
== ctx_field_path
.root
) {
831 int64_t target_index
, ctx_index
;
834 * Find the index of the lowest common ancestor of both field
837 lca_index
= get_field_paths_lca_index(target_field_path
, &ctx_field_path
, ctx
);
839 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get least common ancestor.");
845 * Make sure the target field path is located before the
846 * context field path.
849 ctf_field_path_borrow_index_by_index(target_field_path
, (uint64_t) lca_index
);
850 ctx_index
= ctf_field_path_borrow_index_by_index(&ctx_field_path
, (uint64_t) lca_index
);
852 if (target_index
>= ctx_index
) {
853 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
854 "Target field class's index is greater than or equal to source field class's index in LCA: "
855 "lca-index=%" PRId64
", "
856 "target-index=%" PRId64
", "
857 "source-index=%" PRId64
,
858 lca_index
, target_index
, ctx_index
);
865 * Make sure the target class has the right class and properties.
867 switch (ctx
->cur_fc
->type
) {
868 case CTF_FIELD_CLASS_TYPE_VARIANT
:
869 if (target_fc
->type
!= CTF_FIELD_CLASS_TYPE_ENUM
) {
870 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
871 "Variant field class's tag field class is not an enumeration field class: "
872 "tag-fc-addr=%p, tag-fc-id=%d",
873 target_fc
, target_fc
->type
);
878 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
880 if (target_fc
->type
!= CTF_FIELD_CLASS_TYPE_INT
&&
881 target_fc
->type
!= CTF_FIELD_CLASS_TYPE_ENUM
) {
882 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
883 "Sequence field class's length field class is not an unsigned integer field class: "
884 "length-fc-addr=%p, length-fc-id=%d",
885 target_fc
, target_fc
->type
);
890 ctf_field_class_int
*int_fc
= ctf_field_class_as_int(target_fc
);
892 if (int_fc
->is_signed
) {
893 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
894 "Sequence field class's length field class is not an unsigned integer field class: "
895 "length-fc-addr=%p, length-fc-id=%d",
896 target_fc
, target_fc
->type
);
907 ctf_field_path_fini(&ctx_field_path
);
912 * Resolves a variant or sequence field class `fc`.
914 static int resolve_sequence_or_variant_field_class(struct ctf_field_class
*fc
,
915 struct resolve_context
*ctx
)
919 struct ctf_field_path target_field_path
;
920 struct ctf_field_class
*target_fc
= NULL
;
921 GString
*target_field_path_pretty
= NULL
;
922 const char *target_field_path_pretty_str
;
924 ctf_field_path_init(&target_field_path
);
926 /* Get path string */
928 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
930 struct ctf_field_class_sequence
*seq_fc
= ctf_field_class_as_sequence(fc
);
931 pathstr
= seq_fc
->length_ref
->str
;
934 case CTF_FIELD_CLASS_TYPE_VARIANT
:
936 struct ctf_field_class_variant
*var_fc
= ctf_field_class_as_variant(fc
);
937 pathstr
= var_fc
->tag_ref
->str
;
945 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get path string.");
950 /* Get target field path out of path string */
951 ret
= pathstr_to_field_path(pathstr
, &target_field_path
, ctx
);
953 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field path for path string: "
959 target_field_path_pretty
= ctf_field_path_string(&target_field_path
);
960 target_field_path_pretty_str
= target_field_path_pretty
? target_field_path_pretty
->str
: NULL
;
962 /* Get target field class */
963 target_fc
= field_path_to_field_class(&target_field_path
, ctx
);
965 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field class for path string: "
966 "path=\"%s\", target-field-path=\"%s\"",
967 pathstr
, target_field_path_pretty_str
);
972 ret
= validate_target_field_path(&target_field_path
, target_fc
, ctx
);
974 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid target field path for path string: "
975 "path=\"%s\", target-field-path=\"%s\"",
976 pathstr
, target_field_path_pretty_str
);
980 /* Set target field path and target field class */
982 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
984 ctf_field_class_sequence
*seq_fc
= ctf_field_class_as_sequence(fc
);
986 ctf_field_path_copy_content(&seq_fc
->length_path
, &target_field_path
);
987 seq_fc
->length_fc
= ctf_field_class_as_int(target_fc
);
990 case CTF_FIELD_CLASS_TYPE_VARIANT
:
992 ctf_field_class_variant
*var_fc
= ctf_field_class_as_variant(fc
);
994 ctf_field_path_copy_content(&var_fc
->tag_path
, &target_field_path
);
995 ctf_field_class_variant_set_tag_field_class(var_fc
, ctf_field_class_as_enum(target_fc
));
1003 if (target_field_path_pretty
) {
1004 g_string_free(target_field_path_pretty
, TRUE
);
1007 ctf_field_path_fini(&target_field_path
);
1012 * Resolves a field class `fc`.
1014 static int resolve_field_class(struct ctf_field_class
*fc
, struct resolve_context
*ctx
)
1019 /* Field class is not available; still valid */
1025 /* Resolve sequence/variant field class */
1027 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1028 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1029 ret
= resolve_sequence_or_variant_field_class(fc
, ctx
);
1031 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
1032 "Cannot resolve sequence field class's length or variant field class's tag: "
1033 "ret=%d, fc-addr=%p",
1043 /* Recurse into compound classes */
1045 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1046 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1047 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1048 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1051 uint64_t field_count
= ctf_field_class_compound_get_field_class_count(fc
);
1053 ret
= field_class_stack_push(ctx
->field_class_stack
, fc
, ctx
);
1055 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot push field class on context's stack: "
1061 for (i
= 0; i
< field_count
; i
++) {
1062 struct ctf_field_class
*child_fc
=
1063 ctf_field_class_compound_borrow_field_class_by_index(fc
, i
);
1065 BT_ASSERT(child_fc
);
1067 if (fc
->type
== CTF_FIELD_CLASS_TYPE_ARRAY
||
1068 fc
->type
== CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
1069 field_class_stack_peek(ctx
->field_class_stack
)->index
= -1;
1071 field_class_stack_peek(ctx
->field_class_stack
)->index
= (int64_t) i
;
1074 BT_COMP_LOGD("Resolving field class's child field class: "
1075 "parent-fc-addr=%p, child-fc-addr=%p, "
1076 "index=%" PRIu64
", count=%" PRIu64
,
1077 fc
, child_fc
, i
, field_count
);
1078 ret
= resolve_field_class(child_fc
, ctx
);
1084 field_class_stack_pop(ctx
->field_class_stack
, ctx
);
1096 * Resolves the root field class corresponding to the scope `root_scope`.
1098 static int resolve_root_class(enum ctf_scope root_scope
, struct resolve_context
*ctx
)
1102 BT_ASSERT(field_class_stack_size(ctx
->field_class_stack
) == 0);
1103 ctx
->root_scope
= root_scope
;
1104 ret
= resolve_field_class(borrow_class_from_ctx(ctx
, root_scope
), ctx
);
1105 ctx
->root_scope
= CTF_SCOPE_PACKET_UNKNOWN
;
1109 static int resolve_event_class_field_classes(struct resolve_context
*ctx
,
1110 struct ctf_event_class
*ec
)
1114 BT_ASSERT(!ctx
->scopes
.event_spec_context
);
1115 BT_ASSERT(!ctx
->scopes
.event_payload
);
1117 if (ec
->is_translated
) {
1122 ctx
->scopes
.event_spec_context
= ec
->spec_context_fc
;
1123 ret
= resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT
, ctx
);
1125 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
1126 "Cannot resolve event specific context field class: "
1132 ctx
->scopes
.event_payload
= ec
->payload_fc
;
1133 ret
= resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD
, ctx
);
1135 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event payload field class: "
1142 ctx
->scopes
.event_spec_context
= NULL
;
1143 ctx
->scopes
.event_payload
= NULL
;
1148 static int resolve_stream_class_field_classes(struct resolve_context
*ctx
,
1149 struct ctf_stream_class
*sc
)
1154 BT_ASSERT(!ctx
->scopes
.packet_context
);
1155 BT_ASSERT(!ctx
->scopes
.event_header
);
1156 BT_ASSERT(!ctx
->scopes
.event_common_context
);
1159 if (!sc
->is_translated
) {
1160 ctx
->scopes
.packet_context
= sc
->packet_context_fc
;
1161 ret
= resolve_root_class(CTF_SCOPE_PACKET_CONTEXT
, ctx
);
1163 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet context field class: "
1169 ctx
->scopes
.event_header
= sc
->event_header_fc
;
1170 ret
= resolve_root_class(CTF_SCOPE_EVENT_HEADER
, ctx
);
1172 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event header field class: "
1178 ctx
->scopes
.event_common_context
= sc
->event_common_context_fc
;
1179 ret
= resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT
, ctx
);
1181 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
1182 "Cannot resolve event common context field class: "
1189 ctx
->scopes
.packet_context
= sc
->packet_context_fc
;
1190 ctx
->scopes
.event_header
= sc
->event_header_fc
;
1191 ctx
->scopes
.event_common_context
= sc
->event_common_context_fc
;
1193 for (i
= 0; i
< sc
->event_classes
->len
; i
++) {
1194 ctf_event_class
*ec
= (ctf_event_class
*) sc
->event_classes
->pdata
[i
];
1196 ret
= resolve_event_class_field_classes(ctx
, ec
);
1198 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event class's field classes: "
1199 "ec-id=%" PRIu64
", ec-name=\"%s\"",
1200 ec
->id
, ec
->name
->str
);
1206 ctx
->scopes
.packet_context
= NULL
;
1207 ctx
->scopes
.event_header
= NULL
;
1208 ctx
->scopes
.event_common_context
= NULL
;
1213 int ctf_trace_class_resolve_field_classes(struct ctf_trace_class
*tc
,
1214 struct meta_log_config
*log_cfg
)
1219 resolve_context local_ctx
{};
1220 local_ctx
.log_level
= log_cfg
->log_level
;
1221 local_ctx
.self_comp
= log_cfg
->self_comp
;
1222 local_ctx
.self_comp_class
= log_cfg
->self_comp_class
;
1224 local_ctx
.scopes
.packet_header
= tc
->packet_header_fc
;
1225 local_ctx
.root_scope
= CTF_SCOPE_PACKET_HEADER
;
1227 struct resolve_context
*ctx
= &local_ctx
;
1229 /* Initialize class stack */
1230 ctx
->field_class_stack
= field_class_stack_create();
1231 if (!ctx
->field_class_stack
) {
1232 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create field class stack.");
1237 if (!tc
->is_translated
) {
1238 ctx
->scopes
.packet_header
= tc
->packet_header_fc
;
1239 ret
= resolve_root_class(CTF_SCOPE_PACKET_HEADER
, ctx
);
1241 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet header field class: "
1248 ctx
->scopes
.packet_header
= tc
->packet_header_fc
;
1250 for (i
= 0; i
< tc
->stream_classes
->len
; i
++) {
1251 ctf_stream_class
*sc
= (ctf_stream_class
*) tc
->stream_classes
->pdata
[i
];
1253 ret
= resolve_stream_class_field_classes(ctx
, sc
);
1255 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve stream class's field classes: "
1263 field_class_stack_destroy(ctx
->field_class_stack
);