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>
8 #define BT_COMP_LOG_SELF_COMP (ctx->self_comp)
9 #define BT_COMP_LOG_SELF_COMP_CLASS (ctx->self_comp_class)
10 #define BT_LOG_OUTPUT_LEVEL (ctx->log_level)
11 #define BT_LOG_TAG "PLUGIN/CTF/META/RESOLVE"
12 #include "logging/comp-logging.h"
14 #include <babeltrace2/babeltrace.h>
15 #include "common/macros.h"
16 #include "common/assert.h"
17 #include "common/common.h"
27 #include "ctf-meta-visitors.hpp"
28 #include "logging.hpp"
30 using field_class_stack_t
= GPtrArray
;
35 * `fc` contains a compound field class (structure, variant, array,
36 * or sequence) and `index` indicates the index of the field class in
37 * the upper frame (-1 for array and sequence field classes). `name`
38 * indicates the name of the field class in the upper frame (empty
39 * string for array and sequence field classes).
41 struct field_class_stack_frame
43 struct ctf_field_class
*fc
;
48 * The current context of the resolving engine.
50 struct resolve_context
52 bt_logging_level log_level
;
54 /* Weak, exactly one of these must be set */
55 bt_self_component
*self_comp
;
56 bt_self_component_class
*self_comp_class
;
58 struct ctf_trace_class
*tc
;
59 struct ctf_stream_class
*sc
;
60 struct ctf_event_class
*ec
;
64 struct ctf_field_class
*packet_header
;
65 struct ctf_field_class
*packet_context
;
66 struct ctf_field_class
*event_header
;
67 struct ctf_field_class
*event_common_context
;
68 struct ctf_field_class
*event_spec_context
;
69 struct ctf_field_class
*event_payload
;
72 /* Root scope being visited */
73 enum ctf_scope root_scope
;
74 field_class_stack_t
*field_class_stack
;
75 struct ctf_field_class
*cur_fc
;
78 /* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
79 static const char * const absolute_path_prefixes
[] = {
80 /* CTF_SCOPE_PACKET_HEADER */ "trace.packet.header.",
81 /* CTF_SCOPE_PACKET_CONTEXT */ "stream.packet.context.",
82 /* CTF_SCOPE_EVENT_HEADER */ "stream.event.header.",
83 /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ "stream.event.context.",
84 /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ "event.context.",
85 /* CTF_SCOPE_EVENT_PAYLOAD */ "event.fields.",
88 /* Number of path tokens used for the absolute prefixes */
89 static const uint64_t absolute_path_prefix_ptoken_counts
[] = {
90 /* CTF_SCOPE_PACKET_HEADER */ 3,
91 /* CTF_SCOPE_PACKET_CONTEXT */ 3,
92 /* CTF_SCOPE_EVENT_HEADER */ 3,
93 /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ 3,
94 /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ 2,
95 /* CTF_SCOPE_EVENT_PAYLOAD */ 2,
98 static void destroy_field_class_stack_frame(struct field_class_stack_frame
*frame
)
108 * Creates a class stack.
110 static field_class_stack_t
*field_class_stack_create(void)
112 return g_ptr_array_new_with_free_func((GDestroyNotify
) destroy_field_class_stack_frame
);
116 * Destroys a class stack.
118 static void field_class_stack_destroy(field_class_stack_t
*stack
)
121 g_ptr_array_free(stack
, TRUE
);
126 * Pushes a field class onto a class stack.
128 static int field_class_stack_push(field_class_stack_t
*stack
, struct ctf_field_class
*fc
,
129 struct resolve_context
*ctx
)
132 struct field_class_stack_frame
*frame
= NULL
;
135 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
136 "Invalid parameter: stack or field class is `NULL`.");
141 frame
= g_new0(struct field_class_stack_frame
, 1);
143 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one field class stack frame.");
148 BT_COMP_LOGD("Pushing field class on context's stack: "
149 "fc-addr=%p, stack-size-before=%u",
152 g_ptr_array_add(stack
, frame
);
159 * Checks whether or not `stack` is empty.
161 static bool field_class_stack_empty(field_class_stack_t
*stack
)
163 return stack
->len
== 0;
167 * Returns the number of frames in `stack`.
169 static size_t field_class_stack_size(field_class_stack_t
*stack
)
175 * Returns the top frame of `stack`.
177 static struct field_class_stack_frame
*field_class_stack_peek(field_class_stack_t
*stack
)
180 BT_ASSERT(!field_class_stack_empty(stack
));
182 return (field_class_stack_frame
*) g_ptr_array_index(stack
, stack
->len
- 1);
186 * Returns the frame at index `index` in `stack`.
188 static struct field_class_stack_frame
*field_class_stack_at(field_class_stack_t
*stack
,
192 BT_ASSERT(index
< stack
->len
);
194 return (field_class_stack_frame
*) g_ptr_array_index(stack
, index
);
198 * Removes the top frame of `stack`.
200 static void field_class_stack_pop(field_class_stack_t
*stack
, struct resolve_context
*ctx
)
202 if (!field_class_stack_empty(stack
)) {
204 * This will call the frame's destructor and free it, as
205 * well as put its contained field class.
207 BT_COMP_LOGD("Popping context's stack: stack-size-before=%u", stack
->len
);
208 g_ptr_array_set_size(stack
, stack
->len
- 1);
213 * Returns the scope field class of `scope` in the context `ctx`.
215 static struct ctf_field_class
*borrow_class_from_ctx(struct resolve_context
*ctx
,
216 enum ctf_scope scope
)
219 case CTF_SCOPE_PACKET_HEADER
:
220 return ctx
->scopes
.packet_header
;
221 case CTF_SCOPE_PACKET_CONTEXT
:
222 return ctx
->scopes
.packet_context
;
223 case CTF_SCOPE_EVENT_HEADER
:
224 return ctx
->scopes
.event_header
;
225 case CTF_SCOPE_EVENT_COMMON_CONTEXT
:
226 return ctx
->scopes
.event_common_context
;
227 case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT
:
228 return ctx
->scopes
.event_spec_context
;
229 case CTF_SCOPE_EVENT_PAYLOAD
:
230 return ctx
->scopes
.event_payload
;
239 * Returns the CTF scope from a path string. May return -1 if the path
240 * is found to be relative.
242 static enum ctf_scope
get_root_scope_from_absolute_pathstr(const char *pathstr
,
243 struct resolve_context
*ctx
)
245 enum ctf_scope scope
;
246 enum ctf_scope ret
= CTF_SCOPE_PACKET_UNKNOWN
;
247 const size_t prefixes_count
= sizeof(absolute_path_prefixes
) / sizeof(*absolute_path_prefixes
);
249 for (scope
= CTF_SCOPE_PACKET_HEADER
; scope
< CTF_SCOPE_PACKET_HEADER
+ prefixes_count
;
250 scope
= (ctf_scope
) (scope
+ 1)) {
252 * Check if path string starts with a known absolute
255 * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
257 if (strncmp(pathstr
, absolute_path_prefixes
[scope
],
258 strlen(absolute_path_prefixes
[scope
]))) {
259 /* Prefix does not match: try the next one */
260 BT_COMP_LOGD("Prefix does not match: trying the next one: "
261 "path=\"%s\", path-prefix=\"%s\", scope=%s",
262 pathstr
, absolute_path_prefixes
[scope
], ctf_scope_string(scope
));
268 BT_COMP_LOGD("Found root scope from absolute path: "
269 "path=\"%s\", scope=%s",
270 pathstr
, ctf_scope_string(scope
));
279 * Destroys a path token.
281 static void ptokens_destroy_func(gpointer ptoken
, gpointer data
)
283 g_string_free((GString
*) ptoken
, TRUE
);
287 * Destroys a path token list.
289 static void ptokens_destroy(GList
*ptokens
)
295 g_list_foreach(ptokens
, ptokens_destroy_func
, NULL
);
296 g_list_free(ptokens
);
300 * Returns the string contained in a path token.
302 static const char *ptoken_get_string(GList
*ptoken
)
304 GString
*tokenstr
= (GString
*) ptoken
->data
;
306 return tokenstr
->str
;
310 * Converts a path string to a path token list, that is, splits the
311 * individual words of a path string into a list of individual
314 static GList
*pathstr_to_ptokens(const char *pathstr
, struct resolve_context
*ctx
)
316 const char *at
= pathstr
;
317 const char *last
= at
;
318 GList
*ptokens
= NULL
;
321 if (*at
== '.' || *at
== '\0') {
325 /* Error: empty token */
326 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Empty path token: path=\"%s\", pos=%u",
327 pathstr
, (unsigned int) (at
- pathstr
));
331 tokenstr
= g_string_new(NULL
);
332 g_string_append_len(tokenstr
, last
, at
- last
);
333 ptokens
= g_list_append(ptokens
, tokenstr
);
347 ptokens_destroy(ptokens
);
352 * Converts a path token list to a field path object. The path token
353 * list is relative from `fc`. The index of the source looking for its
354 * target within `fc` is indicated by `src_index`. This can be
355 * `INT64_MAX` if the source is contained in `fc`.
357 * `field_path` is an output parameter owned by the caller that must be
360 static int ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
361 struct ctf_field_class
*fc
, int64_t src_index
,
362 struct resolve_context
*ctx
)
365 GList
*cur_ptoken
= ptokens
;
366 bool first_level_done
= false;
371 struct ctf_field_class
*child_fc
;
372 const char *ft_name
= ptoken_get_string(cur_ptoken
);
374 BT_COMP_LOGD("Current path token: token=\"%s\"", ft_name
);
376 /* Find to which index corresponds the current path token */
377 if (fc
->type
== CTF_FIELD_CLASS_TYPE_ARRAY
|| fc
->type
== CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
381 ctf_field_class_compound_get_field_class_index_from_orig_name(fc
, ft_name
);
382 if (child_index
< 0) {
384 * Error: field name does not exist or
385 * wrong current class.
387 BT_COMP_LOGD("Cannot get index of field class: "
388 "field-name=\"%s\", "
389 "src-index=%" PRId64
", "
390 "child-index=%" PRId64
", "
391 "first-level-done=%d",
392 ft_name
, src_index
, child_index
, first_level_done
);
395 } else if (child_index
> src_index
&& !first_level_done
) {
396 BT_COMP_LOGD("Child field class is located after source field class: "
397 "field-name=\"%s\", "
398 "src-index=%" PRId64
", "
399 "child-index=%" PRId64
", "
400 "first-level-done=%d",
401 ft_name
, src_index
, child_index
, first_level_done
);
406 /* Next path token */
407 cur_ptoken
= g_list_next(cur_ptoken
);
408 first_level_done
= true;
411 /* Create new field path entry */
412 ctf_field_path_append_index(field_path
, child_index
);
414 /* Get child field class */
415 child_fc
= ctf_field_class_compound_borrow_field_class_by_index(fc
, child_index
);
418 /* Move child class to current class */
427 * Converts a known absolute path token list to a field path object
428 * within the resolving context `ctx`.
430 * `field_path` is an output parameter owned by the caller that must be
433 static int absolute_ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
434 struct resolve_context
*ctx
)
438 struct ctf_field_class
*fc
;
441 * Make sure we're not referring to a scope within a translated
444 switch (field_path
->root
) {
445 case CTF_SCOPE_PACKET_HEADER
:
446 if (ctx
->tc
->is_translated
) {
447 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Trace class is already translated: "
449 ctf_scope_string(field_path
->root
));
455 case CTF_SCOPE_PACKET_CONTEXT
:
456 case CTF_SCOPE_EVENT_HEADER
:
457 case CTF_SCOPE_EVENT_COMMON_CONTEXT
:
459 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current stream class: "
461 ctf_scope_string(field_path
->root
));
466 if (ctx
->sc
->is_translated
) {
467 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class is already translated: "
469 ctf_scope_string(field_path
->root
));
475 case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT
:
476 case CTF_SCOPE_EVENT_PAYLOAD
:
478 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current event class: "
480 ctf_scope_string(field_path
->root
));
485 if (ctx
->ec
->is_translated
) {
486 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Event class is already translated: "
488 ctf_scope_string(field_path
->root
));
499 /* Skip absolute path tokens */
500 cur_ptoken
= g_list_nth(ptokens
, absolute_path_prefix_ptoken_counts
[field_path
->root
]);
502 /* Start with root class */
503 fc
= borrow_class_from_ctx(ctx
, field_path
->root
);
505 /* Error: root class is not available */
506 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: "
508 ctf_scope_string(field_path
->root
));
514 ret
= ptokens_to_field_path(cur_ptoken
, field_path
, fc
, INT64_MAX
, ctx
);
521 * Converts a known relative path token list to a field path object
522 * within the resolving context `ctx`.
524 * `field_path` is an output parameter owned by the caller that must be
527 static int relative_ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
528 struct resolve_context
*ctx
)
531 int64_t parent_pos_in_stack
;
532 struct ctf_field_path tail_field_path
;
534 ctf_field_path_init(&tail_field_path
);
535 parent_pos_in_stack
= field_class_stack_size(ctx
->field_class_stack
) - 1;
537 while (parent_pos_in_stack
>= 0) {
538 struct ctf_field_class
*parent_class
=
539 field_class_stack_at(ctx
->field_class_stack
, parent_pos_in_stack
)->fc
;
541 field_class_stack_at(ctx
->field_class_stack
, parent_pos_in_stack
)->index
;
543 BT_COMP_LOGD("Locating target field class from current parent field class: "
544 "parent-pos=%" PRId64
", parent-fc-addr=%p, "
545 "cur-index=%" PRId64
,
546 parent_pos_in_stack
, parent_class
, cur_index
);
548 /* Locate target from current parent class */
549 ret
= ptokens_to_field_path(ptokens
, &tail_field_path
, parent_class
, cur_index
, ctx
);
551 /* Not found... yet */
552 BT_COMP_LOGD_STR("Not found at this point.");
553 ctf_field_path_clear(&tail_field_path
);
555 /* Found: stitch tail field path to head field path */
557 size_t tail_field_path_len
= tail_field_path
.path
->len
;
560 struct ctf_field_class
*cur_class
=
561 field_class_stack_at(ctx
->field_class_stack
, i
)->fc
;
562 int64_t index
= field_class_stack_at(ctx
->field_class_stack
, i
)->index
;
564 if (cur_class
== parent_class
) {
568 ctf_field_path_append_index(field_path
, index
);
572 for (i
= 0; i
< tail_field_path_len
; i
++) {
573 int64_t index
= ctf_field_path_borrow_index_by_index(&tail_field_path
, i
);
575 ctf_field_path_append_index(field_path
, (int64_t) index
);
580 parent_pos_in_stack
--;
583 if (parent_pos_in_stack
< 0) {
588 ctf_field_path_fini(&tail_field_path
);
593 * Converts a path string to a field path object within the resolving
596 static int pathstr_to_field_path(const char *pathstr
, struct ctf_field_path
*field_path
,
597 struct resolve_context
*ctx
)
600 enum ctf_scope root_scope
;
601 GList
*ptokens
= NULL
;
603 /* Convert path string to path tokens */
604 ptokens
= pathstr_to_ptokens(pathstr
, ctx
);
606 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot convert path string to path tokens: "
613 /* Absolute or relative path? */
614 root_scope
= get_root_scope_from_absolute_pathstr(pathstr
, ctx
);
616 if (root_scope
== CTF_SCOPE_PACKET_UNKNOWN
) {
617 /* Relative path: start with current root scope */
618 field_path
->root
= ctx
->root_scope
;
619 BT_COMP_LOGD("Detected relative path: starting with current root scope: "
621 ctf_scope_string(field_path
->root
));
622 ret
= relative_ptokens_to_field_path(ptokens
, field_path
, ctx
);
624 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
625 "Cannot get relative field path of path string: "
626 "path=\"%s\", start-scope=%s, end-scope=%s",
627 pathstr
, ctf_scope_string(ctx
->root_scope
), ctf_scope_string(field_path
->root
));
631 /* Absolute path: use found root scope */
632 field_path
->root
= root_scope
;
633 BT_COMP_LOGD("Detected absolute path: using root scope: "
635 ctf_scope_string(field_path
->root
));
636 ret
= absolute_ptokens_to_field_path(ptokens
, field_path
, ctx
);
638 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
639 "Cannot get absolute field path of path string: "
640 "path=\"%s\", root-scope=%s",
641 pathstr
, ctf_scope_string(root_scope
));
646 if (BT_LOG_ON_TRACE
&& ret
== 0) {
647 GString
*field_path_pretty
= ctf_field_path_string(field_path
);
648 const char *field_path_pretty_str
= field_path_pretty
? field_path_pretty
->str
: "(null)";
650 BT_COMP_LOGD("Found field path: path=\"%s\", field-path=\"%s\"", pathstr
,
651 field_path_pretty_str
);
653 if (field_path_pretty
) {
654 g_string_free(field_path_pretty
, TRUE
);
659 ptokens_destroy(ptokens
);
664 * Retrieves a field class by following the field path `field_path` in
665 * the resolving context `ctx`.
667 static struct ctf_field_class
*field_path_to_field_class(struct ctf_field_path
*field_path
,
668 struct resolve_context
*ctx
)
671 struct ctf_field_class
*fc
;
673 /* Start with root class */
674 fc
= borrow_class_from_ctx(ctx
, field_path
->root
);
676 /* Error: root class is not available */
677 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: root-scope=%s",
678 ctf_scope_string(field_path
->root
));
683 for (i
= 0; i
< field_path
->path
->len
; i
++) {
684 struct ctf_field_class
*child_fc
;
685 int64_t child_index
= ctf_field_path_borrow_index_by_index(field_path
, i
);
687 /* Get child field class */
688 child_fc
= ctf_field_class_compound_borrow_field_class_by_index(fc
, child_index
);
691 /* Move child class to current class */
700 * Fills the equivalent field path object of the context class stack.
702 static void get_ctx_stack_field_path(struct resolve_context
*ctx
, struct ctf_field_path
*field_path
)
706 BT_ASSERT(field_path
);
707 field_path
->root
= ctx
->root_scope
;
708 ctf_field_path_clear(field_path
);
710 for (i
= 0; i
< field_class_stack_size(ctx
->field_class_stack
); i
++) {
711 struct field_class_stack_frame
*frame
= field_class_stack_at(ctx
->field_class_stack
, i
);
713 ctf_field_path_append_index(field_path
, frame
->index
);
718 * Returns the index of the lowest common ancestor of two field path
719 * objects having the same root scope.
721 static int64_t get_field_paths_lca_index(struct ctf_field_path
*field_path1
,
722 struct ctf_field_path
*field_path2
,
723 struct resolve_context
*ctx
)
725 int64_t lca_index
= 0;
726 uint64_t field_path1_len
, field_path2_len
;
728 if (BT_LOG_ON_TRACE
) {
729 GString
*field_path1_pretty
= ctf_field_path_string(field_path1
);
730 GString
*field_path2_pretty
= ctf_field_path_string(field_path2
);
731 const char *field_path1_pretty_str
= field_path1_pretty
? field_path1_pretty
->str
: NULL
;
732 const char *field_path2_pretty_str
= field_path2_pretty
? field_path2_pretty
->str
: NULL
;
734 BT_COMP_LOGD("Finding lowest common ancestor (LCA) between two field paths: "
735 "field-path-1=\"%s\", field-path-2=\"%s\"",
736 field_path1_pretty_str
, field_path2_pretty_str
);
738 if (field_path1_pretty
) {
739 g_string_free(field_path1_pretty
, TRUE
);
742 if (field_path2_pretty
) {
743 g_string_free(field_path2_pretty
, TRUE
);
748 * Start from both roots and find the first mismatch.
750 BT_ASSERT(field_path1
->root
== field_path2
->root
);
751 field_path1_len
= field_path1
->path
->len
;
752 field_path2_len
= field_path2
->path
->len
;
755 int64_t target_index
, ctx_index
;
757 if (lca_index
== (int64_t) field_path2_len
|| lca_index
== (int64_t) field_path1_len
) {
759 * This means that both field paths never split.
760 * This is invalid because the target cannot be
761 * an ancestor of the source.
763 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
764 "Source field class is an ancestor of target field class or vice versa: "
765 "lca-index=%" PRId64
", "
766 "field-path-1-len=%" PRIu64
", "
767 "field-path-2-len=%" PRIu64
,
768 lca_index
, field_path1_len
, field_path2_len
);
773 target_index
= ctf_field_path_borrow_index_by_index(field_path1
, lca_index
);
774 ctx_index
= ctf_field_path_borrow_index_by_index(field_path2
, lca_index
);
776 if (target_index
!= ctx_index
) {
777 /* LCA index is the previous */
784 BT_COMP_LOGD("Found LCA: lca-index=%" PRId64
, lca_index
);
789 * Validates a target field path.
791 static int validate_target_field_path(struct ctf_field_path
*target_field_path
,
792 struct ctf_field_class
*target_fc
,
793 struct resolve_context
*ctx
)
796 struct ctf_field_path ctx_field_path
;
797 uint64_t target_field_path_len
= target_field_path
->path
->len
;
800 /* Get context field path */
801 ctf_field_path_init(&ctx_field_path
);
802 get_ctx_stack_field_path(ctx
, &ctx_field_path
);
805 * Make sure the target is not a root.
807 if (target_field_path_len
== 0) {
808 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
809 "Target field path's length is 0 (targeting the root).");
815 * Make sure the root of the target field path is not located
816 * after the context field path's root.
818 if (target_field_path
->root
> ctx_field_path
.root
) {
819 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
820 "Target field class is located after source field class: "
821 "target-root=%s, source-root=%s",
822 ctf_scope_string(target_field_path
->root
), ctf_scope_string(ctx_field_path
.root
));
827 if (target_field_path
->root
== ctx_field_path
.root
) {
828 int64_t target_index
, ctx_index
;
831 * Find the index of the lowest common ancestor of both field
834 lca_index
= get_field_paths_lca_index(target_field_path
, &ctx_field_path
, ctx
);
836 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get least common ancestor.");
842 * Make sure the target field path is located before the
843 * context field path.
846 ctf_field_path_borrow_index_by_index(target_field_path
, (uint64_t) lca_index
);
847 ctx_index
= ctf_field_path_borrow_index_by_index(&ctx_field_path
, (uint64_t) lca_index
);
849 if (target_index
>= ctx_index
) {
850 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
851 "Target field class's index is greater than or equal to source field class's index in LCA: "
852 "lca-index=%" PRId64
", "
853 "target-index=%" PRId64
", "
854 "source-index=%" PRId64
,
855 lca_index
, target_index
, ctx_index
);
862 * Make sure the target class has the right class and properties.
864 switch (ctx
->cur_fc
->type
) {
865 case CTF_FIELD_CLASS_TYPE_VARIANT
:
866 if (target_fc
->type
!= CTF_FIELD_CLASS_TYPE_ENUM
) {
867 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
868 "Variant field class's tag field class is not an enumeration field class: "
869 "tag-fc-addr=%p, tag-fc-id=%d",
870 target_fc
, target_fc
->type
);
875 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
877 if (target_fc
->type
!= CTF_FIELD_CLASS_TYPE_INT
&&
878 target_fc
->type
!= CTF_FIELD_CLASS_TYPE_ENUM
) {
879 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
880 "Sequence field class's length field class is not an unsigned integer field class: "
881 "length-fc-addr=%p, length-fc-id=%d",
882 target_fc
, target_fc
->type
);
887 ctf_field_class_int
*int_fc
= ctf_field_class_as_int(target_fc
);
889 if (int_fc
->is_signed
) {
890 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
891 "Sequence field class's length field class is not an unsigned integer field class: "
892 "length-fc-addr=%p, length-fc-id=%d",
893 target_fc
, target_fc
->type
);
904 ctf_field_path_fini(&ctx_field_path
);
909 * Resolves a variant or sequence field class `fc`.
911 static int resolve_sequence_or_variant_field_class(struct ctf_field_class
*fc
,
912 struct resolve_context
*ctx
)
916 struct ctf_field_path target_field_path
;
917 struct ctf_field_class
*target_fc
= NULL
;
918 GString
*target_field_path_pretty
= NULL
;
919 const char *target_field_path_pretty_str
;
921 ctf_field_path_init(&target_field_path
);
923 /* Get path string */
925 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
927 struct ctf_field_class_sequence
*seq_fc
= ctf_field_class_as_sequence(fc
);
928 pathstr
= seq_fc
->length_ref
->str
;
931 case CTF_FIELD_CLASS_TYPE_VARIANT
:
933 struct ctf_field_class_variant
*var_fc
= ctf_field_class_as_variant(fc
);
934 pathstr
= var_fc
->tag_ref
->str
;
942 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get path string.");
947 /* Get target field path out of path string */
948 ret
= pathstr_to_field_path(pathstr
, &target_field_path
, ctx
);
950 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field path for path string: "
956 target_field_path_pretty
= ctf_field_path_string(&target_field_path
);
957 target_field_path_pretty_str
= target_field_path_pretty
? target_field_path_pretty
->str
: NULL
;
959 /* Get target field class */
960 target_fc
= field_path_to_field_class(&target_field_path
, ctx
);
962 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field class for path string: "
963 "path=\"%s\", target-field-path=\"%s\"",
964 pathstr
, target_field_path_pretty_str
);
969 ret
= validate_target_field_path(&target_field_path
, target_fc
, ctx
);
971 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid target field path for path string: "
972 "path=\"%s\", target-field-path=\"%s\"",
973 pathstr
, target_field_path_pretty_str
);
977 /* Set target field path and target field class */
979 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
981 ctf_field_class_sequence
*seq_fc
= ctf_field_class_as_sequence(fc
);
983 ctf_field_path_copy_content(&seq_fc
->length_path
, &target_field_path
);
984 seq_fc
->length_fc
= ctf_field_class_as_int(target_fc
);
987 case CTF_FIELD_CLASS_TYPE_VARIANT
:
989 ctf_field_class_variant
*var_fc
= ctf_field_class_as_variant(fc
);
991 ctf_field_path_copy_content(&var_fc
->tag_path
, &target_field_path
);
992 ctf_field_class_variant_set_tag_field_class(var_fc
, ctf_field_class_as_enum(target_fc
));
1000 if (target_field_path_pretty
) {
1001 g_string_free(target_field_path_pretty
, TRUE
);
1004 ctf_field_path_fini(&target_field_path
);
1009 * Resolves a field class `fc`.
1011 static int resolve_field_class(struct ctf_field_class
*fc
, struct resolve_context
*ctx
)
1016 /* Field class is not available; still valid */
1022 /* Resolve sequence/variant field class */
1024 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1025 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1026 ret
= resolve_sequence_or_variant_field_class(fc
, ctx
);
1028 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
1029 "Cannot resolve sequence field class's length or variant field class's tag: "
1030 "ret=%d, fc-addr=%p",
1040 /* Recurse into compound classes */
1042 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1043 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1044 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1045 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1048 uint64_t field_count
= ctf_field_class_compound_get_field_class_count(fc
);
1050 ret
= field_class_stack_push(ctx
->field_class_stack
, fc
, ctx
);
1052 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot push field class on context's stack: "
1058 for (i
= 0; i
< field_count
; i
++) {
1059 struct ctf_field_class
*child_fc
=
1060 ctf_field_class_compound_borrow_field_class_by_index(fc
, i
);
1062 BT_ASSERT(child_fc
);
1064 if (fc
->type
== CTF_FIELD_CLASS_TYPE_ARRAY
||
1065 fc
->type
== CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
1066 field_class_stack_peek(ctx
->field_class_stack
)->index
= -1;
1068 field_class_stack_peek(ctx
->field_class_stack
)->index
= (int64_t) i
;
1071 BT_COMP_LOGD("Resolving field class's child field class: "
1072 "parent-fc-addr=%p, child-fc-addr=%p, "
1073 "index=%" PRIu64
", count=%" PRIu64
,
1074 fc
, child_fc
, i
, field_count
);
1075 ret
= resolve_field_class(child_fc
, ctx
);
1081 field_class_stack_pop(ctx
->field_class_stack
, ctx
);
1093 * Resolves the root field class corresponding to the scope `root_scope`.
1095 static int resolve_root_class(enum ctf_scope root_scope
, struct resolve_context
*ctx
)
1099 BT_ASSERT(field_class_stack_size(ctx
->field_class_stack
) == 0);
1100 ctx
->root_scope
= root_scope
;
1101 ret
= resolve_field_class(borrow_class_from_ctx(ctx
, root_scope
), ctx
);
1102 ctx
->root_scope
= CTF_SCOPE_PACKET_UNKNOWN
;
1106 static int resolve_event_class_field_classes(struct resolve_context
*ctx
,
1107 struct ctf_event_class
*ec
)
1111 BT_ASSERT(!ctx
->scopes
.event_spec_context
);
1112 BT_ASSERT(!ctx
->scopes
.event_payload
);
1114 if (ec
->is_translated
) {
1119 ctx
->scopes
.event_spec_context
= ec
->spec_context_fc
;
1120 ret
= resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT
, ctx
);
1122 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
1123 "Cannot resolve event specific context field class: "
1129 ctx
->scopes
.event_payload
= ec
->payload_fc
;
1130 ret
= resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD
, ctx
);
1132 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event payload field class: "
1139 ctx
->scopes
.event_spec_context
= NULL
;
1140 ctx
->scopes
.event_payload
= NULL
;
1145 static int resolve_stream_class_field_classes(struct resolve_context
*ctx
,
1146 struct ctf_stream_class
*sc
)
1151 BT_ASSERT(!ctx
->scopes
.packet_context
);
1152 BT_ASSERT(!ctx
->scopes
.event_header
);
1153 BT_ASSERT(!ctx
->scopes
.event_common_context
);
1156 if (!sc
->is_translated
) {
1157 ctx
->scopes
.packet_context
= sc
->packet_context_fc
;
1158 ret
= resolve_root_class(CTF_SCOPE_PACKET_CONTEXT
, ctx
);
1160 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet context field class: "
1166 ctx
->scopes
.event_header
= sc
->event_header_fc
;
1167 ret
= resolve_root_class(CTF_SCOPE_EVENT_HEADER
, ctx
);
1169 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event header field class: "
1175 ctx
->scopes
.event_common_context
= sc
->event_common_context_fc
;
1176 ret
= resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT
, ctx
);
1178 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
1179 "Cannot resolve event common context field class: "
1186 ctx
->scopes
.packet_context
= sc
->packet_context_fc
;
1187 ctx
->scopes
.event_header
= sc
->event_header_fc
;
1188 ctx
->scopes
.event_common_context
= sc
->event_common_context_fc
;
1190 for (i
= 0; i
< sc
->event_classes
->len
; i
++) {
1191 ctf_event_class
*ec
= (ctf_event_class
*) sc
->event_classes
->pdata
[i
];
1193 ret
= resolve_event_class_field_classes(ctx
, ec
);
1195 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event class's field classes: "
1196 "ec-id=%" PRIu64
", ec-name=\"%s\"",
1197 ec
->id
, ec
->name
->str
);
1203 ctx
->scopes
.packet_context
= NULL
;
1204 ctx
->scopes
.event_header
= NULL
;
1205 ctx
->scopes
.event_common_context
= NULL
;
1210 int ctf_trace_class_resolve_field_classes(struct ctf_trace_class
*tc
,
1211 struct meta_log_config
*log_cfg
)
1216 resolve_context local_ctx
{};
1217 local_ctx
.log_level
= log_cfg
->log_level
;
1218 local_ctx
.self_comp
= log_cfg
->self_comp
;
1219 local_ctx
.self_comp_class
= log_cfg
->self_comp_class
;
1221 local_ctx
.scopes
.packet_header
= tc
->packet_header_fc
;
1222 local_ctx
.root_scope
= CTF_SCOPE_PACKET_HEADER
;
1224 struct resolve_context
*ctx
= &local_ctx
;
1226 /* Initialize class stack */
1227 ctx
->field_class_stack
= field_class_stack_create();
1228 if (!ctx
->field_class_stack
) {
1229 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create field class stack.");
1234 if (!tc
->is_translated
) {
1235 ctx
->scopes
.packet_header
= tc
->packet_header_fc
;
1236 ret
= resolve_root_class(CTF_SCOPE_PACKET_HEADER
, ctx
);
1238 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet header field class: "
1245 ctx
->scopes
.packet_header
= tc
->packet_header_fc
;
1247 for (i
= 0; i
< tc
->stream_classes
->len
; i
++) {
1248 ctf_stream_class
*sc
= (ctf_stream_class
*) tc
->stream_classes
->pdata
[i
];
1250 ret
= resolve_stream_class_field_classes(ctx
, sc
);
1252 _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve stream class's field classes: "
1260 field_class_stack_destroy(ctx
->field_class_stack
);