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>
19 #include "field-class.h"
20 #include "field-path.h"
21 #include "resolve-field-path.h"
24 bool find_field_class_recursive(struct bt_field_class
*fc
,
25 struct bt_field_class
*tgt_fc
, struct bt_field_path
*field_path
)
34 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
35 struct bt_field_class_option
*opt_fc
= (void *) fc
;
36 struct bt_field_path_item item
= {
37 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
,
38 .index
= UINT64_C(-1),
41 bt_field_path_append_item(field_path
, &item
);
42 found
= find_field_class_recursive(opt_fc
->content_fc
,
48 bt_field_path_remove_last_item(field_path
);
49 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
50 bt_field_class_type_is(fc
->type
,
51 BT_FIELD_CLASS_TYPE_VARIANT
)) {
52 struct bt_field_class_named_field_class_container
*container_fc
=
56 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
57 struct bt_named_field_class
*named_fc
=
58 container_fc
->named_fcs
->pdata
[i
];
59 struct bt_field_path_item item
= {
60 .type
= BT_FIELD_PATH_ITEM_TYPE_INDEX
,
64 bt_field_path_append_item(field_path
, &item
);
65 found
= find_field_class_recursive(named_fc
->fc
,
71 bt_field_path_remove_last_item(field_path
);
73 } else if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
74 struct bt_field_class_array
*array_fc
= (void *) fc
;
75 struct bt_field_path_item item
= {
76 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
,
77 .index
= UINT64_C(-1),
80 bt_field_path_append_item(field_path
, &item
);
81 found
= find_field_class_recursive(array_fc
->element_fc
,
87 bt_field_path_remove_last_item(field_path
);
95 enum bt_resolve_field_xref_status
find_field_class(
96 struct bt_field_class
*root_fc
,
97 enum bt_field_path_scope root_scope
,
98 struct bt_field_class
*tgt_fc
,
99 struct bt_field_path
**ret_field_path
)
101 enum bt_resolve_field_xref_status ret
;
102 struct bt_field_path
*field_path
= NULL
;
105 ret
= BT_RESOLVE_FIELD_XREF_STATUS_OK
;
109 field_path
= bt_field_path_create();
111 ret
= BT_RESOLVE_FIELD_XREF_STATUS_MEMORY_ERROR
;
115 field_path
->root
= root_scope
;
116 if (!find_field_class_recursive(root_fc
, tgt_fc
, field_path
)) {
118 BT_OBJECT_PUT_REF_AND_RESET(field_path
);
121 ret
= BT_RESOLVE_FIELD_XREF_STATUS_OK
;
124 *ret_field_path
= field_path
;
129 enum bt_resolve_field_xref_status
find_field_class_in_ctx(
130 struct bt_field_class
*fc
,
131 struct bt_resolve_field_xref_context
*ctx
,
132 struct bt_field_path
**ret_field_path
)
134 enum bt_resolve_field_xref_status ret
;
136 *ret_field_path
= NULL
;
138 ret
= find_field_class(ctx
->packet_context
,
139 BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
, fc
, ret_field_path
);
140 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
144 ret
= find_field_class(ctx
->event_common_context
,
145 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, fc
, ret_field_path
);
146 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
150 ret
= find_field_class(ctx
->event_specific_context
,
151 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, ret_field_path
);
152 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
156 ret
= find_field_class(ctx
->event_payload
,
157 BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
, fc
, ret_field_path
);
158 if (ret
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
|| *ret_field_path
) {
166 BT_ASSERT_COND_DEV_FUNC
168 bool target_is_before_source(struct bt_field_path
*src_field_path
,
169 struct bt_field_path
*tgt_field_path
)
171 bool is_valid
= true;
172 uint64_t src_i
= 0, tgt_i
= 0;
174 if (tgt_field_path
->root
< src_field_path
->root
) {
178 if (tgt_field_path
->root
> src_field_path
->root
) {
183 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
185 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
186 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
187 struct bt_field_path_item
*src_fp_item
=
188 bt_field_path_borrow_item_by_index_inline(
189 src_field_path
, src_i
);
190 struct bt_field_path_item
*tgt_fp_item
=
191 bt_field_path_borrow_item_by_index_inline(
192 tgt_field_path
, tgt_i
);
194 if (src_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
&&
195 tgt_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
196 if (tgt_fp_item
->index
> src_fp_item
->index
) {
210 BT_ASSERT_COND_DEV_FUNC
212 struct bt_field_class
*borrow_root_field_class(
213 struct bt_resolve_field_xref_context
*ctx
,
214 enum bt_field_path_scope scope
)
217 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
218 return ctx
->packet_context
;
219 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
220 return ctx
->event_common_context
;
221 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
222 return ctx
->event_specific_context
;
223 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
224 return ctx
->event_payload
;
232 BT_ASSERT_COND_DEV_FUNC
234 struct bt_field_class
*borrow_child_field_class(
235 struct bt_field_class
*parent_fc
,
236 struct bt_field_path_item
*fp_item
)
238 struct bt_field_class
*child_fc
= NULL
;
240 if (bt_field_class_type_is(parent_fc
->type
,
241 BT_FIELD_CLASS_TYPE_OPTION
)) {
242 struct bt_field_class_option
*opt_fc
= (void *) parent_fc
;
244 BT_ASSERT(fp_item
->type
==
245 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
);
246 child_fc
= opt_fc
->content_fc
;
247 } else if (parent_fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
248 bt_field_class_type_is(parent_fc
->type
,
249 BT_FIELD_CLASS_TYPE_VARIANT
)) {
250 struct bt_field_class_named_field_class_container
*container_fc
=
252 struct bt_named_field_class
*named_fc
;
254 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
255 named_fc
= container_fc
->named_fcs
->pdata
[fp_item
->index
];
256 child_fc
= named_fc
->fc
;
257 } else if (bt_field_class_type_is(parent_fc
->type
,
258 BT_FIELD_CLASS_TYPE_ARRAY
)) {
259 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
261 BT_ASSERT(fp_item
->type
==
262 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
263 child_fc
= array_fc
->element_fc
;
269 BT_ASSERT_COND_DEV_FUNC
271 bool target_field_path_in_different_scope_has_struct_fc_only(
272 struct bt_field_path
*src_field_path
,
273 struct bt_field_path
*tgt_field_path
,
274 struct bt_resolve_field_xref_context
*ctx
)
276 bool is_valid
= true;
278 struct bt_field_class
*fc
;
280 if (src_field_path
->root
== tgt_field_path
->root
) {
284 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
286 for (i
= 0; i
< tgt_field_path
->items
->len
; i
++) {
287 struct bt_field_path_item
*fp_item
=
288 bt_field_path_borrow_item_by_index_inline(
291 if (bt_field_class_type_is(fc
->type
,
292 BT_FIELD_CLASS_TYPE_ARRAY
) ||
293 bt_field_class_type_is(fc
->type
,
294 BT_FIELD_CLASS_TYPE_OPTION
) ||
295 bt_field_class_type_is(fc
->type
,
296 BT_FIELD_CLASS_TYPE_VARIANT
)) {
301 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
302 fc
= borrow_child_field_class(fc
, fp_item
);
309 BT_ASSERT_COND_DEV_FUNC
311 bool lca_is_structure_field_class(struct bt_field_path
*src_field_path
,
312 struct bt_field_path
*tgt_field_path
,
313 struct bt_resolve_field_xref_context
*ctx
)
315 bool is_valid
= true;
316 struct bt_field_class
*src_fc
;
317 struct bt_field_class
*tgt_fc
;
318 struct bt_field_class
*prev_fc
= NULL
;
319 uint64_t src_i
= 0, tgt_i
= 0;
321 if (src_field_path
->root
!= tgt_field_path
->root
) {
325 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
326 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
330 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
331 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
332 struct bt_field_path_item
*src_fp_item
=
333 bt_field_path_borrow_item_by_index_inline(
334 src_field_path
, src_i
);
335 struct bt_field_path_item
*tgt_fp_item
=
336 bt_field_path_borrow_item_by_index_inline(
337 tgt_field_path
, tgt_i
);
339 if (src_fc
!= tgt_fc
) {
342 * This is correct: the LCA is the root
343 * scope field class, which must be a
344 * structure field class.
349 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
357 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
358 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
365 BT_ASSERT_COND_DEV_FUNC
367 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
368 struct bt_field_path
*tgt_field_path
,
369 struct bt_resolve_field_xref_context
*ctx
)
371 bool is_valid
= true;
372 struct bt_field_class
*src_fc
;
373 struct bt_field_class
*tgt_fc
;
374 uint64_t src_i
= 0, tgt_i
= 0;
376 if (src_field_path
->root
!= tgt_field_path
->root
) {
380 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
381 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
384 BT_ASSERT(src_fc
== tgt_fc
);
387 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
388 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
389 struct bt_field_path_item
*src_fp_item
=
390 bt_field_path_borrow_item_by_index_inline(
391 src_field_path
, src_i
);
392 struct bt_field_path_item
*tgt_fp_item
=
393 bt_field_path_borrow_item_by_index_inline(
394 tgt_field_path
, tgt_i
);
396 if (src_i
!= tgt_i
) {
397 /* Next field class is different: LCA is `tgt_fc` */
401 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
402 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
405 /* Only structure field classes to the target */
406 for (; tgt_i
< tgt_field_path
->items
->len
; tgt_i
++) {
407 struct bt_field_path_item
*tgt_fp_item
=
408 bt_field_path_borrow_item_by_index_inline(
409 tgt_field_path
, tgt_i
);
411 if (bt_field_class_type_is(tgt_fc
->type
,
412 BT_FIELD_CLASS_TYPE_ARRAY
) ||
413 bt_field_class_type_is(tgt_fc
->type
,
414 BT_FIELD_CLASS_TYPE_OPTION
) ||
415 bt_field_class_type_is(tgt_fc
->type
,
416 BT_FIELD_CLASS_TYPE_VARIANT
)) {
421 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
428 BT_ASSERT_COND_DEV_FUNC
430 bool field_path_is_valid(struct bt_field_class
*src_fc
,
431 struct bt_field_class
*tgt_fc
,
432 struct bt_resolve_field_xref_context
*ctx
)
434 struct bt_field_path
*src_field_path
;
435 struct bt_field_path
*tgt_field_path
= NULL
;
436 enum bt_resolve_field_xref_status status
;
439 status
= find_field_class_in_ctx(src_fc
, ctx
, &src_field_path
);
440 BT_ASSERT(status
== BT_RESOLVE_FIELD_XREF_STATUS_OK
);
442 if (!src_field_path
) {
443 BT_ASSERT_COND_DEV_MSG("Cannot find requesting field class in "
444 "resolving context: %!+F", src_fc
);
449 status
= find_field_class_in_ctx(tgt_fc
, ctx
, &tgt_field_path
);
450 BT_ASSERT(status
== BT_RESOLVE_FIELD_XREF_STATUS_OK
);
452 if (!tgt_field_path
) {
453 BT_ASSERT_COND_DEV_MSG("Cannot find target field class in "
454 "resolving context: %!+F", tgt_fc
);
459 /* Target must be before source */
460 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
461 BT_ASSERT_COND_DEV_MSG("Target field class is located after "
462 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
469 * If target is in a different scope than source, there are no
470 * array or variant field classes on the way to the target.
472 if (!target_field_path_in_different_scope_has_struct_fc_only(
473 src_field_path
, tgt_field_path
, ctx
)) {
474 BT_ASSERT_COND_DEV_MSG("Target field class is located in a "
475 "different scope than requesting field class, "
476 "but within an array or a variant field class: "
477 "%![req-fc-]+F, %![tgt-fc-]+F",
483 /* Same scope: LCA must be a structure field class */
484 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
485 BT_ASSERT_COND_DEV_MSG("Lowest common ancestor of target and "
486 "requesting field classes is not a structure field class: "
487 "%![req-fc-]+F, %![tgt-fc-]+F",
493 /* Same scope: path from LCA to target has no array/variant FTs */
494 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
496 BT_ASSERT_COND_DEV_MSG("Path from lowest common ancestor of target "
497 "and requesting field classes to target field class "
498 "contains an array or a variant field class: "
499 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
507 bt_object_put_ref(src_field_path
);
508 bt_object_put_ref(tgt_field_path
);
513 enum bt_resolve_field_xref_status
resolve_field_path(
514 struct bt_field_class
*src_fc
,
515 struct bt_field_class
*tgt_fc
,
516 struct bt_resolve_field_xref_context
*ctx
,
517 const char *api_func
,
518 struct bt_field_path
**ret_field_path
)
520 BT_ASSERT_PRE_DEV_FROM_FUNC(api_func
, "valid-field-class",
521 field_path_is_valid(src_fc
, tgt_fc
, ctx
),
522 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
524 return find_field_class_in_ctx(tgt_fc
, ctx
, ret_field_path
);
528 enum bt_resolve_field_xref_status
bt_resolve_field_paths(
529 struct bt_field_class
*fc
,
530 struct bt_resolve_field_xref_context
*ctx
,
531 const char *api_func
)
533 enum bt_resolve_field_xref_status status
;
537 /* Resolving part for dynamic array and variant field classes */
538 if (bt_field_class_type_is(fc
->type
,
539 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
540 struct bt_field_class_option_with_selector_field
*opt_fc
= (void *) fc
;
542 if (opt_fc
->selector_field_xref_kind
== FIELD_XREF_KIND_PATH
) {
543 BT_ASSERT(opt_fc
->selector_field
.path
.class);
544 BT_ASSERT(!opt_fc
->selector_field
.path
.path
);
545 status
= resolve_field_path(
546 fc
, opt_fc
->selector_field
.path
.class, ctx
, __func__
,
547 &opt_fc
->selector_field
.path
.path
);
548 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
552 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
553 struct bt_field_class_array_dynamic
*dyn_array_fc
= (void *) fc
;
555 if (dyn_array_fc
->length_field
.xref_kind
== FIELD_XREF_KIND_PATH
) {
556 BT_ASSERT(dyn_array_fc
->length_field
.path
.class);
557 BT_ASSERT(!dyn_array_fc
->length_field
.path
.path
);
558 status
= resolve_field_path(
559 fc
, dyn_array_fc
->length_field
.path
.class, ctx
, __func__
,
560 &dyn_array_fc
->length_field
.path
.path
);
561 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
565 } else if (bt_field_class_type_is(fc
->type
,
566 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
567 struct bt_field_class_variant_with_selector_field
*var_fc
=
570 if (var_fc
->selector_field_xref_kind
== FIELD_XREF_KIND_PATH
) {
571 BT_ASSERT(var_fc
->selector_field
.path
.class);
572 BT_ASSERT(!var_fc
->selector_field
.path
.path
);
573 status
= resolve_field_path(fc
,
574 (void *) var_fc
->selector_field
.path
.class, ctx
,
575 __func__
, &var_fc
->selector_field
.path
.path
);
576 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
583 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
584 struct bt_field_class_option
*opt_fc
= (void *) fc
;
586 status
= bt_resolve_field_paths(opt_fc
->content_fc
, ctx
, api_func
);
587 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
590 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
591 bt_field_class_type_is(fc
->type
,
592 BT_FIELD_CLASS_TYPE_VARIANT
)) {
593 struct bt_field_class_named_field_class_container
*container_fc
=
597 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
598 struct bt_named_field_class
*named_fc
=
599 container_fc
->named_fcs
->pdata
[i
];
601 status
= bt_resolve_field_paths(named_fc
->fc
, ctx
,
603 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
607 } else if (bt_field_class_type_is(fc
->type
,
608 BT_FIELD_CLASS_TYPE_ARRAY
)) {
609 struct bt_field_class_array
*array_fc
= (void *) fc
;
611 status
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
,
613 if (status
!= BT_RESOLVE_FIELD_XREF_STATUS_OK
) {
618 status
= BT_RESOLVE_FIELD_XREF_STATUS_OK
;