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 #include <babeltrace2/babeltrace.h>
10 #include "common/assert.h"
11 #include "common/common.h"
12 #include "cpp-common/bt2c/logging.hpp"
13 #include "cpp-common/vendor/fmt/format.h"
15 #include "ctf-meta-visitors.hpp"
17 using field_class_stack_t
= GPtrArray
;
22 * `fc` contains a compound field class (structure, variant, array,
23 * or sequence) and `index` indicates the index of the field class in
24 * the upper frame (-1 for array and sequence field classes). `name`
25 * indicates the name of the field class in the upper frame (empty
26 * string for array and sequence field classes).
28 struct field_class_stack_frame
30 struct ctf_field_class
*fc
;
35 * The current context of the resolving engine.
37 struct resolve_context
39 explicit resolve_context(const bt2c::Logger
& parentLogger
) :
40 logger
{parentLogger
, "PLUGIN/CTF/META/RESOLVE"}
46 struct ctf_trace_class
*tc
= nullptr;
47 struct ctf_stream_class
*sc
= nullptr;
48 struct ctf_event_class
*ec
= nullptr;
52 struct ctf_field_class
*packet_header
= nullptr;
53 struct ctf_field_class
*packet_context
= nullptr;
54 struct ctf_field_class
*event_header
= nullptr;
55 struct ctf_field_class
*event_common_context
= nullptr;
56 struct ctf_field_class
*event_spec_context
= nullptr;
57 struct ctf_field_class
*event_payload
= nullptr;
60 /* Root scope being visited */
61 enum ctf_scope root_scope
= CTF_SCOPE_PACKET_HEADER
;
62 field_class_stack_t
*field_class_stack
= nullptr;
63 struct ctf_field_class
*cur_fc
= nullptr;
66 /* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
67 static const char * const absolute_path_prefixes
[] = {
68 /* CTF_SCOPE_PACKET_HEADER */ "trace.packet.header.",
69 /* CTF_SCOPE_PACKET_CONTEXT */ "stream.packet.context.",
70 /* CTF_SCOPE_EVENT_HEADER */ "stream.event.header.",
71 /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ "stream.event.context.",
72 /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ "event.context.",
73 /* CTF_SCOPE_EVENT_PAYLOAD */ "event.fields.",
76 /* Number of path tokens used for the absolute prefixes */
77 static const uint64_t absolute_path_prefix_ptoken_counts
[] = {
78 /* CTF_SCOPE_PACKET_HEADER */ 3,
79 /* CTF_SCOPE_PACKET_CONTEXT */ 3,
80 /* CTF_SCOPE_EVENT_HEADER */ 3,
81 /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ 3,
82 /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ 2,
83 /* CTF_SCOPE_EVENT_PAYLOAD */ 2,
86 static void destroy_field_class_stack_frame(struct field_class_stack_frame
*frame
)
96 * Creates a class stack.
98 static field_class_stack_t
*field_class_stack_create(void)
100 return g_ptr_array_new_with_free_func((GDestroyNotify
) destroy_field_class_stack_frame
);
104 * Destroys a class stack.
106 static void field_class_stack_destroy(field_class_stack_t
*stack
)
109 g_ptr_array_free(stack
, TRUE
);
114 * Pushes a field class onto a class stack.
116 static int field_class_stack_push(field_class_stack_t
*stack
, struct ctf_field_class
*fc
,
117 struct resolve_context
*ctx
)
120 struct field_class_stack_frame
*frame
= NULL
;
123 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
124 "Invalid parameter: stack or field class is `NULL`.");
129 frame
= g_new0(struct field_class_stack_frame
, 1);
131 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
132 "Failed to allocate one field class stack frame.");
137 BT_CPPLOGD_SPEC(ctx
->logger
,
138 "Pushing field class on context's stack: "
139 "fc-addr={}, stack-size-before={}",
140 fmt::ptr(fc
), stack
->len
);
142 g_ptr_array_add(stack
, frame
);
149 * Checks whether or not `stack` is empty.
151 static bool field_class_stack_empty(field_class_stack_t
*stack
)
153 return stack
->len
== 0;
157 * Returns the number of frames in `stack`.
159 static size_t field_class_stack_size(field_class_stack_t
*stack
)
165 * Returns the top frame of `stack`.
167 static struct field_class_stack_frame
*field_class_stack_peek(field_class_stack_t
*stack
)
170 BT_ASSERT(!field_class_stack_empty(stack
));
172 return (field_class_stack_frame
*) g_ptr_array_index(stack
, stack
->len
- 1);
176 * Returns the frame at index `index` in `stack`.
178 static struct field_class_stack_frame
*field_class_stack_at(field_class_stack_t
*stack
,
182 BT_ASSERT(index
< stack
->len
);
184 return (field_class_stack_frame
*) g_ptr_array_index(stack
, index
);
188 * Removes the top frame of `stack`.
190 static void field_class_stack_pop(field_class_stack_t
*stack
, struct resolve_context
*ctx
)
192 if (!field_class_stack_empty(stack
)) {
194 * This will call the frame's destructor and free it, as
195 * well as put its contained field class.
197 BT_CPPLOGD_SPEC(ctx
->logger
, "Popping context's stack: stack-size-before={}", stack
->len
);
198 g_ptr_array_set_size(stack
, stack
->len
- 1);
203 * Returns the scope field class of `scope` in the context `ctx`.
205 static struct ctf_field_class
*borrow_class_from_ctx(struct resolve_context
*ctx
,
206 enum ctf_scope scope
)
209 case CTF_SCOPE_PACKET_HEADER
:
210 return ctx
->scopes
.packet_header
;
211 case CTF_SCOPE_PACKET_CONTEXT
:
212 return ctx
->scopes
.packet_context
;
213 case CTF_SCOPE_EVENT_HEADER
:
214 return ctx
->scopes
.event_header
;
215 case CTF_SCOPE_EVENT_COMMON_CONTEXT
:
216 return ctx
->scopes
.event_common_context
;
217 case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT
:
218 return ctx
->scopes
.event_spec_context
;
219 case CTF_SCOPE_EVENT_PAYLOAD
:
220 return ctx
->scopes
.event_payload
;
229 * Returns the CTF scope from a path string. May return -1 if the path
230 * is found to be relative.
232 static enum ctf_scope
get_root_scope_from_absolute_pathstr(const char *pathstr
,
233 struct resolve_context
*ctx
)
235 enum ctf_scope scope
;
236 enum ctf_scope ret
= CTF_SCOPE_PACKET_UNKNOWN
;
237 const size_t prefixes_count
= sizeof(absolute_path_prefixes
) / sizeof(*absolute_path_prefixes
);
239 for (scope
= CTF_SCOPE_PACKET_HEADER
; scope
< CTF_SCOPE_PACKET_HEADER
+ prefixes_count
;
240 scope
= (ctf_scope
) (scope
+ 1)) {
242 * Check if path string starts with a known absolute
245 * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
247 if (strncmp(pathstr
, absolute_path_prefixes
[scope
],
248 strlen(absolute_path_prefixes
[scope
]))) {
249 /* Prefix does not match: try the next one */
250 BT_CPPLOGD_SPEC(ctx
->logger
,
251 "Prefix does not match: trying the next one: "
252 "path=\"{}\", path-prefix=\"{}\", scope={}",
253 pathstr
, absolute_path_prefixes
[scope
], scope
);
259 BT_CPPLOGD_SPEC(ctx
->logger
,
260 "Found root scope from absolute path: "
261 "path=\"{}\", scope={}",
271 * Destroys a path token.
273 static void ptokens_destroy_func(gpointer ptoken
, gpointer
)
275 g_string_free((GString
*) ptoken
, TRUE
);
279 * Destroys a path token list.
281 static void ptokens_destroy(GList
*ptokens
)
287 g_list_foreach(ptokens
, ptokens_destroy_func
, NULL
);
288 g_list_free(ptokens
);
292 * Returns the string contained in a path token.
294 static const char *ptoken_get_string(GList
*ptoken
)
296 GString
*tokenstr
= (GString
*) ptoken
->data
;
298 return tokenstr
->str
;
302 * Converts a path string to a path token list, that is, splits the
303 * individual words of a path string into a list of individual
306 static GList
*pathstr_to_ptokens(const char *pathstr
, struct resolve_context
*ctx
)
308 const char *at
= pathstr
;
309 const char *last
= at
;
310 GList
*ptokens
= NULL
;
313 if (*at
== '.' || *at
== '\0') {
317 /* Error: empty token */
318 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
, "Empty path token: path=\"{}\", pos={}",
319 pathstr
, (unsigned int) (at
- pathstr
));
323 tokenstr
= g_string_new(NULL
);
324 g_string_append_len(tokenstr
, last
, at
- last
);
325 ptokens
= g_list_append(ptokens
, tokenstr
);
339 ptokens_destroy(ptokens
);
344 * Converts a path token list to a field path object. The path token
345 * list is relative from `fc`. The index of the source looking for its
346 * target within `fc` is indicated by `src_index`. This can be
347 * `INT64_MAX` if the source is contained in `fc`.
349 * `field_path` is an output parameter owned by the caller that must be
352 static int ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
353 struct ctf_field_class
*fc
, int64_t src_index
,
354 struct resolve_context
*ctx
)
357 GList
*cur_ptoken
= ptokens
;
358 bool first_level_done
= false;
363 struct ctf_field_class
*child_fc
;
364 const char *ft_name
= ptoken_get_string(cur_ptoken
);
366 BT_CPPLOGD_SPEC(ctx
->logger
, "Current path token: token=\"{}\"", ft_name
);
368 /* Find to which index corresponds the current path token */
369 if (fc
->type
== CTF_FIELD_CLASS_TYPE_ARRAY
|| fc
->type
== CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
373 ctf_field_class_compound_get_field_class_index_from_orig_name(fc
, ft_name
);
374 if (child_index
< 0) {
376 * Error: field name does not exist or
377 * wrong current class.
379 BT_CPPLOGD_SPEC(ctx
->logger
,
380 "Cannot get index of field class: "
381 "field-name=\"{}\", "
384 "first-level-done={}",
385 ft_name
, src_index
, child_index
, first_level_done
);
388 } else if (child_index
> src_index
&& !first_level_done
) {
389 BT_CPPLOGD_SPEC(ctx
->logger
,
390 "Child field class is located after source field class: "
391 "field-name=\"{}\", "
394 "first-level-done={}",
395 ft_name
, src_index
, child_index
, first_level_done
);
400 /* Next path token */
401 cur_ptoken
= g_list_next(cur_ptoken
);
402 first_level_done
= true;
405 /* Create new field path entry */
406 ctf_field_path_append_index(field_path
, child_index
);
408 /* Get child field class */
409 child_fc
= ctf_field_class_compound_borrow_field_class_by_index(fc
, child_index
);
412 /* Move child class to current class */
421 * Converts a known absolute path token list to a field path object
422 * within the resolving context `ctx`.
424 * `field_path` is an output parameter owned by the caller that must be
427 static int absolute_ptokens_to_field_path(GList
*ptokens
, struct ctf_field_path
*field_path
,
428 struct resolve_context
*ctx
)
432 struct ctf_field_class
*fc
;
435 * Make sure we're not referring to a scope within a translated
438 switch (field_path
->root
) {
439 case CTF_SCOPE_PACKET_HEADER
:
440 if (ctx
->tc
->is_translated
) {
441 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
442 "Trace class is already translated: "
450 case CTF_SCOPE_PACKET_CONTEXT
:
451 case CTF_SCOPE_EVENT_HEADER
:
452 case CTF_SCOPE_EVENT_COMMON_CONTEXT
:
454 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
455 "No current stream class: "
462 if (ctx
->sc
->is_translated
) {
463 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
464 "Stream class is already translated: "
472 case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT
:
473 case CTF_SCOPE_EVENT_PAYLOAD
:
475 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
476 "No current event class: "
483 if (ctx
->ec
->is_translated
) {
484 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
485 "Event class is already translated: "
498 /* Skip absolute path tokens */
499 cur_ptoken
= g_list_nth(ptokens
, absolute_path_prefix_ptoken_counts
[field_path
->root
]);
501 /* Start with root class */
502 fc
= borrow_class_from_ctx(ctx
, field_path
->root
);
504 /* Error: root class is not available */
505 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
506 "Root field class is not available: "
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_CPPLOGD_SPEC(ctx
->logger
,
544 "Locating target field class from current parent field class: "
545 "parent-pos={}, parent-fc-addr={}, "
547 parent_pos_in_stack
, fmt::ptr(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_CPPLOGD_STR_SPEC(ctx
->logger
, "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_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
608 "Cannot convert path string to path tokens: "
615 /* Absolute or relative path? */
616 root_scope
= get_root_scope_from_absolute_pathstr(pathstr
, ctx
);
618 if (root_scope
== CTF_SCOPE_PACKET_UNKNOWN
) {
619 /* Relative path: start with current root scope */
620 field_path
->root
= ctx
->root_scope
;
621 BT_CPPLOGD_SPEC(ctx
->logger
,
622 "Detected relative path: starting with current root scope: "
625 ret
= relative_ptokens_to_field_path(ptokens
, field_path
, ctx
);
627 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
628 "Cannot get relative field path of path string: "
629 "path=\"{}\", start-scope={}, end-scope={}",
630 pathstr
, ctx
->root_scope
, field_path
->root
);
634 /* Absolute path: use found root scope */
635 field_path
->root
= root_scope
;
636 BT_CPPLOGD_SPEC(ctx
->logger
,
637 "Detected absolute path: using root scope: "
640 ret
= absolute_ptokens_to_field_path(ptokens
, field_path
, ctx
);
642 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
643 "Cannot get absolute field path of path string: "
644 "path=\"{}\", root-scope={}",
645 pathstr
, root_scope
);
651 BT_CPPLOGD_SPEC(ctx
->logger
, "Found field path: path=\"{}\", field-path=\"{}\"", pathstr
,
656 ptokens_destroy(ptokens
);
661 * Retrieves a field class by following the field path `field_path` in
662 * the resolving context `ctx`.
664 static struct ctf_field_class
*field_path_to_field_class(struct ctf_field_path
*field_path
,
665 struct resolve_context
*ctx
)
668 struct ctf_field_class
*fc
;
670 /* Start with root class */
671 fc
= borrow_class_from_ctx(ctx
, field_path
->root
);
673 /* Error: root class is not available */
674 BT_CPPLOGE_APPEND_CAUSE_SPEC(
675 ctx
->logger
, "Root field class is not available: root-scope={}", field_path
->root
);
680 for (i
= 0; i
< field_path
->path
->len
; i
++) {
681 struct ctf_field_class
*child_fc
;
682 int64_t child_index
= ctf_field_path_borrow_index_by_index(field_path
, i
);
684 /* Get child field class */
685 child_fc
= ctf_field_class_compound_borrow_field_class_by_index(fc
, child_index
);
688 /* Move child class to current class */
697 * Fills the equivalent field path object of the context class stack.
699 static void get_ctx_stack_field_path(struct resolve_context
*ctx
, struct ctf_field_path
*field_path
)
703 BT_ASSERT(field_path
);
704 field_path
->root
= ctx
->root_scope
;
705 ctf_field_path_clear(field_path
);
707 for (i
= 0; i
< field_class_stack_size(ctx
->field_class_stack
); i
++) {
708 struct field_class_stack_frame
*frame
= field_class_stack_at(ctx
->field_class_stack
, i
);
710 ctf_field_path_append_index(field_path
, frame
->index
);
715 * Returns the index of the lowest common ancestor of two field path
716 * objects having the same root scope.
718 static int64_t get_field_paths_lca_index(struct ctf_field_path
*field_path1
,
719 struct ctf_field_path
*field_path2
,
720 struct resolve_context
*ctx
)
722 int64_t lca_index
= 0;
723 uint64_t field_path1_len
, field_path2_len
;
725 BT_CPPLOGD_SPEC(ctx
->logger
,
726 "Finding lowest common ancestor (LCA) between two field paths: "
727 "field-path-1=\"{}\", field-path-2=\"{}\"",
728 *field_path1
, *field_path2
);
731 * Start from both roots and find the first mismatch.
733 BT_ASSERT(field_path1
->root
== field_path2
->root
);
734 field_path1_len
= field_path1
->path
->len
;
735 field_path2_len
= field_path2
->path
->len
;
738 int64_t target_index
, ctx_index
;
740 if (lca_index
== (int64_t) field_path2_len
|| lca_index
== (int64_t) field_path1_len
) {
742 * This means that both field paths never split.
743 * This is invalid because the target cannot be
744 * an ancestor of the source.
746 BT_CPPLOGE_APPEND_CAUSE_SPEC(
748 "Source field class is an ancestor of target field class or vice versa: "
750 "field-path-1-len={}, "
751 "field-path-2-len={}",
752 lca_index
, field_path1_len
, field_path2_len
);
757 target_index
= ctf_field_path_borrow_index_by_index(field_path1
, lca_index
);
758 ctx_index
= ctf_field_path_borrow_index_by_index(field_path2
, lca_index
);
760 if (target_index
!= ctx_index
) {
761 /* LCA index is the previous */
768 BT_CPPLOGD_SPEC(ctx
->logger
, "Found LCA: lca-index={}", lca_index
);
773 * Validates a target field path.
775 static int validate_target_field_path(struct ctf_field_path
*target_field_path
,
776 struct ctf_field_class
*target_fc
,
777 struct resolve_context
*ctx
)
780 struct ctf_field_path ctx_field_path
;
781 uint64_t target_field_path_len
= target_field_path
->path
->len
;
784 /* Get context field path */
785 ctf_field_path_init(&ctx_field_path
);
786 get_ctx_stack_field_path(ctx
, &ctx_field_path
);
789 * Make sure the target is not a root.
791 if (target_field_path_len
== 0) {
792 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
793 "Target field path's length is 0 (targeting the root).");
799 * Make sure the root of the target field path is not located
800 * after the context field path's root.
802 if (target_field_path
->root
> ctx_field_path
.root
) {
803 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
804 "Target field class is located after source field class: "
805 "target-root={}, source-root={}",
806 target_field_path
->root
, ctx_field_path
.root
);
811 if (target_field_path
->root
== ctx_field_path
.root
) {
812 int64_t target_index
, ctx_index
;
815 * Find the index of the lowest common ancestor of both field
818 lca_index
= get_field_paths_lca_index(target_field_path
, &ctx_field_path
, ctx
);
820 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
, "Cannot get least common ancestor.");
826 * Make sure the target field path is located before the
827 * context field path.
830 ctf_field_path_borrow_index_by_index(target_field_path
, (uint64_t) lca_index
);
831 ctx_index
= ctf_field_path_borrow_index_by_index(&ctx_field_path
, (uint64_t) lca_index
);
833 if (target_index
>= ctx_index
) {
834 BT_CPPLOGE_APPEND_CAUSE_SPEC(
836 "Target field class's index is greater than or equal to source field class's index in LCA: "
840 lca_index
, target_index
, ctx_index
);
847 * Make sure the target class has the right class and properties.
849 switch (ctx
->cur_fc
->type
) {
850 case CTF_FIELD_CLASS_TYPE_VARIANT
:
851 if (target_fc
->type
!= CTF_FIELD_CLASS_TYPE_ENUM
) {
852 BT_CPPLOGE_APPEND_CAUSE_SPEC(
854 "Variant field class's tag field class is not an enumeration field class: "
855 "tag-fc-addr={}, tag-fc-id={}",
856 fmt::ptr(target_fc
), (int) target_fc
->type
);
861 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
863 if (target_fc
->type
!= CTF_FIELD_CLASS_TYPE_INT
&&
864 target_fc
->type
!= CTF_FIELD_CLASS_TYPE_ENUM
) {
865 BT_CPPLOGE_APPEND_CAUSE_SPEC(
867 "Sequence field class's length field class is not an unsigned integer field class: "
868 "length-fc-addr={}, length-fc-id={}",
869 fmt::ptr(target_fc
), (int) target_fc
->type
);
874 ctf_field_class_int
*int_fc
= ctf_field_class_as_int(target_fc
);
876 if (int_fc
->is_signed
) {
877 BT_CPPLOGE_APPEND_CAUSE_SPEC(
879 "Sequence field class's length field class is not an unsigned integer field class: "
880 "length-fc-addr={}, length-fc-id={}",
881 fmt::ptr(target_fc
), (int) target_fc
->type
);
892 ctf_field_path_fini(&ctx_field_path
);
897 * Resolves a variant or sequence field class `fc`.
899 static int resolve_sequence_or_variant_field_class(struct ctf_field_class
*fc
,
900 struct resolve_context
*ctx
)
904 struct ctf_field_path target_field_path
;
905 struct ctf_field_class
*target_fc
= NULL
;
907 ctf_field_path_init(&target_field_path
);
909 /* Get path string */
911 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
913 struct ctf_field_class_sequence
*seq_fc
= ctf_field_class_as_sequence(fc
);
914 pathstr
= seq_fc
->length_ref
->str
;
917 case CTF_FIELD_CLASS_TYPE_VARIANT
:
919 struct ctf_field_class_variant
*var_fc
= ctf_field_class_as_variant(fc
);
920 pathstr
= var_fc
->tag_ref
->str
;
928 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
, "Cannot get path string.");
933 /* Get target field path out of path string */
934 ret
= pathstr_to_field_path(pathstr
, &target_field_path
, ctx
);
936 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
937 "Cannot get target field path for path string: "
943 /* Get target field class */
944 target_fc
= field_path_to_field_class(&target_field_path
, ctx
);
946 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
947 "Cannot get target field class for path string: "
948 "path=\"{}\", target-field-path=\"{}\"",
949 pathstr
, target_field_path
);
954 ret
= validate_target_field_path(&target_field_path
, target_fc
, ctx
);
956 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
957 "Invalid target field path for path string: "
958 "path=\"{}\", target-field-path=\"{}\"",
959 pathstr
, target_field_path
);
963 /* Set target field path and target field class */
965 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
967 ctf_field_class_sequence
*seq_fc
= ctf_field_class_as_sequence(fc
);
969 ctf_field_path_copy_content(&seq_fc
->length_path
, &target_field_path
);
970 seq_fc
->length_fc
= ctf_field_class_as_int(target_fc
);
973 case CTF_FIELD_CLASS_TYPE_VARIANT
:
975 ctf_field_class_variant
*var_fc
= ctf_field_class_as_variant(fc
);
977 ctf_field_path_copy_content(&var_fc
->tag_path
, &target_field_path
);
978 ctf_field_class_variant_set_tag_field_class(var_fc
, ctf_field_class_as_enum(target_fc
));
986 ctf_field_path_fini(&target_field_path
);
991 * Resolves a field class `fc`.
993 static int resolve_field_class(struct ctf_field_class
*fc
, struct resolve_context
*ctx
)
998 /* Field class is not available; still valid */
1004 /* Resolve sequence/variant field class */
1006 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1007 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1008 ret
= resolve_sequence_or_variant_field_class(fc
, ctx
);
1010 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1012 "Cannot resolve sequence field class's length or variant field class's tag: "
1013 "ret={}, fc-addr={}",
1023 /* Recurse into compound classes */
1025 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1026 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1027 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1028 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1031 uint64_t field_count
= ctf_field_class_compound_get_field_class_count(fc
);
1033 ret
= field_class_stack_push(ctx
->field_class_stack
, fc
, ctx
);
1035 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1036 "Cannot push field class on context's stack: "
1042 for (i
= 0; i
< field_count
; i
++) {
1043 struct ctf_field_class
*child_fc
=
1044 ctf_field_class_compound_borrow_field_class_by_index(fc
, i
);
1046 BT_ASSERT(child_fc
);
1048 if (fc
->type
== CTF_FIELD_CLASS_TYPE_ARRAY
||
1049 fc
->type
== CTF_FIELD_CLASS_TYPE_SEQUENCE
) {
1050 field_class_stack_peek(ctx
->field_class_stack
)->index
= -1;
1052 field_class_stack_peek(ctx
->field_class_stack
)->index
= (int64_t) i
;
1055 BT_CPPLOGD_SPEC(ctx
->logger
,
1056 "Resolving field class's child field class: "
1057 "parent-fc-addr={}, child-fc-addr={}, "
1058 "index={}, count={}",
1059 fmt::ptr(fc
), fmt::ptr(child_fc
), i
, field_count
);
1060 ret
= resolve_field_class(child_fc
, ctx
);
1066 field_class_stack_pop(ctx
->field_class_stack
, ctx
);
1078 * Resolves the root field class corresponding to the scope `root_scope`.
1080 static int resolve_root_class(enum ctf_scope root_scope
, struct resolve_context
*ctx
)
1084 BT_ASSERT(field_class_stack_size(ctx
->field_class_stack
) == 0);
1085 ctx
->root_scope
= root_scope
;
1086 ret
= resolve_field_class(borrow_class_from_ctx(ctx
, root_scope
), ctx
);
1087 ctx
->root_scope
= CTF_SCOPE_PACKET_UNKNOWN
;
1091 static int resolve_event_class_field_classes(struct resolve_context
*ctx
,
1092 struct ctf_event_class
*ec
)
1096 BT_ASSERT(!ctx
->scopes
.event_spec_context
);
1097 BT_ASSERT(!ctx
->scopes
.event_payload
);
1099 if (ec
->is_translated
) {
1104 ctx
->scopes
.event_spec_context
= ec
->spec_context_fc
;
1105 ret
= resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT
, ctx
);
1107 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1108 "Cannot resolve event specific context field class: "
1114 ctx
->scopes
.event_payload
= ec
->payload_fc
;
1115 ret
= resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD
, ctx
);
1117 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1118 "Cannot resolve event payload field class: "
1125 ctx
->scopes
.event_spec_context
= NULL
;
1126 ctx
->scopes
.event_payload
= NULL
;
1131 static int resolve_stream_class_field_classes(struct resolve_context
*ctx
,
1132 struct ctf_stream_class
*sc
)
1137 BT_ASSERT(!ctx
->scopes
.packet_context
);
1138 BT_ASSERT(!ctx
->scopes
.event_header
);
1139 BT_ASSERT(!ctx
->scopes
.event_common_context
);
1142 if (!sc
->is_translated
) {
1143 ctx
->scopes
.packet_context
= sc
->packet_context_fc
;
1144 ret
= resolve_root_class(CTF_SCOPE_PACKET_CONTEXT
, ctx
);
1146 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1147 "Cannot resolve packet context field class: "
1153 ctx
->scopes
.event_header
= sc
->event_header_fc
;
1154 ret
= resolve_root_class(CTF_SCOPE_EVENT_HEADER
, ctx
);
1156 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1157 "Cannot resolve event header field class: "
1163 ctx
->scopes
.event_common_context
= sc
->event_common_context_fc
;
1164 ret
= resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT
, ctx
);
1166 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1167 "Cannot resolve event common context field class: "
1174 ctx
->scopes
.packet_context
= sc
->packet_context_fc
;
1175 ctx
->scopes
.event_header
= sc
->event_header_fc
;
1176 ctx
->scopes
.event_common_context
= sc
->event_common_context_fc
;
1178 for (i
= 0; i
< sc
->event_classes
->len
; i
++) {
1179 ctf_event_class
*ec
= (ctf_event_class
*) sc
->event_classes
->pdata
[i
];
1181 ret
= resolve_event_class_field_classes(ctx
, ec
);
1183 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1184 "Cannot resolve event class's field classes: "
1185 "ec-id={}, ec-name=\"{}\"",
1186 ec
->id
, ec
->name
->str
);
1192 ctx
->scopes
.packet_context
= NULL
;
1193 ctx
->scopes
.event_header
= NULL
;
1194 ctx
->scopes
.event_common_context
= NULL
;
1199 int ctf_trace_class_resolve_field_classes(struct ctf_trace_class
*tc
,
1200 const bt2c::Logger
& parentLogger
)
1205 resolve_context
local_ctx(parentLogger
);
1207 local_ctx
.scopes
.packet_header
= tc
->packet_header_fc
;
1208 local_ctx
.root_scope
= CTF_SCOPE_PACKET_HEADER
;
1210 struct resolve_context
*ctx
= &local_ctx
;
1212 /* Initialize class stack */
1213 ctx
->field_class_stack
= field_class_stack_create();
1214 if (!ctx
->field_class_stack
) {
1215 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
, "Cannot create field class stack.");
1220 if (!tc
->is_translated
) {
1221 ctx
->scopes
.packet_header
= tc
->packet_header_fc
;
1222 ret
= resolve_root_class(CTF_SCOPE_PACKET_HEADER
, ctx
);
1224 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1225 "Cannot resolve packet header field class: "
1232 ctx
->scopes
.packet_header
= tc
->packet_header_fc
;
1234 for (i
= 0; i
< tc
->stream_classes
->len
; i
++) {
1235 ctf_stream_class
*sc
= (ctf_stream_class
*) tc
->stream_classes
->pdata
[i
];
1237 ret
= resolve_stream_class_field_classes(ctx
, sc
);
1239 BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx
->logger
,
1240 "Cannot resolve stream class's field classes: "
1248 field_class_stack_destroy(ctx
->field_class_stack
);