2 * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 #define BT_LOG_TAG "LIB/RESOLVE-FIELD-PATH"
24 #include "lib/logging.h"
26 #include "lib/assert-pre.h"
27 #include "common/assert.h"
28 #include <babeltrace2/trace-ir/field-path-const.h>
34 #include "field-class.h"
35 #include "field-path.h"
36 #include "resolve-field-path.h"
39 bool find_field_class_recursive(struct bt_field_class
*fc
,
40 struct bt_field_class
*tgt_fc
, struct bt_field_path
*field_path
)
50 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR
:
51 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR
:
52 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR
:
53 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR
:
55 struct bt_field_class_option
*opt_fc
= (void *) fc
;
56 struct bt_field_path_item item
= {
57 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
,
58 .index
= UINT64_C(-1),
61 bt_field_path_append_item(field_path
, &item
);
62 found
= find_field_class_recursive(opt_fc
->content_fc
,
68 bt_field_path_remove_last_item(field_path
);
71 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
72 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
:
73 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR
:
74 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR
:
76 struct bt_field_class_named_field_class_container
*container_fc
=
80 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
81 struct bt_named_field_class
*named_fc
=
82 container_fc
->named_fcs
->pdata
[i
];
83 struct bt_field_path_item item
= {
84 .type
= BT_FIELD_PATH_ITEM_TYPE_INDEX
,
88 bt_field_path_append_item(field_path
, &item
);
89 found
= find_field_class_recursive(named_fc
->fc
,
95 bt_field_path_remove_last_item(field_path
);
100 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
101 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
102 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
104 struct bt_field_class_array
*array_fc
= (void *) fc
;
105 struct bt_field_path_item item
= {
106 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
,
107 .index
= UINT64_C(-1),
110 bt_field_path_append_item(field_path
, &item
);
111 found
= find_field_class_recursive(array_fc
->element_fc
,
117 bt_field_path_remove_last_item(field_path
);
129 int find_field_class(struct bt_field_class
*root_fc
,
130 enum bt_field_path_scope root_scope
, struct bt_field_class
*tgt_fc
,
131 struct bt_field_path
**ret_field_path
)
134 struct bt_field_path
*field_path
= NULL
;
140 field_path
= bt_field_path_create();
146 field_path
->root
= root_scope
;
147 if (!find_field_class_recursive(root_fc
, tgt_fc
, field_path
)) {
149 BT_OBJECT_PUT_REF_AND_RESET(field_path
);
153 *ret_field_path
= field_path
;
158 struct bt_field_path
*find_field_class_in_ctx(struct bt_field_class
*fc
,
159 struct bt_resolve_field_path_context
*ctx
)
161 struct bt_field_path
*field_path
= NULL
;
164 ret
= find_field_class(ctx
->packet_context
, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
,
166 if (ret
|| field_path
) {
170 ret
= find_field_class(ctx
->event_common_context
,
171 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, fc
, &field_path
);
172 if (ret
|| field_path
) {
176 ret
= find_field_class(ctx
->event_specific_context
,
177 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, &field_path
);
178 if (ret
|| field_path
) {
182 ret
= find_field_class(ctx
->event_payload
, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
,
184 if (ret
|| field_path
) {
192 BT_ASSERT_PRE_DEV_FUNC
194 bool target_is_before_source(struct bt_field_path
*src_field_path
,
195 struct bt_field_path
*tgt_field_path
)
197 bool is_valid
= true;
198 uint64_t src_i
= 0, tgt_i
= 0;
200 if (tgt_field_path
->root
< src_field_path
->root
) {
204 if (tgt_field_path
->root
> src_field_path
->root
) {
209 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
211 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
212 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
213 struct bt_field_path_item
*src_fp_item
=
214 bt_field_path_borrow_item_by_index_inline(
215 src_field_path
, src_i
);
216 struct bt_field_path_item
*tgt_fp_item
=
217 bt_field_path_borrow_item_by_index_inline(
218 tgt_field_path
, tgt_i
);
220 if (src_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
&&
221 tgt_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
222 if (tgt_fp_item
->index
> src_fp_item
->index
) {
236 BT_ASSERT_PRE_DEV_FUNC
238 struct bt_field_class
*borrow_root_field_class(
239 struct bt_resolve_field_path_context
*ctx
, enum bt_field_path_scope scope
)
242 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
243 return ctx
->packet_context
;
244 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
245 return ctx
->event_common_context
;
246 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
247 return ctx
->event_specific_context
;
248 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
249 return ctx
->event_payload
;
257 BT_ASSERT_PRE_DEV_FUNC
259 struct bt_field_class
*borrow_child_field_class(
260 struct bt_field_class
*parent_fc
,
261 struct bt_field_path_item
*fp_item
)
263 struct bt_field_class
*child_fc
= NULL
;
265 switch (parent_fc
->type
) {
266 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR
:
267 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR
:
268 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR
:
269 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR
:
271 struct bt_field_class_option
*opt_fc
= (void *) parent_fc
;
273 BT_ASSERT(fp_item
->type
==
274 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
);
275 child_fc
= opt_fc
->content_fc
;
278 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
279 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
:
280 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR
:
281 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR
:
283 struct bt_field_class_named_field_class_container
*container_fc
=
285 struct bt_named_field_class
*named_fc
;
287 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
288 named_fc
= container_fc
->named_fcs
->pdata
[fp_item
->index
];
289 child_fc
= named_fc
->fc
;
292 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
293 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
294 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
296 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
298 BT_ASSERT(fp_item
->type
==
299 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
300 child_fc
= array_fc
->element_fc
;
310 BT_ASSERT_PRE_DEV_FUNC
312 bool target_field_path_in_different_scope_has_struct_fc_only(
313 struct bt_field_path
*src_field_path
,
314 struct bt_field_path
*tgt_field_path
,
315 struct bt_resolve_field_path_context
*ctx
)
317 bool is_valid
= true;
319 struct bt_field_class
*fc
;
321 if (src_field_path
->root
== tgt_field_path
->root
) {
325 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
327 for (i
= 0; i
< tgt_field_path
->items
->len
; i
++) {
328 struct bt_field_path_item
*fp_item
=
329 bt_field_path_borrow_item_by_index_inline(
332 if (fc
->type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
||
333 fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
||
334 fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
||
335 fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR
||
336 fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR
||
337 fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR
||
338 fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR
||
339 fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
||
340 fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR
||
341 fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR
) {
346 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
347 fc
= borrow_child_field_class(fc
, fp_item
);
354 BT_ASSERT_PRE_DEV_FUNC
356 bool lca_is_structure_field_class(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 struct bt_field_class
*prev_fc
= NULL
;
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
);
375 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
376 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
377 struct bt_field_path_item
*src_fp_item
=
378 bt_field_path_borrow_item_by_index_inline(
379 src_field_path
, src_i
);
380 struct bt_field_path_item
*tgt_fp_item
=
381 bt_field_path_borrow_item_by_index_inline(
382 tgt_field_path
, tgt_i
);
384 if (src_fc
!= tgt_fc
) {
387 * This is correct: the LCA is the root
388 * scope field class, which must be a
389 * structure field class.
394 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
402 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
403 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
410 BT_ASSERT_PRE_DEV_FUNC
412 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
413 struct bt_field_path
*tgt_field_path
,
414 struct bt_resolve_field_path_context
*ctx
)
416 bool is_valid
= true;
417 struct bt_field_class
*src_fc
;
418 struct bt_field_class
*tgt_fc
;
419 uint64_t src_i
= 0, tgt_i
= 0;
421 if (src_field_path
->root
!= tgt_field_path
->root
) {
425 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
426 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
429 BT_ASSERT(src_fc
== tgt_fc
);
432 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
433 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
434 struct bt_field_path_item
*src_fp_item
=
435 bt_field_path_borrow_item_by_index_inline(
436 src_field_path
, src_i
);
437 struct bt_field_path_item
*tgt_fp_item
=
438 bt_field_path_borrow_item_by_index_inline(
439 tgt_field_path
, tgt_i
);
441 if (src_i
!= tgt_i
) {
442 /* Next field class is different: LCA is `tgt_fc` */
446 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
447 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
450 /* Only structure field classes to the target */
451 for (; tgt_i
< tgt_field_path
->items
->len
; tgt_i
++) {
452 struct bt_field_path_item
*tgt_fp_item
=
453 bt_field_path_borrow_item_by_index_inline(
454 tgt_field_path
, tgt_i
);
456 if (tgt_fc
->type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
||
457 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
||
458 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
||
459 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR
||
460 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR
||
461 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR
||
462 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR
||
463 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
||
464 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR
||
465 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR
) {
470 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
477 BT_ASSERT_PRE_DEV_FUNC
479 bool field_path_is_valid(struct bt_field_class
*src_fc
,
480 struct bt_field_class
*tgt_fc
,
481 struct bt_resolve_field_path_context
*ctx
)
483 bool is_valid
= true;
484 struct bt_field_path
*src_field_path
= find_field_class_in_ctx(
486 struct bt_field_path
*tgt_field_path
= find_field_class_in_ctx(
489 if (!src_field_path
) {
490 BT_ASSERT_PRE_DEV_MSG("Cannot find requesting field class in "
491 "resolving context: %!+F", src_fc
);
496 if (!tgt_field_path
) {
497 BT_ASSERT_PRE_DEV_MSG("Cannot find target field class in "
498 "resolving context: %!+F", tgt_fc
);
503 /* Target must be before source */
504 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
505 BT_ASSERT_PRE_DEV_MSG("Target field class is located after "
506 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
513 * If target is in a different scope than source, there are no
514 * array or variant field classes on the way to the target.
516 if (!target_field_path_in_different_scope_has_struct_fc_only(
517 src_field_path
, tgt_field_path
, ctx
)) {
518 BT_ASSERT_PRE_DEV_MSG("Target field class is located in a "
519 "different scope than requesting field class, "
520 "but within an array or a variant field class: "
521 "%![req-fc-]+F, %![tgt-fc-]+F",
527 /* Same scope: LCA must be a structure field class */
528 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
529 BT_ASSERT_PRE_DEV_MSG("Lowest common ancestor of target and "
530 "requesting field classes is not a structure field class: "
531 "%![req-fc-]+F, %![tgt-fc-]+F",
537 /* Same scope: path from LCA to target has no array/variant FTs */
538 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
540 BT_ASSERT_PRE_DEV_MSG("Path from lowest common ancestor of target "
541 "and requesting field classes to target field class "
542 "contains an array or a variant field class: "
543 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
549 bt_object_put_ref(src_field_path
);
550 bt_object_put_ref(tgt_field_path
);
555 struct bt_field_path
*resolve_field_path(struct bt_field_class
*src_fc
,
556 struct bt_field_class
*tgt_fc
,
557 struct bt_resolve_field_path_context
*ctx
)
559 BT_ASSERT_PRE_DEV(field_path_is_valid(src_fc
, tgt_fc
, ctx
),
560 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
562 return find_field_class_in_ctx(tgt_fc
, ctx
);
566 int bt_resolve_field_paths(struct bt_field_class
*fc
,
567 struct bt_resolve_field_path_context
*ctx
)
573 /* Resolving part for dynamic array and variant field classes */
575 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR
:
576 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR
:
577 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR
:
579 struct bt_field_class_option_with_selector
*opt_fc
= (void *) fc
;
581 BT_ASSERT(opt_fc
->selector_fc
);
582 BT_ASSERT(!opt_fc
->selector_field_path
);
583 opt_fc
->selector_field_path
= resolve_field_path(
584 fc
, opt_fc
->selector_fc
, ctx
);
585 if (!opt_fc
->selector_field_path
) {
592 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
594 struct bt_field_class_array_dynamic
*dyn_array_fc
= (void *) fc
;
596 BT_ASSERT(dyn_array_fc
->length_fc
);
597 BT_ASSERT(!dyn_array_fc
->length_field_path
);
598 dyn_array_fc
->length_field_path
= resolve_field_path(
599 fc
, dyn_array_fc
->length_fc
, ctx
);
600 if (!dyn_array_fc
->length_field_path
) {
607 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR
:
608 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR
:
610 struct bt_field_class_variant_with_selector
*var_fc
=
613 if (var_fc
->selector_fc
) {
614 BT_ASSERT(!var_fc
->selector_field_path
);
615 var_fc
->selector_field_path
=
616 resolve_field_path(fc
,
617 (void *) var_fc
->selector_fc
, ctx
);
618 if (!var_fc
->selector_field_path
) {
630 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR
:
631 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR
:
632 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR
:
633 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR
:
635 struct bt_field_class_option
*opt_fc
= (void *) fc
;
637 ret
= bt_resolve_field_paths(opt_fc
->content_fc
, ctx
);
640 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
641 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
:
642 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR
:
643 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR
:
645 struct bt_field_class_named_field_class_container
*container_fc
=
649 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
650 struct bt_named_field_class
*named_fc
=
651 container_fc
->named_fcs
->pdata
[i
];
653 ret
= bt_resolve_field_paths(named_fc
->fc
, ctx
);
661 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
662 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
663 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
665 struct bt_field_class_array
*array_fc
= (void *) fc
;
667 ret
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
);