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 int find_field_class(struct bt_field_class
*root_fc
,
95 enum bt_field_path_scope root_scope
, struct bt_field_class
*tgt_fc
,
96 struct bt_field_path
**ret_field_path
)
99 struct bt_field_path
*field_path
= NULL
;
105 field_path
= bt_field_path_create();
111 field_path
->root
= root_scope
;
112 if (!find_field_class_recursive(root_fc
, tgt_fc
, field_path
)) {
114 BT_OBJECT_PUT_REF_AND_RESET(field_path
);
118 *ret_field_path
= field_path
;
123 struct bt_field_path
*find_field_class_in_ctx(struct bt_field_class
*fc
,
124 struct bt_resolve_field_path_context
*ctx
)
126 struct bt_field_path
*field_path
= NULL
;
129 ret
= find_field_class(ctx
->packet_context
, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
,
131 if (ret
|| field_path
) {
135 ret
= find_field_class(ctx
->event_common_context
,
136 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, fc
, &field_path
);
137 if (ret
|| field_path
) {
141 ret
= find_field_class(ctx
->event_specific_context
,
142 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, &field_path
);
143 if (ret
|| field_path
) {
147 ret
= find_field_class(ctx
->event_payload
, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
,
149 if (ret
|| field_path
) {
157 BT_ASSERT_COND_DEV_FUNC
159 bool target_is_before_source(struct bt_field_path
*src_field_path
,
160 struct bt_field_path
*tgt_field_path
)
162 bool is_valid
= true;
163 uint64_t src_i
= 0, tgt_i
= 0;
165 if (tgt_field_path
->root
< src_field_path
->root
) {
169 if (tgt_field_path
->root
> src_field_path
->root
) {
174 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
176 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
177 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
178 struct bt_field_path_item
*src_fp_item
=
179 bt_field_path_borrow_item_by_index_inline(
180 src_field_path
, src_i
);
181 struct bt_field_path_item
*tgt_fp_item
=
182 bt_field_path_borrow_item_by_index_inline(
183 tgt_field_path
, tgt_i
);
185 if (src_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
&&
186 tgt_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
187 if (tgt_fp_item
->index
> src_fp_item
->index
) {
201 BT_ASSERT_COND_DEV_FUNC
203 struct bt_field_class
*borrow_root_field_class(
204 struct bt_resolve_field_path_context
*ctx
, enum bt_field_path_scope scope
)
207 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
208 return ctx
->packet_context
;
209 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
210 return ctx
->event_common_context
;
211 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
212 return ctx
->event_specific_context
;
213 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
214 return ctx
->event_payload
;
222 BT_ASSERT_COND_DEV_FUNC
224 struct bt_field_class
*borrow_child_field_class(
225 struct bt_field_class
*parent_fc
,
226 struct bt_field_path_item
*fp_item
)
228 struct bt_field_class
*child_fc
= NULL
;
230 if (bt_field_class_type_is(parent_fc
->type
,
231 BT_FIELD_CLASS_TYPE_OPTION
)) {
232 struct bt_field_class_option
*opt_fc
= (void *) parent_fc
;
234 BT_ASSERT(fp_item
->type
==
235 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
);
236 child_fc
= opt_fc
->content_fc
;
237 } else if (parent_fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
238 bt_field_class_type_is(parent_fc
->type
,
239 BT_FIELD_CLASS_TYPE_VARIANT
)) {
240 struct bt_field_class_named_field_class_container
*container_fc
=
242 struct bt_named_field_class
*named_fc
;
244 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
245 named_fc
= container_fc
->named_fcs
->pdata
[fp_item
->index
];
246 child_fc
= named_fc
->fc
;
247 } else if (bt_field_class_type_is(parent_fc
->type
,
248 BT_FIELD_CLASS_TYPE_ARRAY
)) {
249 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
251 BT_ASSERT(fp_item
->type
==
252 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
253 child_fc
= array_fc
->element_fc
;
259 BT_ASSERT_COND_DEV_FUNC
261 bool target_field_path_in_different_scope_has_struct_fc_only(
262 struct bt_field_path
*src_field_path
,
263 struct bt_field_path
*tgt_field_path
,
264 struct bt_resolve_field_path_context
*ctx
)
266 bool is_valid
= true;
268 struct bt_field_class
*fc
;
270 if (src_field_path
->root
== tgt_field_path
->root
) {
274 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
276 for (i
= 0; i
< tgt_field_path
->items
->len
; i
++) {
277 struct bt_field_path_item
*fp_item
=
278 bt_field_path_borrow_item_by_index_inline(
281 if (bt_field_class_type_is(fc
->type
,
282 BT_FIELD_CLASS_TYPE_ARRAY
) ||
283 bt_field_class_type_is(fc
->type
,
284 BT_FIELD_CLASS_TYPE_OPTION
) ||
285 bt_field_class_type_is(fc
->type
,
286 BT_FIELD_CLASS_TYPE_VARIANT
)) {
291 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
292 fc
= borrow_child_field_class(fc
, fp_item
);
299 BT_ASSERT_COND_DEV_FUNC
301 bool lca_is_structure_field_class(struct bt_field_path
*src_field_path
,
302 struct bt_field_path
*tgt_field_path
,
303 struct bt_resolve_field_path_context
*ctx
)
305 bool is_valid
= true;
306 struct bt_field_class
*src_fc
;
307 struct bt_field_class
*tgt_fc
;
308 struct bt_field_class
*prev_fc
= NULL
;
309 uint64_t src_i
= 0, tgt_i
= 0;
311 if (src_field_path
->root
!= tgt_field_path
->root
) {
315 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
316 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
320 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
321 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
322 struct bt_field_path_item
*src_fp_item
=
323 bt_field_path_borrow_item_by_index_inline(
324 src_field_path
, src_i
);
325 struct bt_field_path_item
*tgt_fp_item
=
326 bt_field_path_borrow_item_by_index_inline(
327 tgt_field_path
, tgt_i
);
329 if (src_fc
!= tgt_fc
) {
332 * This is correct: the LCA is the root
333 * scope field class, which must be a
334 * structure field class.
339 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
347 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
348 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
355 BT_ASSERT_COND_DEV_FUNC
357 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
358 struct bt_field_path
*tgt_field_path
,
359 struct bt_resolve_field_path_context
*ctx
)
361 bool is_valid
= true;
362 struct bt_field_class
*src_fc
;
363 struct bt_field_class
*tgt_fc
;
364 uint64_t src_i
= 0, tgt_i
= 0;
366 if (src_field_path
->root
!= tgt_field_path
->root
) {
370 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
371 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
374 BT_ASSERT(src_fc
== tgt_fc
);
377 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
378 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
379 struct bt_field_path_item
*src_fp_item
=
380 bt_field_path_borrow_item_by_index_inline(
381 src_field_path
, src_i
);
382 struct bt_field_path_item
*tgt_fp_item
=
383 bt_field_path_borrow_item_by_index_inline(
384 tgt_field_path
, tgt_i
);
386 if (src_i
!= tgt_i
) {
387 /* Next field class is different: LCA is `tgt_fc` */
391 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
392 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
395 /* Only structure field classes to the target */
396 for (; tgt_i
< tgt_field_path
->items
->len
; tgt_i
++) {
397 struct bt_field_path_item
*tgt_fp_item
=
398 bt_field_path_borrow_item_by_index_inline(
399 tgt_field_path
, tgt_i
);
401 if (bt_field_class_type_is(tgt_fc
->type
,
402 BT_FIELD_CLASS_TYPE_ARRAY
) ||
403 bt_field_class_type_is(tgt_fc
->type
,
404 BT_FIELD_CLASS_TYPE_OPTION
) ||
405 bt_field_class_type_is(tgt_fc
->type
,
406 BT_FIELD_CLASS_TYPE_VARIANT
)) {
411 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
418 BT_ASSERT_COND_DEV_FUNC
420 bool field_path_is_valid(struct bt_field_class
*src_fc
,
421 struct bt_field_class
*tgt_fc
,
422 struct bt_resolve_field_path_context
*ctx
)
424 bool is_valid
= true;
425 struct bt_field_path
*src_field_path
= find_field_class_in_ctx(
427 struct bt_field_path
*tgt_field_path
= find_field_class_in_ctx(
430 if (!src_field_path
) {
431 BT_ASSERT_COND_DEV_MSG("Cannot find requesting field class in "
432 "resolving context: %!+F", src_fc
);
437 if (!tgt_field_path
) {
438 BT_ASSERT_COND_DEV_MSG("Cannot find target field class in "
439 "resolving context: %!+F", tgt_fc
);
444 /* Target must be before source */
445 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
446 BT_ASSERT_COND_DEV_MSG("Target field class is located after "
447 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
454 * If target is in a different scope than source, there are no
455 * array or variant field classes on the way to the target.
457 if (!target_field_path_in_different_scope_has_struct_fc_only(
458 src_field_path
, tgt_field_path
, ctx
)) {
459 BT_ASSERT_COND_DEV_MSG("Target field class is located in a "
460 "different scope than requesting field class, "
461 "but within an array or a variant field class: "
462 "%![req-fc-]+F, %![tgt-fc-]+F",
468 /* Same scope: LCA must be a structure field class */
469 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
470 BT_ASSERT_COND_DEV_MSG("Lowest common ancestor of target and "
471 "requesting field classes is not a structure field class: "
472 "%![req-fc-]+F, %![tgt-fc-]+F",
478 /* Same scope: path from LCA to target has no array/variant FTs */
479 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
481 BT_ASSERT_COND_DEV_MSG("Path from lowest common ancestor of target "
482 "and requesting field classes to target field class "
483 "contains an array or a variant field class: "
484 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
490 bt_object_put_ref(src_field_path
);
491 bt_object_put_ref(tgt_field_path
);
496 struct bt_field_path
*resolve_field_path(struct bt_field_class
*src_fc
,
497 struct bt_field_class
*tgt_fc
,
498 struct bt_resolve_field_path_context
*ctx
,
499 const char *api_func
)
501 BT_ASSERT_PRE_DEV_FROM_FUNC(api_func
, "valid-field-class",
502 field_path_is_valid(src_fc
, tgt_fc
, ctx
),
503 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
505 return find_field_class_in_ctx(tgt_fc
, ctx
);
508 int bt_resolve_field_paths(struct bt_field_class
*fc
,
509 struct bt_resolve_field_path_context
*ctx
,
510 const char *api_func
)
516 /* Resolving part for dynamic array and variant field classes */
517 if (bt_field_class_type_is(fc
->type
,
518 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
519 struct bt_field_class_option_with_selector_field
*opt_fc
= (void *) fc
;
521 BT_ASSERT(opt_fc
->selector_fc
);
522 BT_ASSERT(!opt_fc
->selector_field_path
);
523 opt_fc
->selector_field_path
= resolve_field_path(
524 fc
, opt_fc
->selector_fc
, ctx
, __func__
);
525 if (!opt_fc
->selector_field_path
) {
529 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
530 struct bt_field_class_array_dynamic
*dyn_array_fc
= (void *) fc
;
532 BT_ASSERT(dyn_array_fc
->length_fc
);
533 BT_ASSERT(!dyn_array_fc
->length_field_path
);
534 dyn_array_fc
->length_field_path
= resolve_field_path(
535 fc
, dyn_array_fc
->length_fc
, ctx
, __func__
);
536 if (!dyn_array_fc
->length_field_path
) {
540 } else if (bt_field_class_type_is(fc
->type
,
541 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
542 struct bt_field_class_variant_with_selector_field
*var_fc
=
545 if (var_fc
->selector_fc
) {
546 BT_ASSERT(!var_fc
->selector_field_path
);
547 var_fc
->selector_field_path
=
548 resolve_field_path(fc
,
549 (void *) var_fc
->selector_fc
, ctx
,
551 if (!var_fc
->selector_field_path
) {
559 if (bt_field_class_type_is(fc
->type
, BT_FIELD_CLASS_TYPE_OPTION
)) {
560 struct bt_field_class_option
*opt_fc
= (void *) fc
;
562 ret
= bt_resolve_field_paths(opt_fc
->content_fc
, ctx
, api_func
);
563 } else if (fc
->type
== BT_FIELD_CLASS_TYPE_STRUCTURE
||
564 bt_field_class_type_is(fc
->type
,
565 BT_FIELD_CLASS_TYPE_VARIANT
)) {
566 struct bt_field_class_named_field_class_container
*container_fc
=
570 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
571 struct bt_named_field_class
*named_fc
=
572 container_fc
->named_fcs
->pdata
[i
];
574 ret
= bt_resolve_field_paths(named_fc
->fc
, ctx
,
580 } else if (bt_field_class_type_is(fc
->type
,
581 BT_FIELD_CLASS_TYPE_ARRAY
)) {
582 struct bt_field_class_array
*array_fc
= (void *) fc
;
584 ret
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
,