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 "RESOLVE-FIELD-PATH"
24 #include <babeltrace/lib-logging-internal.h>
26 #include <babeltrace/assert-pre-internal.h>
27 #include <babeltrace/assert-internal.h>
28 #include <babeltrace/object.h>
29 #include <babeltrace/trace-ir/field-classes-internal.h>
30 #include <babeltrace/trace-ir/field-path-internal.h>
31 #include <babeltrace/trace-ir/field-path-const.h>
32 #include <babeltrace/trace-ir/resolve-field-path-internal.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_STRUCTURE
:
51 case BT_FIELD_CLASS_TYPE_VARIANT
:
53 struct bt_field_class_named_field_class_container
*container_fc
=
57 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
58 struct bt_named_field_class
*named_fc
=
59 BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
62 g_array_append_val(field_path
->indexes
, i
);
63 found
= find_field_class_recursive(named_fc
->fc
,
69 g_array_set_size(field_path
->indexes
,
70 field_path
->indexes
->len
- 1);
75 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
76 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
78 struct bt_field_class_array
*array_fc
= (void *) fc
;
80 found
= find_field_class_recursive(array_fc
->element_fc
,
93 int find_field_class(struct bt_field_class
*root_fc
,
94 enum bt_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_header
, BT_SCOPE_PACKET_HEADER
,
130 if (ret
|| field_path
) {
134 ret
= find_field_class(ctx
->packet_context
, BT_SCOPE_PACKET_CONTEXT
,
136 if (ret
|| field_path
) {
140 ret
= find_field_class(ctx
->event_header
, BT_SCOPE_EVENT_HEADER
,
142 if (ret
|| field_path
) {
146 ret
= find_field_class(ctx
->event_common_context
,
147 BT_SCOPE_EVENT_COMMON_CONTEXT
, fc
, &field_path
);
148 if (ret
|| field_path
) {
152 ret
= find_field_class(ctx
->event_specific_context
,
153 BT_SCOPE_EVENT_SPECIFIC_CONTEXT
, fc
, &field_path
);
154 if (ret
|| field_path
) {
158 ret
= find_field_class(ctx
->event_payload
, BT_SCOPE_EVENT_PAYLOAD
,
160 if (ret
|| field_path
) {
170 bool target_is_before_source(struct bt_field_path
*src_field_path
,
171 struct bt_field_path
*tgt_field_path
)
173 bool is_valid
= true;
174 uint64_t src_i
= 0, tgt_i
= 0;
176 if (tgt_field_path
->root
< src_field_path
->root
) {
180 if (tgt_field_path
->root
> src_field_path
->root
) {
185 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
187 while (src_i
< src_field_path
->indexes
->len
&&
188 tgt_i
< tgt_field_path
->indexes
->len
) {
189 uint64_t src_index
= bt_field_path_get_index_by_index_inline(
190 src_field_path
, src_i
);
191 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
192 tgt_field_path
, tgt_i
);
194 if (tgt_index
> src_index
) {
209 struct bt_field_class
*borrow_root_field_class(
210 struct bt_resolve_field_path_context
*ctx
, enum bt_scope scope
)
213 case BT_SCOPE_PACKET_HEADER
:
214 return ctx
->packet_header
;
215 case BT_SCOPE_PACKET_CONTEXT
:
216 return ctx
->packet_context
;
217 case BT_SCOPE_EVENT_HEADER
:
218 return ctx
->event_header
;
219 case BT_SCOPE_EVENT_COMMON_CONTEXT
:
220 return ctx
->event_common_context
;
221 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT
:
222 return ctx
->event_specific_context
;
223 case BT_SCOPE_EVENT_PAYLOAD
:
224 return ctx
->event_payload
;
234 struct bt_field_class
*borrow_child_field_class(struct bt_field_class
*parent_fc
,
235 uint64_t index
, bool *advance
)
237 struct bt_field_class
*child_fc
= NULL
;
239 switch (parent_fc
->type
) {
240 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
241 case BT_FIELD_CLASS_TYPE_VARIANT
:
243 struct bt_named_field_class
*named_fc
=
244 BT_FIELD_CLASS_NAMED_FC_AT_INDEX(parent_fc
, index
);
246 child_fc
= named_fc
->fc
;
250 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
251 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
253 struct bt_field_class_array
*array_fc
= (void *) parent_fc
;
255 child_fc
= array_fc
->element_fc
;
268 bool target_field_path_in_different_scope_has_struct_fc_only(
269 struct bt_field_path
*src_field_path
,
270 struct bt_field_path
*tgt_field_path
,
271 struct bt_resolve_field_path_context
*ctx
)
273 bool is_valid
= true;
275 struct bt_field_class
*fc
;
277 if (src_field_path
->root
== tgt_field_path
->root
) {
281 fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
283 while (i
< tgt_field_path
->indexes
->len
) {
284 uint64_t index
= bt_field_path_get_index_by_index_inline(
288 if (fc
->type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
||
289 fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
||
290 fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT
) {
295 fc
= borrow_child_field_class(fc
, index
, &advance
);
308 bool lca_is_structure_field_class(struct bt_field_path
*src_field_path
,
309 struct bt_field_path
*tgt_field_path
,
310 struct bt_resolve_field_path_context
*ctx
)
312 bool is_valid
= true;
313 struct bt_field_class
*src_fc
;
314 struct bt_field_class
*tgt_fc
;
315 struct bt_field_class
*prev_fc
= NULL
;
316 uint64_t src_i
= 0, tgt_i
= 0;
318 if (src_field_path
->root
!= tgt_field_path
->root
) {
322 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
323 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
327 while (src_i
< src_field_path
->indexes
->len
&&
328 tgt_i
< tgt_field_path
->indexes
->len
) {
330 uint64_t src_index
= bt_field_path_get_index_by_index_inline(
331 src_field_path
, src_i
);
332 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
333 tgt_field_path
, tgt_i
);
335 if (src_fc
!= tgt_fc
) {
338 * This is correct: the LCA is the root
339 * scope field class, which must be a
340 * structure field class.
345 if (prev_fc
->type
!= BT_FIELD_CLASS_TYPE_STRUCTURE
) {
353 src_fc
= borrow_child_field_class(src_fc
, src_index
, &advance
);
359 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_index
, &advance
);
372 bool lca_to_target_has_struct_fc_only(struct bt_field_path
*src_field_path
,
373 struct bt_field_path
*tgt_field_path
,
374 struct bt_resolve_field_path_context
*ctx
)
376 bool is_valid
= true;
377 struct bt_field_class
*src_fc
;
378 struct bt_field_class
*tgt_fc
;
379 uint64_t src_i
= 0, tgt_i
= 0;
381 if (src_field_path
->root
!= tgt_field_path
->root
) {
385 src_fc
= borrow_root_field_class(ctx
, src_field_path
->root
);
386 tgt_fc
= borrow_root_field_class(ctx
, tgt_field_path
->root
);
389 BT_ASSERT(src_fc
== tgt_fc
);
392 while (src_i
< src_field_path
->indexes
->len
&&
393 tgt_i
< tgt_field_path
->indexes
->len
) {
395 uint64_t src_index
= bt_field_path_get_index_by_index_inline(
396 src_field_path
, src_i
);
397 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
398 tgt_field_path
, tgt_i
);
400 if (src_i
!= tgt_i
) {
401 /* Next field class is different: LCA is `tgt_fc` */
405 src_fc
= borrow_child_field_class(src_fc
, src_index
, &advance
);
411 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_index
, &advance
);
418 /* Only structure field classes to the target */
419 while (tgt_i
< tgt_field_path
->indexes
->len
) {
421 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
422 tgt_field_path
, tgt_i
);
424 if (tgt_fc
->type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
||
425 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
||
426 tgt_fc
->type
== BT_FIELD_CLASS_TYPE_VARIANT
) {
431 tgt_fc
= borrow_child_field_class(tgt_fc
, tgt_index
, &advance
);
444 bool field_path_is_valid(struct bt_field_class
*src_fc
,
445 struct bt_field_class
*tgt_fc
,
446 struct bt_resolve_field_path_context
*ctx
)
448 bool is_valid
= true;
449 struct bt_field_path
*src_field_path
= find_field_class_in_ctx(
451 struct bt_field_path
*tgt_field_path
= find_field_class_in_ctx(
454 if (!src_field_path
) {
455 BT_ASSERT_PRE_MSG("Cannot find requesting field class in "
456 "resolving context: %!+F", src_fc
);
461 if (!tgt_field_path
) {
462 BT_ASSERT_PRE_MSG("Cannot find target field class in "
463 "resolving context: %!+F", tgt_fc
);
468 /* Target must be before source */
469 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
470 BT_ASSERT_PRE_MSG("Target field class is located after "
471 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
478 * If target is in a different scope than source, there are no
479 * array or variant field classes on the way to the target.
481 if (!target_field_path_in_different_scope_has_struct_fc_only(
482 src_field_path
, tgt_field_path
, ctx
)) {
483 BT_ASSERT_PRE_MSG("Target field class is located in a "
484 "different scope than requesting field class, "
485 "but within an array or a variant field class: "
486 "%![req-fc-]+F, %![tgt-fc-]+F",
492 /* Same scope: LCA must be a structure field class */
493 if (!lca_is_structure_field_class(src_field_path
, tgt_field_path
, ctx
)) {
494 BT_ASSERT_PRE_MSG("Lowest common ancestor of target and "
495 "requesting field classes is not a structure field class: "
496 "%![req-fc-]+F, %![tgt-fc-]+F",
502 /* Same scope: path from LCA to target has no array/variant FTs */
503 if (!lca_to_target_has_struct_fc_only(src_field_path
, tgt_field_path
,
505 BT_ASSERT_PRE_MSG("Path from lowest common ancestor of target "
506 "and requesting field classes to target field class "
507 "contains an array or a variant field class: "
508 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc
, tgt_fc
);
514 bt_object_put_ref(src_field_path
);
515 bt_object_put_ref(tgt_field_path
);
520 struct bt_field_path
*resolve_field_path(struct bt_field_class
*src_fc
,
521 struct bt_field_class
*tgt_fc
,
522 struct bt_resolve_field_path_context
*ctx
)
524 BT_ASSERT_PRE(field_path_is_valid(src_fc
, tgt_fc
, ctx
),
525 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
527 return find_field_class_in_ctx(tgt_fc
, ctx
);
531 int bt_resolve_field_paths(struct bt_field_class
*fc
,
532 struct bt_resolve_field_path_context
*ctx
)
538 /* Resolving part for dynamic array and variant field classes */
540 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
542 struct bt_field_class_dynamic_array
*dyn_array_fc
= (void *) fc
;
544 if (dyn_array_fc
->length_fc
) {
545 BT_ASSERT(!dyn_array_fc
->length_field_path
);
546 dyn_array_fc
->length_field_path
= resolve_field_path(
547 fc
, dyn_array_fc
->length_fc
, ctx
);
548 if (!dyn_array_fc
->length_field_path
) {
556 case BT_FIELD_CLASS_TYPE_VARIANT
:
558 struct bt_field_class_variant
*var_fc
= (void *) fc
;
560 if (var_fc
->selector_fc
) {
561 BT_ASSERT(!var_fc
->selector_field_path
);
562 var_fc
->selector_field_path
=
563 resolve_field_path(fc
,
564 var_fc
->selector_fc
, ctx
);
565 if (!var_fc
->selector_field_path
) {
577 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
578 case BT_FIELD_CLASS_TYPE_VARIANT
:
580 struct bt_field_class_named_field_class_container
*container_fc
=
584 for (i
= 0; i
< container_fc
->named_fcs
->len
; i
++) {
585 struct bt_named_field_class
*named_fc
=
586 BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
589 ret
= bt_resolve_field_paths(named_fc
->fc
, ctx
);
597 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
598 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY
:
600 struct bt_field_class_array
*array_fc
= (void *) fc
;
602 ret
= bt_resolve_field_paths(array_fc
->element_fc
, ctx
);