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/trace-ir/field-types-internal.h>
29 #include <babeltrace/trace-ir/field-path-internal.h>
30 #include <babeltrace/trace-ir/field-path.h>
31 #include <babeltrace/trace-ir/resolve-field-path-internal.h>
38 bool find_field_type_recursive(struct bt_field_type
*ft
,
39 struct bt_field_type
*tgt_ft
, struct bt_field_path
*field_path
)
49 case BT_FIELD_TYPE_ID_STRUCTURE
:
50 case BT_FIELD_TYPE_ID_VARIANT
:
52 struct bt_field_type_named_field_types_container
*container_ft
=
56 for (i
= 0; i
< container_ft
->named_fts
->len
; i
++) {
57 struct bt_named_field_type
*named_ft
=
58 BT_FIELD_TYPE_NAMED_FT_AT_INDEX(
61 g_array_append_val(field_path
->indexes
, i
);
62 found
= find_field_type_recursive(named_ft
->ft
,
68 g_array_set_size(field_path
->indexes
,
69 field_path
->indexes
->len
- 1);
74 case BT_FIELD_TYPE_ID_STATIC_ARRAY
:
75 case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY
:
77 struct bt_field_type_array
*array_ft
= (void *) ft
;
79 found
= find_field_type_recursive(array_ft
->element_ft
,
92 int find_field_type(struct bt_field_type
*root_ft
,
93 enum bt_scope root_scope
, struct bt_field_type
*tgt_ft
,
94 struct bt_field_path
**ret_field_path
)
97 struct bt_field_path
*field_path
= NULL
;
103 field_path
= bt_field_path_create();
109 field_path
->root
= root_scope
;
110 if (!find_field_type_recursive(root_ft
, tgt_ft
, field_path
)) {
116 *ret_field_path
= field_path
;
121 struct bt_field_path
*find_field_type_in_ctx(struct bt_field_type
*ft
,
122 struct bt_resolve_field_path_context
*ctx
)
124 struct bt_field_path
*field_path
= NULL
;
127 ret
= find_field_type(ctx
->packet_header
, BT_SCOPE_PACKET_HEADER
,
129 if (ret
|| field_path
) {
133 ret
= find_field_type(ctx
->packet_context
, BT_SCOPE_PACKET_CONTEXT
,
135 if (ret
|| field_path
) {
139 ret
= find_field_type(ctx
->event_header
, BT_SCOPE_EVENT_HEADER
,
141 if (ret
|| field_path
) {
145 ret
= find_field_type(ctx
->event_common_context
,
146 BT_SCOPE_EVENT_COMMON_CONTEXT
, ft
, &field_path
);
147 if (ret
|| field_path
) {
151 ret
= find_field_type(ctx
->event_specific_context
,
152 BT_SCOPE_EVENT_SPECIFIC_CONTEXT
, ft
, &field_path
);
153 if (ret
|| field_path
) {
157 ret
= find_field_type(ctx
->event_payload
, BT_SCOPE_EVENT_PAYLOAD
,
159 if (ret
|| field_path
) {
169 bool target_is_before_source(struct bt_field_path
*src_field_path
,
170 struct bt_field_path
*tgt_field_path
)
172 bool is_valid
= true;
173 uint64_t src_i
= 0, tgt_i
= 0;
175 if (tgt_field_path
->root
< src_field_path
->root
) {
179 if (tgt_field_path
->root
> src_field_path
->root
) {
184 BT_ASSERT(tgt_field_path
->root
== src_field_path
->root
);
186 while (src_i
< src_field_path
->indexes
->len
&&
187 tgt_i
< tgt_field_path
->indexes
->len
) {
188 uint64_t src_index
= bt_field_path_get_index_by_index_inline(
189 src_field_path
, src_i
);
190 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
191 tgt_field_path
, tgt_i
);
193 if (tgt_index
> src_index
) {
208 struct bt_field_type
*borrow_root_field_type(
209 struct bt_resolve_field_path_context
*ctx
, enum bt_scope scope
)
212 case BT_SCOPE_PACKET_HEADER
:
213 return ctx
->packet_header
;
214 case BT_SCOPE_PACKET_CONTEXT
:
215 return ctx
->packet_context
;
216 case BT_SCOPE_EVENT_HEADER
:
217 return ctx
->event_header
;
218 case BT_SCOPE_EVENT_COMMON_CONTEXT
:
219 return ctx
->event_common_context
;
220 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT
:
221 return ctx
->event_specific_context
;
222 case BT_SCOPE_EVENT_PAYLOAD
:
223 return ctx
->event_payload
;
233 struct bt_field_type
*borrow_child_field_type(struct bt_field_type
*parent_ft
,
234 uint64_t index
, bool *advance
)
236 struct bt_field_type
*child_ft
= NULL
;
238 switch (parent_ft
->id
) {
239 case BT_FIELD_TYPE_ID_STRUCTURE
:
240 case BT_FIELD_TYPE_ID_VARIANT
:
242 struct bt_named_field_type
*named_ft
=
243 BT_FIELD_TYPE_NAMED_FT_AT_INDEX(parent_ft
, index
);
245 child_ft
= named_ft
->ft
;
249 case BT_FIELD_TYPE_ID_STATIC_ARRAY
:
250 case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY
:
252 struct bt_field_type_array
*array_ft
= (void *) parent_ft
;
254 child_ft
= array_ft
->element_ft
;
267 bool target_field_path_in_different_scope_has_struct_ft_only(
268 struct bt_field_path
*src_field_path
,
269 struct bt_field_path
*tgt_field_path
,
270 struct bt_resolve_field_path_context
*ctx
)
272 bool is_valid
= true;
274 struct bt_field_type
*ft
;
276 if (src_field_path
->root
== tgt_field_path
->root
) {
280 ft
= borrow_root_field_type(ctx
, tgt_field_path
->root
);
282 while (i
< tgt_field_path
->indexes
->len
) {
283 uint64_t index
= bt_field_path_get_index_by_index_inline(
287 if (ft
->id
== BT_FIELD_TYPE_ID_STATIC_ARRAY
||
288 ft
->id
== BT_FIELD_TYPE_ID_DYNAMIC_ARRAY
||
289 ft
->id
== BT_FIELD_TYPE_ID_VARIANT
) {
294 ft
= borrow_child_field_type(ft
, index
, &advance
);
307 bool lca_is_structure_field_type(struct bt_field_path
*src_field_path
,
308 struct bt_field_path
*tgt_field_path
,
309 struct bt_resolve_field_path_context
*ctx
)
311 bool is_valid
= true;
312 struct bt_field_type
*src_ft
;
313 struct bt_field_type
*tgt_ft
;
314 struct bt_field_type
*prev_ft
= NULL
;
315 uint64_t src_i
= 0, tgt_i
= 0;
317 if (src_field_path
->root
!= tgt_field_path
->root
) {
321 src_ft
= borrow_root_field_type(ctx
, src_field_path
->root
);
322 tgt_ft
= borrow_root_field_type(ctx
, tgt_field_path
->root
);
326 while (src_i
< src_field_path
->indexes
->len
&&
327 tgt_i
< tgt_field_path
->indexes
->len
) {
329 uint64_t src_index
= bt_field_path_get_index_by_index_inline(
330 src_field_path
, src_i
);
331 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
332 tgt_field_path
, tgt_i
);
334 if (src_ft
!= tgt_ft
) {
337 * This is correct: the LCA is the root
338 * scope field type, which must be a
339 * structure field type.
344 if (prev_ft
->id
!= BT_FIELD_TYPE_ID_STRUCTURE
) {
352 src_ft
= borrow_child_field_type(src_ft
, src_index
, &advance
);
358 tgt_ft
= borrow_child_field_type(tgt_ft
, tgt_index
, &advance
);
371 bool lca_to_target_has_struct_ft_only(struct bt_field_path
*src_field_path
,
372 struct bt_field_path
*tgt_field_path
,
373 struct bt_resolve_field_path_context
*ctx
)
375 bool is_valid
= true;
376 struct bt_field_type
*src_ft
;
377 struct bt_field_type
*tgt_ft
;
378 uint64_t src_i
= 0, tgt_i
= 0;
380 if (src_field_path
->root
!= tgt_field_path
->root
) {
384 src_ft
= borrow_root_field_type(ctx
, src_field_path
->root
);
385 tgt_ft
= borrow_root_field_type(ctx
, tgt_field_path
->root
);
388 BT_ASSERT(src_ft
== tgt_ft
);
391 while (src_i
< src_field_path
->indexes
->len
&&
392 tgt_i
< tgt_field_path
->indexes
->len
) {
394 uint64_t src_index
= bt_field_path_get_index_by_index_inline(
395 src_field_path
, src_i
);
396 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
397 tgt_field_path
, tgt_i
);
399 if (src_i
!= tgt_i
) {
400 /* Next FT is different: LCA is `tgt_ft` */
404 src_ft
= borrow_child_field_type(src_ft
, src_index
, &advance
);
410 tgt_ft
= borrow_child_field_type(tgt_ft
, tgt_index
, &advance
);
417 /* Only structure field types to the target */
418 while (tgt_i
< tgt_field_path
->indexes
->len
) {
420 uint64_t tgt_index
= bt_field_path_get_index_by_index_inline(
421 tgt_field_path
, tgt_i
);
423 if (tgt_ft
->id
== BT_FIELD_TYPE_ID_STATIC_ARRAY
||
424 tgt_ft
->id
== BT_FIELD_TYPE_ID_DYNAMIC_ARRAY
||
425 tgt_ft
->id
== BT_FIELD_TYPE_ID_VARIANT
) {
430 tgt_ft
= borrow_child_field_type(tgt_ft
, tgt_index
, &advance
);
443 bool field_path_is_valid(struct bt_field_type
*src_ft
,
444 struct bt_field_type
*tgt_ft
,
445 struct bt_resolve_field_path_context
*ctx
)
447 bool is_valid
= true;
448 struct bt_field_path
*src_field_path
= find_field_type_in_ctx(
450 struct bt_field_path
*tgt_field_path
= find_field_type_in_ctx(
453 if (!src_field_path
) {
454 BT_ASSERT_PRE_MSG("Cannot find requesting field type in "
455 "resolving context: %!+F", src_ft
);
460 if (!tgt_field_path
) {
461 BT_ASSERT_PRE_MSG("Cannot find target field type in "
462 "resolving context: %!+F", tgt_ft
);
467 /* Target must be before source */
468 if (!target_is_before_source(src_field_path
, tgt_field_path
)) {
469 BT_ASSERT_PRE_MSG("Target field type is located after "
470 "requesting field type: %![req-ft-]+F, %![tgt-ft-]+F",
477 * If target is in a different scope than source, there are no
478 * array or variant field types on the way to the target.
480 if (!target_field_path_in_different_scope_has_struct_ft_only(
481 src_field_path
, tgt_field_path
, ctx
)) {
482 BT_ASSERT_PRE_MSG("Target field type is located in a "
483 "different scope than requesting field type, "
484 "but within an array or a variant field type: "
485 "%![req-ft-]+F, %![tgt-ft-]+F",
491 /* Same scope: LCA must be a structure field type */
492 if (!lca_is_structure_field_type(src_field_path
, tgt_field_path
, ctx
)) {
493 BT_ASSERT_PRE_MSG("Lowest common ancestor of target and "
494 "requesting field types is not a structure field type: "
495 "%![req-ft-]+F, %![tgt-ft-]+F",
501 /* Same scope: path from LCA to target has no array/variant FTs */
502 if (!lca_to_target_has_struct_ft_only(src_field_path
, tgt_field_path
,
504 BT_ASSERT_PRE_MSG("Path from lowest common ancestor of target "
505 "and requesting field types to target field type "
506 "contains an array or a variant field type: "
507 "%![req-ft-]+F, %![tgt-ft-]+F", src_ft
, tgt_ft
);
513 bt_put(src_field_path
);
514 bt_put(tgt_field_path
);
519 struct bt_field_path
*resolve_field_path(struct bt_field_type
*src_ft
,
520 struct bt_field_type
*tgt_ft
,
521 struct bt_resolve_field_path_context
*ctx
)
523 BT_ASSERT_PRE(field_path_is_valid(src_ft
, tgt_ft
, ctx
),
524 "Invalid target field type: %![req-ft-]+F, %![tgt-ft-]+F",
526 return find_field_type_in_ctx(tgt_ft
, ctx
);
530 int bt_resolve_field_paths(struct bt_field_type
*ft
,
531 struct bt_resolve_field_path_context
*ctx
)
537 /* Resolving part for dynamic array and variant field types */
539 case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY
:
541 struct bt_field_type_dynamic_array
*dyn_array_ft
= (void *) ft
;
543 if (dyn_array_ft
->length_ft
) {
544 BT_ASSERT(!dyn_array_ft
->length_field_path
);
545 dyn_array_ft
->length_field_path
= resolve_field_path(
546 ft
, dyn_array_ft
->length_ft
, ctx
);
547 if (!dyn_array_ft
->length_field_path
) {
555 case BT_FIELD_TYPE_ID_VARIANT
:
557 struct bt_field_type_variant
*var_ft
= (void *) ft
;
559 if (var_ft
->selector_ft
) {
560 BT_ASSERT(!var_ft
->selector_field_path
);
561 var_ft
->selector_field_path
=
562 resolve_field_path(ft
,
563 var_ft
->selector_ft
, ctx
);
564 if (!var_ft
->selector_field_path
) {
576 case BT_FIELD_TYPE_ID_STRUCTURE
:
577 case BT_FIELD_TYPE_ID_VARIANT
:
579 struct bt_field_type_named_field_types_container
*container_ft
=
583 for (i
= 0; i
< container_ft
->named_fts
->len
; i
++) {
584 struct bt_named_field_type
*named_ft
=
585 BT_FIELD_TYPE_NAMED_FT_AT_INDEX(
588 ret
= bt_resolve_field_paths(named_ft
->ft
, ctx
);
596 case BT_FIELD_TYPE_ID_STATIC_ARRAY
:
597 case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY
:
599 struct bt_field_type_array
*array_ft
= (void *) ft
;
601 ret
= bt_resolve_field_paths(array_ft
->element_ft
, ctx
);