2 * SPDX-License-Identifier: MIT
4 * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
7 #define BT_LOG_TAG "LIB/RESOLVE-FIELD-PATH"
8 #include "lib/logging.h"
10 #include "lib/assert-cond.h"
11 #include "common/assert.h"
12 #include <babeltrace2/trace-ir/field-path.h>
17 #include "field-class.h"
18 #include "field-path.h"
19 #include "resolve-field-path.h"
20 #include "common/common.h"
23 bool find_field_class_recursive(struct bt_field_class
*fc
,
24 struct bt_field_class
*tgt_fc
, struct bt_field_path
*field_path
)
33 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
34 struct bt_field_class_option
*opt_fc
= (void *) fc
;
35 struct bt_field_path_item item
= {
36 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
,
37 .index
= UINT64_C(-1),
40 bt_field_path_append_item(field_path
, &item
);
41 found
= find_field_class_recursive(opt_fc
->content_fc
,
47 bt_field_path_remove_last_item(field_path
);
48 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
49 bt_field_class_type_is(fc
->type
,
50 BT_FIELD_CLASS_TYPE_VARIANT
)) {
51 struct bt_field_class_named_field_class_container
*container_fc
=
55 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
56 struct bt_named_field_class
*named_fc
=
57 container_fc
->named_fcs
->pdata
[i
];
58 struct bt_field_path_item item
= {
59 .type
= BT_FIELD_PATH_ITEM_TYPE_INDEX
,
63 bt_field_path_append_item(field_path
, &item
);
64 found
= find_field_class_recursive(named_fc
->fc
,
70 bt_field_path_remove_last_item(field_path
);
72 } else if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
73 struct bt_field_class_array
*array_fc
= (void *) fc
;
74 struct bt_field_path_item item
= {
75 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
,
76 .index
= UINT64_C(-1),
79 bt_field_path_append_item(field_path
, &item
);
80 found
= find_field_class_recursive(array_fc
->element_fc
,
86 bt_field_path_remove_last_item(field_path
);
94 enum bt_resolve_field_xref_status
find_field_class(
95 struct bt_field_class
*root_fc
,
96 enum bt_field_path_scope root_scope
,
97 struct bt_field_class
*tgt_fc
,
98 struct bt_field_path
**ret_field_path
)
100 enum bt_resolve_field_xref_status ret
;
101 struct bt_field_path
*field_path
= NULL
;
104 ret
= BT_RESOLVE_FIELD_XREF_STATUS_OK
;
108 field_path
= bt_field_path_create();
110 ret
= BT_RESOLVE_FIELD_XREF_STATUS_MEMORY_ERROR
;
114 field_path
->root
= root_scope
;
115 if (!find_field_class_recursive(root_fc
, tgt_fc
, field_path
)) {
117 BT_OBJECT_PUT_REF_AND_RESET(field_path
);
120 ret
= BT_RESOLVE_FIELD_XREF_STATUS_OK
;
123 *ret_field_path
= field_path
;
128 enum bt_resolve_field_xref_status
find_field_class_in_ctx(
129 struct bt_field_class
*fc
,
130 struct bt_resolve_field_xref_context
*ctx
,
131 struct bt_field_path
**ret_field_path
)
133 enum bt_resolve_field_xref_status ret
;
135 *ret_field_path
= NULL
;
137 ret
= find_field_class(ctx
->packet_context
,
138 BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
, fc
, ret_field_path
);
139 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
143 ret
= find_field_class(ctx
->event_common_context
,
144 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, fc
, ret_field_path
);
145 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
149 ret
= find_field_class(ctx
->event_specific_context
,
150 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, ret_field_path
);
151 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
155 ret
= find_field_class(ctx
->event_payload
,
156 BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
, fc
, ret_field_path
);
157 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
165 BT_ASSERT_COND_DEV_FUNC
167 bool target_is_before_source(struct bt_field_path
*src_field_path
,
168 struct bt_field_path
*tgt_field_path
)
170 bool is_valid
= true;
171 uint64_t src_i
= 0, tgt_i
= 0;
173 if (tgt_field_path
->root
< src_field_path
->root
) {
177 if (tgt_field_path
->root
> src_field_path
->root
) {
182 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
184 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
185 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
186 struct bt_field_path_item
*src_fp_item
=
187 bt_field_path_borrow_item_by_index_inline(
188 src_field_path
, src_i
);
189 struct bt_field_path_item
*tgt_fp_item
=
190 bt_field_path_borrow_item_by_index_inline(
191 tgt_field_path
, tgt_i
);
193 if (src_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
&&
194 tgt_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
195 if (tgt_fp_item
->index
> src_fp_item
->index
) {
209 BT_ASSERT_COND_DEV_FUNC
211 struct bt_field_class
*borrow_root_field_class(
212 struct bt_resolve_field_xref_context
*ctx
,
213 enum bt_field_path_scope scope
)
216 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
217 return ctx
->packet_context
;
218 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
219 return ctx
->event_common_context
;
220 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
221 return ctx
->event_specific_context
;
222 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
223 return ctx
->event_payload
;
231 BT_ASSERT_COND_DEV_FUNC
233 struct bt_field_class
*borrow_child_field_class(
234 struct bt_field_class
*parent_fc
,
235 struct bt_field_path_item
*fp_item
)
237 struct bt_field_class
*child_fc
= NULL
;
239 if (bt_field_class_type_is(parent_fc
->type
,
240 BT_FIELD_CLASS_TYPE_OPTION
)) {
241 struct bt_field_class_option
*opt_fc
= (void *) parent_fc
;
243 BT_ASSERT(fp_item
->type
==
244 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
);
245 child_fc
= opt_fc
->content_fc
;
246 } else if (parent_fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
247 bt_field_class_type_is(parent_fc
->type
,
248 BT_FIELD_CLASS_TYPE_VARIANT
)) {
249 struct bt_field_class_named_field_class_container
*container_fc
=
251 struct bt_named_field_class
*named_fc
;
253 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
254 named_fc
= container_fc
->named_fcs
->pdata
[fp_item
->index
];
255 child_fc
= named_fc
->fc
;
256 } else if (bt_field_class_type_is(parent_fc
->type
,
257 BT_FIELD_CLASS_TYPE_ARRAY
)) {
258 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
260 BT_ASSERT(fp_item
->type
==
261 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
262 child_fc
= array_fc
->element_fc
;
268 BT_ASSERT_COND_DEV_FUNC
270 bool target_field_path_in_different_scope_has_struct_fc_only(
271 struct bt_field_path
*src_field_path
,
272 struct bt_field_path
*tgt_field_path
,
273 struct bt_resolve_field_xref_context
*ctx
)
275 bool is_valid
= true;
277 struct bt_field_class
*fc
;
279 if (src_field_path
->root
== tgt_field_path
->root
) {
283 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
285 for (i
= 0; i
< tgt_field_path
->items
->len
; i
++) {
286 struct bt_field_path_item
*fp_item
=
287 bt_field_path_borrow_item_by_index_inline(
290 if (bt_field_class_type_is(fc
->type
,
291 BT_FIELD_CLASS_TYPE_ARRAY
) ||
292 bt_field_class_type_is(fc
->type
,
293 BT_FIELD_CLASS_TYPE_OPTION
) ||
294 bt_field_class_type_is(fc
->type
,
295 BT_FIELD_CLASS_TYPE_VARIANT
)) {
300 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
301 fc
= borrow_child_field_class(fc
, fp_item
);
308 BT_ASSERT_COND_DEV_FUNC
310 bool lca_is_structure_field_class(struct bt_field_path
*src_field_path
,
311 struct bt_field_path
*tgt_field_path
,
312 struct bt_resolve_field_xref_context
*ctx
)
314 bool is_valid
= true;
315 struct bt_field_class
*src_fc
;
316 struct bt_field_class
*tgt_fc
;
317 struct bt_field_class
*prev_fc
= NULL
;
318 uint64_t src_i
= 0, tgt_i
= 0;
320 if (src_field_path
->root
!= tgt_field_path
->root
) {
324 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
325 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
329 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
330 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
331 struct bt_field_path_item
*src_fp_item
=
332 bt_field_path_borrow_item_by_index_inline(
333 src_field_path
, src_i
);
334 struct bt_field_path_item
*tgt_fp_item
=
335 bt_field_path_borrow_item_by_index_inline(
336 tgt_field_path
, tgt_i
);
338 if (src_fc
!= tgt_fc
) {
341 * This is correct: the LCA is the root
342 * scope field class, which must be a
343 * structure field class.
348 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
356 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
357 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
364 BT_ASSERT_COND_DEV_FUNC
366 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
367 struct bt_field_path
*tgt_field_path
,
368 struct bt_resolve_field_xref_context
*ctx
)
370 bool is_valid
= true;
371 struct bt_field_class
*src_fc
;
372 struct bt_field_class
*tgt_fc
;
373 uint64_t src_i
= 0, tgt_i
= 0;
375 if (src_field_path
->root
!= tgt_field_path
->root
) {
379 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
380 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
383 BT_ASSERT(src_fc
== tgt_fc
);
386 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
387 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
388 struct bt_field_path_item
*src_fp_item
=
389 bt_field_path_borrow_item_by_index_inline(
390 src_field_path
, src_i
);
391 struct bt_field_path_item
*tgt_fp_item
=
392 bt_field_path_borrow_item_by_index_inline(
393 tgt_field_path
, tgt_i
);
395 if (src_i
!= tgt_i
) {
396 /* Next field class is different: LCA is `tgt_fc` */
400 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
401 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
404 /* Only structure field classes to the target */
405 for (; tgt_i
< tgt_field_path
->items
->len
; tgt_i
++) {
406 struct bt_field_path_item
*tgt_fp_item
=
407 bt_field_path_borrow_item_by_index_inline(
408 tgt_field_path
, tgt_i
);
410 if (bt_field_class_type_is(tgt_fc
->type
,
411 BT_FIELD_CLASS_TYPE_ARRAY
) ||
412 bt_field_class_type_is(tgt_fc
->type
,
413 BT_FIELD_CLASS_TYPE_OPTION
) ||
414 bt_field_class_type_is(tgt_fc
->type
,
415 BT_FIELD_CLASS_TYPE_VARIANT
)) {
420 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
427 BT_ASSERT_COND_DEV_FUNC
429 bool field_path_is_valid(struct bt_field_class
*src_fc
,
430 struct bt_field_class
*tgt_fc
,
431 struct bt_resolve_field_xref_context
*ctx
)
433 struct bt_field_path
*src_field_path
;
434 struct bt_field_path
*tgt_field_path
= NULL
;
435 enum bt_resolve_field_xref_status status
;
438 status
= find_field_class_in_ctx(src_fc
, ctx
, &src_field_path
);
439 BT_ASSERT(status
== BT_RESOLVE_FIELD_XREF_STATUS_OK
);
441 if (!src_field_path
) {
442 BT_ASSERT_COND_DEV_MSG("Cannot find requesting field class in "
443 "resolving context: %!+F", src_fc
);
448 status
= find_field_class_in_ctx(tgt_fc
, ctx
, &tgt_field_path
);
449 BT_ASSERT(status
== BT_RESOLVE_FIELD_XREF_STATUS_OK
);
451 if (!tgt_field_path
) {
452 BT_ASSERT_COND_DEV_MSG("Cannot find target field class in "
453 "resolving context: %!+F", tgt_fc
);
458 /* Target must be before source */
459 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
460 BT_ASSERT_COND_DEV_MSG("Target field class is located after "
461 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
468 * If target is in a different scope than source, there are no
469 * array or variant field classes on the way to the target.
471 if (!target_field_path_in_different_scope_has_struct_fc_only(
472 src_field_path
, tgt_field_path
, ctx
)) {
473 BT_ASSERT_COND_DEV_MSG("Target field class is located in a "
474 "different scope than requesting field class, "
475 "but within an array or a variant field class: "
476 "%![req-fc-]+F, %![tgt-fc-]+F",
482 /* Same scope: LCA must be a structure field class */
483 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
484 BT_ASSERT_COND_DEV_MSG("Lowest common ancestor of target and "
485 "requesting field classes is not a structure field class: "
486 "%![req-fc-]+F, %![tgt-fc-]+F",
492 /* Same scope: path from LCA to target has no array/variant FTs */
493 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
495 BT_ASSERT_COND_DEV_MSG("Path from lowest common ancestor of target "
496 "and requesting field classes to target field class "
497 "contains an array or a variant field class: "
498 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
506 bt_object_put_ref(src_field_path
);
507 bt_object_put_ref(tgt_field_path
);
512 enum bt_resolve_field_xref_status
resolve_field_path(
513 struct bt_field_class
*src_fc
,
514 struct bt_field_class
*tgt_fc
,
515 struct bt_resolve_field_xref_context
*ctx
,
516 const char *api_func
,
517 struct bt_field_path
**ret_field_path
)
519 BT_ASSERT_PRE_DEV_FROM_FUNC(api_func
, "valid-field-class",
520 field_path_is_valid(src_fc
, tgt_fc
, ctx
),
521 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
523 return find_field_class_in_ctx(tgt_fc
, ctx
, ret_field_path
);
526 enum bt_resolve_field_xref_status
bt_resolve_field_paths(
527 struct bt_field_class
*fc
,
528 struct bt_resolve_field_xref_context
*ctx
,
529 const char *api_func
)
531 enum bt_resolve_field_xref_status status
;
535 /* Resolving part for dynamic array and variant field classes */
536 if (bt_field_class_type_is(fc
->type
,
537 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
538 struct bt_field_class_option_with_selector_field
*opt_fc
= (void *) fc
;
540 if (opt_fc
->selector_field_xref_kind
== FIELD_XREF_KIND_PATH
) {
541 BT_ASSERT(opt_fc
->selector_field
.path
.class);
542 BT_ASSERT(!opt_fc
->selector_field
.path
.path
);
543 status
= resolve_field_path(
544 fc
, opt_fc
->selector_field
.path
.class, ctx
, __func__
,
545 &opt_fc
->selector_field
.path
.path
);
546 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
550 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
551 struct bt_field_class_array_dynamic
*dyn_array_fc
= (void *) fc
;
553 if (dyn_array_fc
->length_field
.xref_kind
== FIELD_XREF_KIND_PATH
) {
554 BT_ASSERT(dyn_array_fc
->length_field
.path
.class);
555 BT_ASSERT(!dyn_array_fc
->length_field
.path
.path
);
556 status
= resolve_field_path(
557 fc
, dyn_array_fc
->length_field
.path
.class, ctx
, __func__
,
558 &dyn_array_fc
->length_field
.path
.path
);
559 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
563 } else if (bt_field_class_type_is(fc
->type
,
564 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
565 struct bt_field_class_variant_with_selector_field
*var_fc
=
568 if (var_fc
->selector_field_xref_kind
== FIELD_XREF_KIND_PATH
) {
569 BT_ASSERT(var_fc
->selector_field
.path
.class);
570 BT_ASSERT(!var_fc
->selector_field
.path
.path
);
571 status
= resolve_field_path(fc
,
572 (void *) var_fc
->selector_field
.path
.class, ctx
,
573 __func__
, &var_fc
->selector_field
.path
.path
);
574 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
581 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
582 struct bt_field_class_option
*opt_fc
= (void *) fc
;
584 status
= bt_resolve_field_paths(opt_fc
->content_fc
, ctx
, api_func
);
585 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
588 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
589 bt_field_class_type_is(fc
->type
,
590 BT_FIELD_CLASS_TYPE_VARIANT
)) {
591 struct bt_field_class_named_field_class_container
*container_fc
=
595 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
596 struct bt_named_field_class
*named_fc
=
597 container_fc
->named_fcs
->pdata
[i
];
599 status
= bt_resolve_field_paths(named_fc
->fc
, ctx
,
601 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
605 } else if (bt_field_class_type_is(fc
->type
,
606 BT_FIELD_CLASS_TYPE_ARRAY
)) {
607 struct bt_field_class_array
*array_fc
= (void *) fc
;
609 status
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
,
611 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
616 status
= BT_RESOLVE_FIELD_XREF_STATUS_OK
;