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
:
52 struct bt_field_class_option
*opt_fc
= (void *) fc
;
54 struct bt_field_path_item item
= {
55 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
,
56 .index
= UINT64_C(-1),
59 bt_field_path_append_item(field_path
, &item
);
60 found
= find_field_class_recursive(opt_fc
->content_fc
,
66 bt_field_path_remove_last_item(field_path
);
69 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
70 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
:
71 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR
:
72 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR
:
74 struct bt_field_class_named_field_class_container
*container_fc
=
78 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
79 struct bt_named_field_class
*named_fc
=
80 container_fc
->named_fcs
->pdata
[i
];
81 struct bt_field_path_item item
= {
82 .type
= BT_FIELD_PATH_ITEM_TYPE_INDEX
,
86 bt_field_path_append_item(field_path
, &item
);
87 found
= find_field_class_recursive(named_fc
->fc
,
93 bt_field_path_remove_last_item(field_path
);
98 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
99 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
101 struct bt_field_class_array
*array_fc
= (void *) fc
;
102 struct bt_field_path_item item
= {
103 .type
= BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
,
104 .index
= UINT64_C(-1),
107 bt_field_path_append_item(field_path
, &item
);
108 found
= find_field_class_recursive(array_fc
->element_fc
,
114 bt_field_path_remove_last_item(field_path
);
126 int find_field_class(struct bt_field_class
*root_fc
,
127 enum bt_field_path_scope root_scope
, struct bt_field_class
*tgt_fc
,
128 struct bt_field_path
**ret_field_path
)
131 struct bt_field_path
*field_path
= NULL
;
137 field_path
= bt_field_path_create();
143 field_path
->root
= root_scope
;
144 if (!find_field_class_recursive(root_fc
, tgt_fc
, field_path
)) {
146 BT_OBJECT_PUT_REF_AND_RESET(field_path
);
150 *ret_field_path
= field_path
;
155 struct bt_field_path
*find_field_class_in_ctx(struct bt_field_class
*fc
,
156 struct bt_resolve_field_path_context
*ctx
)
158 struct bt_field_path
*field_path
= NULL
;
161 ret
= find_field_class(ctx
->packet_context
, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
,
163 if (ret
|| field_path
) {
167 ret
= find_field_class(ctx
->event_common_context
,
168 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
, fc
, &field_path
);
169 if (ret
|| field_path
) {
173 ret
= find_field_class(ctx
->event_specific_context
,
174 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, &field_path
);
175 if (ret
|| field_path
) {
179 ret
= find_field_class(ctx
->event_payload
, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
,
181 if (ret
|| field_path
) {
189 BT_ASSERT_PRE_DEV_FUNC
191 bool target_is_before_source(struct bt_field_path
*src_field_path
,
192 struct bt_field_path
*tgt_field_path
)
194 bool is_valid
= true;
195 uint64_t src_i
= 0, tgt_i
= 0;
197 if (tgt_field_path
->root
< src_field_path
->root
) {
201 if (tgt_field_path
->root
> src_field_path
->root
) {
206 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
208 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
209 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
210 struct bt_field_path_item
*src_fp_item
=
211 bt_field_path_borrow_item_by_index_inline(
212 src_field_path
, src_i
);
213 struct bt_field_path_item
*tgt_fp_item
=
214 bt_field_path_borrow_item_by_index_inline(
215 tgt_field_path
, tgt_i
);
217 if (src_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
&&
218 tgt_fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
) {
219 if (tgt_fp_item
->index
> src_fp_item
->index
) {
233 BT_ASSERT_PRE_DEV_FUNC
235 struct bt_field_class
*borrow_root_field_class(
236 struct bt_resolve_field_path_context
*ctx
, enum bt_field_path_scope scope
)
239 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
240 return ctx
->packet_context
;
241 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
242 return ctx
->event_common_context
;
243 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
244 return ctx
->event_specific_context
;
245 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
246 return ctx
->event_payload
;
254 BT_ASSERT_PRE_DEV_FUNC
256 struct bt_field_class
*borrow_child_field_class(
257 struct bt_field_class
*parent_fc
,
258 struct bt_field_path_item
*fp_item
)
260 struct bt_field_class
*child_fc
= NULL
;
262 switch (parent_fc
->type
) {
263 case BT_FIELD_CLASS_TYPE_OPTION
:
265 struct bt_field_class_option
*opt_fc
= (void *) parent_fc
;
267 BT_ASSERT(fp_item
->type
==
268 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT
);
269 child_fc
= opt_fc
->content_fc
;
272 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
273 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
:
274 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR
:
275 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR
:
277 struct bt_field_class_named_field_class_container
*container_fc
=
279 struct bt_named_field_class
*named_fc
;
281 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
282 named_fc
= container_fc
->named_fcs
->pdata
[fp_item
->index
];
283 child_fc
= named_fc
->fc
;
286 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
287 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
289 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
291 BT_ASSERT(fp_item
->type
==
292 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
);
293 child_fc
= array_fc
->element_fc
;
303 BT_ASSERT_PRE_DEV_FUNC
305 bool target_field_path_in_different_scope_has_struct_fc_only(
306 struct bt_field_path
*src_field_path
,
307 struct bt_field_path
*tgt_field_path
,
308 struct bt_resolve_field_path_context
*ctx
)
310 bool is_valid
= true;
312 struct bt_field_class
*fc
;
314 if (src_field_path
->root
== tgt_field_path
->root
) {
318 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
320 for (i
= 0; i
< tgt_field_path
->items
->len
; i
++) {
321 struct bt_field_path_item
*fp_item
=
322 bt_field_path_borrow_item_by_index_inline(
325 if (fc
->type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
||
326 fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
||
327 fc
->type
== BT_FIELD_CLASS_TYPE_OPTION
||
328 fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
||
329 fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR
||
330 fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR
) {
335 BT_ASSERT(fp_item
->type
== BT_FIELD_PATH_ITEM_TYPE_INDEX
);
336 fc
= borrow_child_field_class(fc
, fp_item
);
343 BT_ASSERT_PRE_DEV_FUNC
345 bool lca_is_structure_field_class(struct bt_field_path
*src_field_path
,
346 struct bt_field_path
*tgt_field_path
,
347 struct bt_resolve_field_path_context
*ctx
)
349 bool is_valid
= true;
350 struct bt_field_class
*src_fc
;
351 struct bt_field_class
*tgt_fc
;
352 struct bt_field_class
*prev_fc
= NULL
;
353 uint64_t src_i
= 0, tgt_i
= 0;
355 if (src_field_path
->root
!= tgt_field_path
->root
) {
359 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
360 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
364 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
365 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
366 struct bt_field_path_item
*src_fp_item
=
367 bt_field_path_borrow_item_by_index_inline(
368 src_field_path
, src_i
);
369 struct bt_field_path_item
*tgt_fp_item
=
370 bt_field_path_borrow_item_by_index_inline(
371 tgt_field_path
, tgt_i
);
373 if (src_fc
!= tgt_fc
) {
376 * This is correct: the LCA is the root
377 * scope field class, which must be a
378 * structure field class.
383 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
391 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
392 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
399 BT_ASSERT_PRE_DEV_FUNC
401 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
402 struct bt_field_path
*tgt_field_path
,
403 struct bt_resolve_field_path_context
*ctx
)
405 bool is_valid
= true;
406 struct bt_field_class
*src_fc
;
407 struct bt_field_class
*tgt_fc
;
408 uint64_t src_i
= 0, tgt_i
= 0;
410 if (src_field_path
->root
!= tgt_field_path
->root
) {
414 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
415 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
418 BT_ASSERT(src_fc
== tgt_fc
);
421 for (src_i
= 0, tgt_i
= 0; src_i
< src_field_path
->items
->len
&&
422 tgt_i
< tgt_field_path
->items
->len
; src_i
++, tgt_i
++) {
423 struct bt_field_path_item
*src_fp_item
=
424 bt_field_path_borrow_item_by_index_inline(
425 src_field_path
, src_i
);
426 struct bt_field_path_item
*tgt_fp_item
=
427 bt_field_path_borrow_item_by_index_inline(
428 tgt_field_path
, tgt_i
);
430 if (src_i
!= tgt_i
) {
431 /* Next field class is different: LCA is `tgt_fc` */
435 src_fc
= borrow_child_field_class(src_fc
, src_fp_item
);
436 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
439 /* Only structure field classes to the target */
440 for (; tgt_i
< tgt_field_path
->items
->len
; tgt_i
++) {
441 struct bt_field_path_item
*tgt_fp_item
=
442 bt_field_path_borrow_item_by_index_inline(
443 tgt_field_path
, tgt_i
);
445 if (tgt_fc
->type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
||
446 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
||
447 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_OPTION
||
448 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
||
449 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR
||
450 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR
) {
455 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_fp_item
);
462 BT_ASSERT_PRE_DEV_FUNC
464 bool field_path_is_valid(struct bt_field_class
*src_fc
,
465 struct bt_field_class
*tgt_fc
,
466 struct bt_resolve_field_path_context
*ctx
)
468 bool is_valid
= true;
469 struct bt_field_path
*src_field_path
= find_field_class_in_ctx(
471 struct bt_field_path
*tgt_field_path
= find_field_class_in_ctx(
474 if (!src_field_path
) {
475 BT_ASSERT_PRE_DEV_MSG("Cannot find requesting field class in "
476 "resolving context: %!+F", src_fc
);
481 if (!tgt_field_path
) {
482 BT_ASSERT_PRE_DEV_MSG("Cannot find target field class in "
483 "resolving context: %!+F", tgt_fc
);
488 /* Target must be before source */
489 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
490 BT_ASSERT_PRE_DEV_MSG("Target field class is located after "
491 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
498 * If target is in a different scope than source, there are no
499 * array or variant field classes on the way to the target.
501 if (!target_field_path_in_different_scope_has_struct_fc_only(
502 src_field_path
, tgt_field_path
, ctx
)) {
503 BT_ASSERT_PRE_DEV_MSG("Target field class is located in a "
504 "different scope than requesting field class, "
505 "but within an array or a variant field class: "
506 "%![req-fc-]+F, %![tgt-fc-]+F",
512 /* Same scope: LCA must be a structure field class */
513 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
514 BT_ASSERT_PRE_DEV_MSG("Lowest common ancestor of target and "
515 "requesting field classes is not a structure field class: "
516 "%![req-fc-]+F, %![tgt-fc-]+F",
522 /* Same scope: path from LCA to target has no array/variant FTs */
523 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
525 BT_ASSERT_PRE_DEV_MSG("Path from lowest common ancestor of target "
526 "and requesting field classes to target field class "
527 "contains an array or a variant field class: "
528 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
534 bt_object_put_ref(src_field_path
);
535 bt_object_put_ref(tgt_field_path
);
540 struct bt_field_path
*resolve_field_path(struct bt_field_class
*src_fc
,
541 struct bt_field_class
*tgt_fc
,
542 struct bt_resolve_field_path_context
*ctx
)
544 BT_ASSERT_PRE_DEV(field_path_is_valid(src_fc
, tgt_fc
, ctx
),
545 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
547 return find_field_class_in_ctx(tgt_fc
, ctx
);
551 int bt_resolve_field_paths(struct bt_field_class
*fc
,
552 struct bt_resolve_field_path_context
*ctx
)
558 /* Resolving part for dynamic array and variant field classes */
560 case BT_FIELD_CLASS_TYPE_OPTION
:
562 struct bt_field_class_option
*opt_fc
= (void *) fc
;
564 if (opt_fc
->selector_fc
) {
565 BT_ASSERT(!opt_fc
->selector_field_path
);
566 opt_fc
->selector_field_path
= resolve_field_path(
567 fc
, opt_fc
->selector_fc
, ctx
);
568 if (!opt_fc
->selector_field_path
) {
576 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
578 struct bt_field_class_array_dynamic
*dyn_array_fc
= (void *) fc
;
580 if (dyn_array_fc
->length_fc
) {
581 BT_ASSERT(!dyn_array_fc
->length_field_path
);
582 dyn_array_fc
->length_field_path
= resolve_field_path(
583 fc
, dyn_array_fc
->length_fc
, ctx
);
584 if (!dyn_array_fc
->length_field_path
) {
592 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR
:
593 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR
:
595 struct bt_field_class_variant_with_selector
*var_fc
=
598 if (var_fc
->selector_fc
) {
599 BT_ASSERT(!var_fc
->selector_field_path
);
600 var_fc
->selector_field_path
=
601 resolve_field_path(fc
,
602 (void *) var_fc
->selector_fc
, ctx
);
603 if (!var_fc
->selector_field_path
) {
615 case BT_FIELD_CLASS_TYPE_OPTION
:
617 struct bt_field_class_option
*opt_fc
= (void *) fc
;
619 ret
= bt_resolve_field_paths(opt_fc
->content_fc
, ctx
);
622 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
623 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
:
624 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR
:
625 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR
:
627 struct bt_field_class_named_field_class_container
*container_fc
=
631 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
632 struct bt_named_field_class
*named_fc
=
633 container_fc
->named_fcs
->pdata
[i
];
635 ret
= bt_resolve_field_paths(named_fc
->fc
, ctx
);
643 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
644 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
646 struct bt_field_class_array
*array_fc
= (void *) fc
;
648 ret
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
);