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 int find_field_class(struct bt_field_class
*root_fc
,
96 enum bt_field_path_scope root_scope
, struct bt_field_class
*tgt_fc
,
97 struct bt_field_path
**ret_field_path
)
100 struct bt_field_path
*field_path
= NULL
;
106 field_path
= bt_field_path_create();
112 field_path
->root
= root_scope
;
113 if (!find_field_class_recursive(root_fc
, tgt_fc
, field_path
)) {
115 BT_OBJECT_PUT_REF_AND_RESET(field_path
);
119 *ret_field_path
= field_path
;
124 struct bt_field_path
*find_field_class_in_ctx(struct bt_field_class
*fc
,
125 struct bt_resolve_field_path_context
*ctx
)
127 struct bt_field_path
*field_path
= NULL
;
130 ret
= find_field_class(ctx
->packet_context
, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
,
132 if (ret
|| field_path
) {
136 ret
= find_field_class(ctx
->event_common_context
,
137 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, fc
, &field_path
);
138 if (ret
|| field_path
) {
142 ret
= find_field_class(ctx
->event_specific_context
,
143 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, &field_path
);
144 if (ret
|| field_path
) {
148 ret
= find_field_class(ctx
->event_payload
, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
,
150 if (ret
|| field_path
) {
158 BT_ASSERT_COND_DEV_FUNC
160 bool target_is_before_source(struct bt_field_path
*src_field_path
,
161 struct bt_field_path
*tgt_field_path
)
163 bool is_valid
= true;
164 uint64_t src_i
= 0, tgt_i
= 0;
166 if (tgt_field_path
->root
< src_field_path
->root
) {
170 if (tgt_field_path
->root
> src_field_path
->root
) {
175 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
177 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
178 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
179 struct bt_field_path_item
*src_fp_item
=
180 bt_field_path_borrow_item_by_index_inline(
181 src_field_path
, src_i
);
182 struct bt_field_path_item
*tgt_fp_item
=
183 bt_field_path_borrow_item_by_index_inline(
184 tgt_field_path
, tgt_i
);
186 if (src_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
&&
187 tgt_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
188 if (tgt_fp_item
->index
> src_fp_item
->index
) {
202 BT_ASSERT_COND_DEV_FUNC
204 struct bt_field_class
*borrow_root_field_class(
205 struct bt_resolve_field_path_context
*ctx
, enum bt_field_path_scope scope
)
208 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
209 return ctx
->packet_context
;
210 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
211 return ctx
->event_common_context
;
212 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
213 return ctx
->event_specific_context
;
214 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
215 return ctx
->event_payload
;
223 BT_ASSERT_COND_DEV_FUNC
225 struct bt_field_class
*borrow_child_field_class(
226 struct bt_field_class
*parent_fc
,
227 struct bt_field_path_item
*fp_item
)
229 struct bt_field_class
*child_fc
= NULL
;
231 if (bt_field_class_type_is(parent_fc
->type
,
232 BT_FIELD_CLASS_TYPE_OPTION
)) {
233 struct bt_field_class_option
*opt_fc
= (void *) parent_fc
;
235 BT_ASSERT(fp_item
->type
==
236 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
);
237 child_fc
= opt_fc
->content_fc
;
238 } else if (parent_fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
239 bt_field_class_type_is(parent_fc
->type
,
240 BT_FIELD_CLASS_TYPE_VARIANT
)) {
241 struct bt_field_class_named_field_class_container
*container_fc
=
243 struct bt_named_field_class
*named_fc
;
245 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
246 named_fc
= container_fc
->named_fcs
->pdata
[fp_item
->index
];
247 child_fc
= named_fc
->fc
;
248 } else if (bt_field_class_type_is(parent_fc
->type
,
249 BT_FIELD_CLASS_TYPE_ARRAY
)) {
250 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
252 BT_ASSERT(fp_item
->type
==
253 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
254 child_fc
= array_fc
->element_fc
;
260 BT_ASSERT_COND_DEV_FUNC
262 bool target_field_path_in_different_scope_has_struct_fc_only(
263 struct bt_field_path
*src_field_path
,
264 struct bt_field_path
*tgt_field_path
,
265 struct bt_resolve_field_path_context
*ctx
)
267 bool is_valid
= true;
269 struct bt_field_class
*fc
;
271 if (src_field_path
->root
== tgt_field_path
->root
) {
275 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
277 for (i
= 0; i
< tgt_field_path
->items
->len
; i
++) {
278 struct bt_field_path_item
*fp_item
=
279 bt_field_path_borrow_item_by_index_inline(
282 if (bt_field_class_type_is(fc
->type
,
283 BT_FIELD_CLASS_TYPE_ARRAY
) ||
284 bt_field_class_type_is(fc
->type
,
285 BT_FIELD_CLASS_TYPE_OPTION
) ||
286 bt_field_class_type_is(fc
->type
,
287 BT_FIELD_CLASS_TYPE_VARIANT
)) {
292 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
293 fc
= borrow_child_field_class(fc
, fp_item
);
300 BT_ASSERT_COND_DEV_FUNC
302 bool lca_is_structure_field_class(struct bt_field_path
*src_field_path
,
303 struct bt_field_path
*tgt_field_path
,
304 struct bt_resolve_field_path_context
*ctx
)
306 bool is_valid
= true;
307 struct bt_field_class
*src_fc
;
308 struct bt_field_class
*tgt_fc
;
309 struct bt_field_class
*prev_fc
= NULL
;
310 uint64_t src_i
= 0, tgt_i
= 0;
312 if (src_field_path
->root
!= tgt_field_path
->root
) {
316 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
317 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
321 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
322 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
323 struct bt_field_path_item
*src_fp_item
=
324 bt_field_path_borrow_item_by_index_inline(
325 src_field_path
, src_i
);
326 struct bt_field_path_item
*tgt_fp_item
=
327 bt_field_path_borrow_item_by_index_inline(
328 tgt_field_path
, tgt_i
);
330 if (src_fc
!= tgt_fc
) {
333 * This is correct: the LCA is the root
334 * scope field class, which must be a
335 * structure field class.
340 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
348 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
349 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
356 BT_ASSERT_COND_DEV_FUNC
358 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
359 struct bt_field_path
*tgt_field_path
,
360 struct bt_resolve_field_path_context
*ctx
)
362 bool is_valid
= true;
363 struct bt_field_class
*src_fc
;
364 struct bt_field_class
*tgt_fc
;
365 uint64_t src_i
= 0, tgt_i
= 0;
367 if (src_field_path
->root
!= tgt_field_path
->root
) {
371 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
372 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
375 BT_ASSERT(src_fc
== tgt_fc
);
378 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
379 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
380 struct bt_field_path_item
*src_fp_item
=
381 bt_field_path_borrow_item_by_index_inline(
382 src_field_path
, src_i
);
383 struct bt_field_path_item
*tgt_fp_item
=
384 bt_field_path_borrow_item_by_index_inline(
385 tgt_field_path
, tgt_i
);
387 if (src_i
!= tgt_i
) {
388 /* Next field class is different: LCA is `tgt_fc` */
392 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
393 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
396 /* Only structure field classes to the target */
397 for (; tgt_i
< tgt_field_path
->items
->len
; tgt_i
++) {
398 struct bt_field_path_item
*tgt_fp_item
=
399 bt_field_path_borrow_item_by_index_inline(
400 tgt_field_path
, tgt_i
);
402 if (bt_field_class_type_is(tgt_fc
->type
,
403 BT_FIELD_CLASS_TYPE_ARRAY
) ||
404 bt_field_class_type_is(tgt_fc
->type
,
405 BT_FIELD_CLASS_TYPE_OPTION
) ||
406 bt_field_class_type_is(tgt_fc
->type
,
407 BT_FIELD_CLASS_TYPE_VARIANT
)) {
412 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
419 BT_ASSERT_COND_DEV_FUNC
421 bool field_path_is_valid(struct bt_field_class
*src_fc
,
422 struct bt_field_class
*tgt_fc
,
423 struct bt_resolve_field_path_context
*ctx
)
425 bool is_valid
= true;
426 struct bt_field_path
*src_field_path
= find_field_class_in_ctx(
428 struct bt_field_path
*tgt_field_path
= find_field_class_in_ctx(
431 if (!src_field_path
) {
432 BT_ASSERT_COND_DEV_MSG("Cannot find requesting field class in "
433 "resolving context: %!+F", src_fc
);
438 if (!tgt_field_path
) {
439 BT_ASSERT_COND_DEV_MSG("Cannot find target field class in "
440 "resolving context: %!+F", tgt_fc
);
445 /* Target must be before source */
446 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
447 BT_ASSERT_COND_DEV_MSG("Target field class is located after "
448 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
455 * If target is in a different scope than source, there are no
456 * array or variant field classes on the way to the target.
458 if (!target_field_path_in_different_scope_has_struct_fc_only(
459 src_field_path
, tgt_field_path
, ctx
)) {
460 BT_ASSERT_COND_DEV_MSG("Target field class is located in a "
461 "different scope than requesting field class, "
462 "but within an array or a variant field class: "
463 "%![req-fc-]+F, %![tgt-fc-]+F",
469 /* Same scope: LCA must be a structure field class */
470 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
471 BT_ASSERT_COND_DEV_MSG("Lowest common ancestor of target and "
472 "requesting field classes is not a structure field class: "
473 "%![req-fc-]+F, %![tgt-fc-]+F",
479 /* Same scope: path from LCA to target has no array/variant FTs */
480 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
482 BT_ASSERT_COND_DEV_MSG("Path from lowest common ancestor of target "
483 "and requesting field classes to target field class "
484 "contains an array or a variant field class: "
485 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
491 bt_object_put_ref(src_field_path
);
492 bt_object_put_ref(tgt_field_path
);
497 struct bt_field_path
*resolve_field_path(struct bt_field_class
*src_fc
,
498 struct bt_field_class
*tgt_fc
,
499 struct bt_resolve_field_path_context
*ctx
,
500 const char *api_func
)
502 BT_ASSERT_PRE_DEV_FROM_FUNC(api_func
, "valid-field-class",
503 field_path_is_valid(src_fc
, tgt_fc
, ctx
),
504 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
506 return find_field_class_in_ctx(tgt_fc
, ctx
);
510 int bt_resolve_field_paths(struct bt_field_class
*fc
,
511 struct bt_resolve_field_path_context
*ctx
,
512 const char *api_func
)
518 /* Resolving part for dynamic array and variant field classes */
519 if (bt_field_class_type_is(fc
->type
,
520 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
521 struct bt_field_class_option_with_selector_field
*opt_fc
= (void *) fc
;
523 BT_ASSERT(opt_fc
->selector_fc
);
524 BT_ASSERT(!opt_fc
->selector_field_path
);
525 opt_fc
->selector_field_path
= resolve_field_path(
526 fc
, opt_fc
->selector_fc
, ctx
, __func__
);
527 if (!opt_fc
->selector_field_path
) {
531 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
532 struct bt_field_class_array_dynamic
*dyn_array_fc
= (void *) fc
;
534 BT_ASSERT(dyn_array_fc
->length_fc
);
535 BT_ASSERT(!dyn_array_fc
->length_field_path
);
536 dyn_array_fc
->length_field_path
= resolve_field_path(
537 fc
, dyn_array_fc
->length_fc
, ctx
, __func__
);
538 if (!dyn_array_fc
->length_field_path
) {
542 } else if (bt_field_class_type_is(fc
->type
,
543 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
544 struct bt_field_class_variant_with_selector_field
*var_fc
=
547 if (var_fc
->selector_fc
) {
548 BT_ASSERT(!var_fc
->selector_field_path
);
549 var_fc
->selector_field_path
=
550 resolve_field_path(fc
,
551 (void *) var_fc
->selector_fc
, ctx
,
553 if (!var_fc
->selector_field_path
) {
561 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
562 struct bt_field_class_option
*opt_fc
= (void *) fc
;
564 ret
= bt_resolve_field_paths(opt_fc
->content_fc
, ctx
, api_func
);
565 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
566 bt_field_class_type_is(fc
->type
,
567 BT_FIELD_CLASS_TYPE_VARIANT
)) {
568 struct bt_field_class_named_field_class_container
*container_fc
=
572 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
573 struct bt_named_field_class
*named_fc
=
574 container_fc
->named_fcs
->pdata
[i
];
576 ret
= bt_resolve_field_paths(named_fc
->fc
, ctx
,
582 } else if (bt_field_class_type_is(fc
->type
,
583 BT_FIELD_CLASS_TYPE_ARRAY
)) {
584 struct bt_field_class_array
*array_fc
= (void *) fc
;
586 ret
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
,