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"
22 bool find_field_class_recursive(struct bt_field_class
*fc
,
23 struct bt_field_class
*tgt_fc
, struct bt_field_path
*field_path
)
32 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
33 struct bt_field_class_option
*opt_fc
= (void *) fc
;
34 struct bt_field_path_item item
= {
35 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
,
36 .index
= UINT64_C(-1),
39 bt_field_path_append_item(field_path
, &item
);
40 found
= find_field_class_recursive(opt_fc
->content_fc
,
46 bt_field_path_remove_last_item(field_path
);
47 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
48 bt_field_class_type_is(fc
->type
,
49 BT_FIELD_CLASS_TYPE_VARIANT
)) {
50 struct bt_field_class_named_field_class_container
*container_fc
=
54 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
55 struct bt_named_field_class
*named_fc
=
56 container_fc
->named_fcs
->pdata
[i
];
57 struct bt_field_path_item item
= {
58 .type
= BT_FIELD_PATH_ITEM_TYPE_INDEX
,
62 bt_field_path_append_item(field_path
, &item
);
63 found
= find_field_class_recursive(named_fc
->fc
,
69 bt_field_path_remove_last_item(field_path
);
71 } else if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
72 struct bt_field_class_array
*array_fc
= (void *) fc
;
73 struct bt_field_path_item item
= {
74 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
,
75 .index
= UINT64_C(-1),
78 bt_field_path_append_item(field_path
, &item
);
79 found
= find_field_class_recursive(array_fc
->element_fc
,
85 bt_field_path_remove_last_item(field_path
);
93 int find_field_class(struct bt_field_class
*root_fc
,
94 enum bt_field_path_scope root_scope
, struct bt_field_class
*tgt_fc
,
95 struct bt_field_path
**ret_field_path
)
98 struct bt_field_path
*field_path
= NULL
;
104 field_path
= bt_field_path_create();
110 field_path
->root
= root_scope
;
111 if (!find_field_class_recursive(root_fc
, tgt_fc
, field_path
)) {
113 BT_OBJECT_PUT_REF_AND_RESET(field_path
);
117 *ret_field_path
= field_path
;
122 struct bt_field_path
*find_field_class_in_ctx(struct bt_field_class
*fc
,
123 struct bt_resolve_field_path_context
*ctx
)
125 struct bt_field_path
*field_path
= NULL
;
128 ret
= find_field_class(ctx
->packet_context
, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
,
130 if (ret
|| field_path
) {
134 ret
= find_field_class(ctx
->event_common_context
,
135 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, fc
, &field_path
);
136 if (ret
|| field_path
) {
140 ret
= find_field_class(ctx
->event_specific_context
,
141 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, &field_path
);
142 if (ret
|| field_path
) {
146 ret
= find_field_class(ctx
->event_payload
, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
,
148 if (ret
|| field_path
) {
156 BT_ASSERT_COND_DEV_FUNC
158 bool target_is_before_source(struct bt_field_path
*src_field_path
,
159 struct bt_field_path
*tgt_field_path
)
161 bool is_valid
= true;
162 uint64_t src_i
= 0, tgt_i
= 0;
164 if (tgt_field_path
->root
< src_field_path
->root
) {
168 if (tgt_field_path
->root
> src_field_path
->root
) {
173 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
175 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
176 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
177 struct bt_field_path_item
*src_fp_item
=
178 bt_field_path_borrow_item_by_index_inline(
179 src_field_path
, src_i
);
180 struct bt_field_path_item
*tgt_fp_item
=
181 bt_field_path_borrow_item_by_index_inline(
182 tgt_field_path
, tgt_i
);
184 if (src_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
&&
185 tgt_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
186 if (tgt_fp_item
->index
> src_fp_item
->index
) {
200 BT_ASSERT_COND_DEV_FUNC
202 struct bt_field_class
*borrow_root_field_class(
203 struct bt_resolve_field_path_context
*ctx
, enum bt_field_path_scope scope
)
206 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
207 return ctx
->packet_context
;
208 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
209 return ctx
->event_common_context
;
210 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
211 return ctx
->event_specific_context
;
212 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
213 return ctx
->event_payload
;
221 BT_ASSERT_COND_DEV_FUNC
223 struct bt_field_class
*borrow_child_field_class(
224 struct bt_field_class
*parent_fc
,
225 struct bt_field_path_item
*fp_item
)
227 struct bt_field_class
*child_fc
= NULL
;
229 if (bt_field_class_type_is(parent_fc
->type
,
230 BT_FIELD_CLASS_TYPE_OPTION
)) {
231 struct bt_field_class_option
*opt_fc
= (void *) parent_fc
;
233 BT_ASSERT(fp_item
->type
==
234 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
);
235 child_fc
= opt_fc
->content_fc
;
236 } else if (parent_fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
237 bt_field_class_type_is(parent_fc
->type
,
238 BT_FIELD_CLASS_TYPE_VARIANT
)) {
239 struct bt_field_class_named_field_class_container
*container_fc
=
241 struct bt_named_field_class
*named_fc
;
243 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
244 named_fc
= container_fc
->named_fcs
->pdata
[fp_item
->index
];
245 child_fc
= named_fc
->fc
;
246 } else if (bt_field_class_type_is(parent_fc
->type
,
247 BT_FIELD_CLASS_TYPE_ARRAY
)) {
248 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
250 BT_ASSERT(fp_item
->type
==
251 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
252 child_fc
= array_fc
->element_fc
;
258 BT_ASSERT_COND_DEV_FUNC
260 bool target_field_path_in_different_scope_has_struct_fc_only(
261 struct bt_field_path
*src_field_path
,
262 struct bt_field_path
*tgt_field_path
,
263 struct bt_resolve_field_path_context
*ctx
)
265 bool is_valid
= true;
267 struct bt_field_class
*fc
;
269 if (src_field_path
->root
== tgt_field_path
->root
) {
273 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
275 for (i
= 0; i
< tgt_field_path
->items
->len
; i
++) {
276 struct bt_field_path_item
*fp_item
=
277 bt_field_path_borrow_item_by_index_inline(
280 if (bt_field_class_type_is(fc
->type
,
281 BT_FIELD_CLASS_TYPE_ARRAY
) ||
282 bt_field_class_type_is(fc
->type
,
283 BT_FIELD_CLASS_TYPE_OPTION
) ||
284 bt_field_class_type_is(fc
->type
,
285 BT_FIELD_CLASS_TYPE_VARIANT
)) {
290 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
291 fc
= borrow_child_field_class(fc
, fp_item
);
298 BT_ASSERT_COND_DEV_FUNC
300 bool lca_is_structure_field_class(struct bt_field_path
*src_field_path
,
301 struct bt_field_path
*tgt_field_path
,
302 struct bt_resolve_field_path_context
*ctx
)
304 bool is_valid
= true;
305 struct bt_field_class
*src_fc
;
306 struct bt_field_class
*tgt_fc
;
307 struct bt_field_class
*prev_fc
= NULL
;
308 uint64_t src_i
= 0, tgt_i
= 0;
310 if (src_field_path
->root
!= tgt_field_path
->root
) {
314 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
315 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
319 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
320 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
321 struct bt_field_path_item
*src_fp_item
=
322 bt_field_path_borrow_item_by_index_inline(
323 src_field_path
, src_i
);
324 struct bt_field_path_item
*tgt_fp_item
=
325 bt_field_path_borrow_item_by_index_inline(
326 tgt_field_path
, tgt_i
);
328 if (src_fc
!= tgt_fc
) {
331 * This is correct: the LCA is the root
332 * scope field class, which must be a
333 * structure field class.
338 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
346 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
347 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
354 BT_ASSERT_COND_DEV_FUNC
356 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
357 struct bt_field_path
*tgt_field_path
,
358 struct bt_resolve_field_path_context
*ctx
)
360 bool is_valid
= true;
361 struct bt_field_class
*src_fc
;
362 struct bt_field_class
*tgt_fc
;
363 uint64_t src_i
= 0, tgt_i
= 0;
365 if (src_field_path
->root
!= tgt_field_path
->root
) {
369 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
370 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
373 BT_ASSERT(src_fc
== tgt_fc
);
376 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
377 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
378 struct bt_field_path_item
*src_fp_item
=
379 bt_field_path_borrow_item_by_index_inline(
380 src_field_path
, src_i
);
381 struct bt_field_path_item
*tgt_fp_item
=
382 bt_field_path_borrow_item_by_index_inline(
383 tgt_field_path
, tgt_i
);
385 if (src_i
!= tgt_i
) {
386 /* Next field class is different: LCA is `tgt_fc` */
390 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
391 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
394 /* Only structure field classes to the target */
395 for (; tgt_i
< tgt_field_path
->items
->len
; tgt_i
++) {
396 struct bt_field_path_item
*tgt_fp_item
=
397 bt_field_path_borrow_item_by_index_inline(
398 tgt_field_path
, tgt_i
);
400 if (bt_field_class_type_is(tgt_fc
->type
,
401 BT_FIELD_CLASS_TYPE_ARRAY
) ||
402 bt_field_class_type_is(tgt_fc
->type
,
403 BT_FIELD_CLASS_TYPE_OPTION
) ||
404 bt_field_class_type_is(tgt_fc
->type
,
405 BT_FIELD_CLASS_TYPE_VARIANT
)) {
410 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
417 BT_ASSERT_COND_DEV_FUNC
419 bool field_path_is_valid(struct bt_field_class
*src_fc
,
420 struct bt_field_class
*tgt_fc
,
421 struct bt_resolve_field_path_context
*ctx
)
423 bool is_valid
= true;
424 struct bt_field_path
*src_field_path
= find_field_class_in_ctx(
426 struct bt_field_path
*tgt_field_path
= find_field_class_in_ctx(
429 if (!src_field_path
) {
430 BT_ASSERT_COND_DEV_MSG("Cannot find requesting field class in "
431 "resolving context: %!+F", src_fc
);
436 if (!tgt_field_path
) {
437 BT_ASSERT_COND_DEV_MSG("Cannot find target field class in "
438 "resolving context: %!+F", tgt_fc
);
443 /* Target must be before source */
444 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
445 BT_ASSERT_COND_DEV_MSG("Target field class is located after "
446 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
453 * If target is in a different scope than source, there are no
454 * array or variant field classes on the way to the target.
456 if (!target_field_path_in_different_scope_has_struct_fc_only(
457 src_field_path
, tgt_field_path
, ctx
)) {
458 BT_ASSERT_COND_DEV_MSG("Target field class is located in a "
459 "different scope than requesting field class, "
460 "but within an array or a variant field class: "
461 "%![req-fc-]+F, %![tgt-fc-]+F",
467 /* Same scope: LCA must be a structure field class */
468 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
469 BT_ASSERT_COND_DEV_MSG("Lowest common ancestor of target and "
470 "requesting field classes is not a structure field class: "
471 "%![req-fc-]+F, %![tgt-fc-]+F",
477 /* Same scope: path from LCA to target has no array/variant FTs */
478 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
480 BT_ASSERT_COND_DEV_MSG("Path from lowest common ancestor of target "
481 "and requesting field classes to target field class "
482 "contains an array or a variant field class: "
483 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
489 bt_object_put_ref(src_field_path
);
490 bt_object_put_ref(tgt_field_path
);
495 struct bt_field_path
*resolve_field_path(struct bt_field_class
*src_fc
,
496 struct bt_field_class
*tgt_fc
,
497 struct bt_resolve_field_path_context
*ctx
,
498 const char *api_func
)
500 BT_ASSERT_PRE_DEV_FROM_FUNC(api_func
, "valid-field-class",
501 field_path_is_valid(src_fc
, tgt_fc
, ctx
),
502 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
504 return find_field_class_in_ctx(tgt_fc
, ctx
);
507 int bt_resolve_field_paths(struct bt_field_class
*fc
,
508 struct bt_resolve_field_path_context
*ctx
,
509 const char *api_func
)
515 /* Resolving part for dynamic array and variant field classes */
516 if (bt_field_class_type_is(fc
->type
,
517 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
518 struct bt_field_class_option_with_selector_field
*opt_fc
= (void *) fc
;
520 BT_ASSERT(opt_fc
->selector_fc
);
521 BT_ASSERT(!opt_fc
->selector_field_path
);
522 opt_fc
->selector_field_path
= resolve_field_path(
523 fc
, opt_fc
->selector_fc
, ctx
, __func__
);
524 if (!opt_fc
->selector_field_path
) {
528 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
529 struct bt_field_class_array_dynamic
*dyn_array_fc
= (void *) fc
;
531 BT_ASSERT(dyn_array_fc
->length_fc
);
532 BT_ASSERT(!dyn_array_fc
->length_field_path
);
533 dyn_array_fc
->length_field_path
= resolve_field_path(
534 fc
, dyn_array_fc
->length_fc
, ctx
, __func__
);
535 if (!dyn_array_fc
->length_field_path
) {
539 } else if (bt_field_class_type_is(fc
->type
,
540 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
541 struct bt_field_class_variant_with_selector_field
*var_fc
=
544 if (var_fc
->selector_fc
) {
545 BT_ASSERT(!var_fc
->selector_field_path
);
546 var_fc
->selector_field_path
=
547 resolve_field_path(fc
,
548 (void *) var_fc
->selector_fc
, ctx
,
550 if (!var_fc
->selector_field_path
) {
558 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
559 struct bt_field_class_option
*opt_fc
= (void *) fc
;
561 ret
= bt_resolve_field_paths(opt_fc
->content_fc
, ctx
, api_func
);
562 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
563 bt_field_class_type_is(fc
->type
,
564 BT_FIELD_CLASS_TYPE_VARIANT
)) {
565 struct bt_field_class_named_field_class_container
*container_fc
=
569 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
570 struct bt_named_field_class
*named_fc
=
571 container_fc
->named_fcs
->pdata
[i
];
573 ret
= bt_resolve_field_paths(named_fc
->fc
, ctx
,
579 } else if (bt_field_class_type_is(fc
->type
,
580 BT_FIELD_CLASS_TYPE_ARRAY
)) {
581 struct bt_field_class_array
*array_fc
= (void *) fc
;
583 ret
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
,