lib: split trace API into trace class and trace APIs
[babeltrace.git] / lib / trace-ir / resolve-field-path.c
CommitLineData
44c440bc
PP
1/*
2 * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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
20 * SOFTWARE.
21 */
22
23#define BT_LOG_TAG "RESOLVE-FIELD-PATH"
24#include <babeltrace/lib-logging-internal.h>
25
26#include <babeltrace/assert-pre-internal.h>
27#include <babeltrace/assert-internal.h>
e5be10ef 28#include <babeltrace/object.h>
5cd6d0e5 29#include <babeltrace/trace-ir/field-classes-internal.h>
56e18c4c 30#include <babeltrace/trace-ir/field-path-internal.h>
40f4ba76 31#include <babeltrace/trace-ir/field-path-const.h>
56e18c4c 32#include <babeltrace/trace-ir/resolve-field-path-internal.h>
44c440bc
PP
33#include <limits.h>
34#include <stdint.h>
35#include <inttypes.h>
36#include <glib.h>
37
38static
5cd6d0e5
PP
39bool find_field_class_recursive(struct bt_field_class *fc,
40 struct bt_field_class *tgt_fc, struct bt_field_path *field_path)
44c440bc
PP
41{
42 bool found = false;
43
5cd6d0e5 44 if (tgt_fc == fc) {
44c440bc
PP
45 found = true;
46 goto end;
47 }
48
864cad70
PP
49 switch (fc->type) {
50 case BT_FIELD_CLASS_TYPE_STRUCTURE:
51 case BT_FIELD_CLASS_TYPE_VARIANT:
44c440bc 52 {
5cd6d0e5
PP
53 struct bt_field_class_named_field_class_container *container_fc =
54 (void *) fc;
44c440bc
PP
55 uint64_t i;
56
5cd6d0e5
PP
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(
60 container_fc, i);
44c440bc
PP
61
62 g_array_append_val(field_path->indexes, i);
5cd6d0e5
PP
63 found = find_field_class_recursive(named_fc->fc,
64 tgt_fc, field_path);
44c440bc
PP
65 if (found) {
66 goto end;
67 }
68
69 g_array_set_size(field_path->indexes,
70 field_path->indexes->len - 1);
71 }
72
73 break;
74 }
864cad70
PP
75 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
76 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
44c440bc 77 {
5cd6d0e5 78 struct bt_field_class_array *array_fc = (void *) fc;
44c440bc 79
5cd6d0e5
PP
80 found = find_field_class_recursive(array_fc->element_fc,
81 tgt_fc, field_path);
44c440bc
PP
82 break;
83 }
84 default:
85 break;
86 }
87
88end:
89 return found;
90}
91
92static
5cd6d0e5
PP
93int find_field_class(struct bt_field_class *root_fc,
94 enum bt_scope root_scope, struct bt_field_class *tgt_fc,
44c440bc
PP
95 struct bt_field_path **ret_field_path)
96{
97 int ret = 0;
98 struct bt_field_path *field_path = NULL;
99
5cd6d0e5 100 if (!root_fc) {
44c440bc
PP
101 goto end;
102 }
103
104 field_path = bt_field_path_create();
105 if (!field_path) {
106 ret = -1;
107 goto end;
108 }
109
110 field_path->root = root_scope;
5cd6d0e5 111 if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) {
44c440bc 112 /* Not found here */
65300d60 113 BT_OBJECT_PUT_REF_AND_RESET(field_path);
44c440bc
PP
114 }
115
116end:
117 *ret_field_path = field_path;
118 return ret;
119}
120
121static
5cd6d0e5 122struct bt_field_path *find_field_class_in_ctx(struct bt_field_class *fc,
44c440bc
PP
123 struct bt_resolve_field_path_context *ctx)
124{
125 struct bt_field_path *field_path = NULL;
126 int ret;
127
5cd6d0e5
PP
128 ret = find_field_class(ctx->packet_header, BT_SCOPE_PACKET_HEADER,
129 fc, &field_path);
44c440bc
PP
130 if (ret || field_path) {
131 goto end;
132 }
133
5cd6d0e5
PP
134 ret = find_field_class(ctx->packet_context, BT_SCOPE_PACKET_CONTEXT,
135 fc, &field_path);
44c440bc
PP
136 if (ret || field_path) {
137 goto end;
138 }
139
5cd6d0e5
PP
140 ret = find_field_class(ctx->event_header, BT_SCOPE_EVENT_HEADER,
141 fc, &field_path);
44c440bc
PP
142 if (ret || field_path) {
143 goto end;
144 }
145
5cd6d0e5
PP
146 ret = find_field_class(ctx->event_common_context,
147 BT_SCOPE_EVENT_COMMON_CONTEXT, fc, &field_path);
44c440bc
PP
148 if (ret || field_path) {
149 goto end;
150 }
151
5cd6d0e5
PP
152 ret = find_field_class(ctx->event_specific_context,
153 BT_SCOPE_EVENT_SPECIFIC_CONTEXT, fc, &field_path);
44c440bc
PP
154 if (ret || field_path) {
155 goto end;
156 }
157
5cd6d0e5
PP
158 ret = find_field_class(ctx->event_payload, BT_SCOPE_EVENT_PAYLOAD,
159 fc, &field_path);
44c440bc
PP
160 if (ret || field_path) {
161 goto end;
162 }
163
164end:
165 return field_path;
166}
167
168BT_ASSERT_PRE_FUNC
169static inline
170bool target_is_before_source(struct bt_field_path *src_field_path,
171 struct bt_field_path *tgt_field_path)
172{
173 bool is_valid = true;
174 uint64_t src_i = 0, tgt_i = 0;
175
176 if (tgt_field_path->root < src_field_path->root) {
177 goto end;
178 }
179
180 if (tgt_field_path->root > src_field_path->root) {
181 is_valid = false;
182 goto end;
183 }
184
185 BT_ASSERT(tgt_field_path->root == src_field_path->root);
186
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);
193
194 if (tgt_index > src_index) {
195 is_valid = false;
196 goto end;
197 }
198
199 src_i++;
200 tgt_i++;
201 }
202
203end:
204 return is_valid;
205}
206
207BT_ASSERT_PRE_FUNC
208static inline
5cd6d0e5 209struct bt_field_class *borrow_root_field_class(
44c440bc
PP
210 struct bt_resolve_field_path_context *ctx, enum bt_scope scope)
211{
212 switch (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;
225 default:
226 abort();
227 }
228
229 return NULL;
230}
231
232BT_ASSERT_PRE_FUNC
233static inline
5cd6d0e5 234struct bt_field_class *borrow_child_field_class(struct bt_field_class *parent_fc,
44c440bc
PP
235 uint64_t index, bool *advance)
236{
5cd6d0e5 237 struct bt_field_class *child_fc = NULL;
44c440bc 238
864cad70
PP
239 switch (parent_fc->type) {
240 case BT_FIELD_CLASS_TYPE_STRUCTURE:
241 case BT_FIELD_CLASS_TYPE_VARIANT:
44c440bc 242 {
5cd6d0e5
PP
243 struct bt_named_field_class *named_fc =
244 BT_FIELD_CLASS_NAMED_FC_AT_INDEX(parent_fc, index);
44c440bc 245
5cd6d0e5 246 child_fc = named_fc->fc;
44c440bc
PP
247 *advance = true;
248 break;
249 }
864cad70
PP
250 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
251 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
44c440bc 252 {
5cd6d0e5 253 struct bt_field_class_array *array_fc = (void *) parent_fc;
44c440bc 254
5cd6d0e5 255 child_fc = array_fc->element_fc;
44c440bc
PP
256 *advance = false;
257 break;
258 }
259 default:
260 break;
261 }
262
5cd6d0e5 263 return child_fc;
44c440bc
PP
264}
265
266BT_ASSERT_PRE_FUNC
267static inline
5cd6d0e5 268bool target_field_path_in_different_scope_has_struct_fc_only(
44c440bc
PP
269 struct bt_field_path *src_field_path,
270 struct bt_field_path *tgt_field_path,
271 struct bt_resolve_field_path_context *ctx)
272{
273 bool is_valid = true;
274 uint64_t i = 0;
5cd6d0e5 275 struct bt_field_class *fc;
44c440bc
PP
276
277 if (src_field_path->root == tgt_field_path->root) {
278 goto end;
279 }
280
5cd6d0e5 281 fc = borrow_root_field_class(ctx, tgt_field_path->root);
44c440bc
PP
282
283 while (i < tgt_field_path->indexes->len) {
284 uint64_t index = bt_field_path_get_index_by_index_inline(
285 tgt_field_path, i);
286 bool advance;
287
864cad70
PP
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) {
44c440bc
PP
291 is_valid = false;
292 goto end;
293 }
294
5cd6d0e5 295 fc = borrow_child_field_class(fc, index, &advance);
44c440bc
PP
296
297 if (advance) {
298 i++;
299 }
300 }
301
302end:
303 return is_valid;
304}
305
306BT_ASSERT_PRE_FUNC
307static inline
5cd6d0e5 308bool lca_is_structure_field_class(struct bt_field_path *src_field_path,
44c440bc
PP
309 struct bt_field_path *tgt_field_path,
310 struct bt_resolve_field_path_context *ctx)
311{
312 bool is_valid = true;
5cd6d0e5
PP
313 struct bt_field_class *src_fc;
314 struct bt_field_class *tgt_fc;
315 struct bt_field_class *prev_fc = NULL;
44c440bc
PP
316 uint64_t src_i = 0, tgt_i = 0;
317
318 if (src_field_path->root != tgt_field_path->root) {
319 goto end;
320 }
321
5cd6d0e5
PP
322 src_fc = borrow_root_field_class(ctx, src_field_path->root);
323 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
324 BT_ASSERT(src_fc);
325 BT_ASSERT(tgt_fc);
44c440bc
PP
326
327 while (src_i < src_field_path->indexes->len &&
328 tgt_i < tgt_field_path->indexes->len) {
329 bool advance;
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);
334
5cd6d0e5
PP
335 if (src_fc != tgt_fc) {
336 if (!prev_fc) {
44c440bc
PP
337 /*
338 * This is correct: the LCA is the root
5cd6d0e5
PP
339 * scope field classe, which must be a
340 * structure field classe.
44c440bc
PP
341 */
342 break;
343 }
344
864cad70 345 if (prev_fc->type != BT_FIELD_CLASS_TYPE_STRUCTURE) {
44c440bc
PP
346 is_valid = false;
347 }
348
349 break;
350 }
351
5cd6d0e5
PP
352 prev_fc = src_fc;
353 src_fc = borrow_child_field_class(src_fc, src_index, &advance);
44c440bc
PP
354
355 if (advance) {
356 src_i++;
357 }
358
5cd6d0e5 359 tgt_fc = borrow_child_field_class(tgt_fc, tgt_index, &advance);
44c440bc
PP
360
361 if (advance) {
362 tgt_i++;
363 }
364 }
365
366end:
367 return is_valid;
368}
369
370BT_ASSERT_PRE_FUNC
371static inline
5cd6d0e5 372bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path,
44c440bc
PP
373 struct bt_field_path *tgt_field_path,
374 struct bt_resolve_field_path_context *ctx)
375{
376 bool is_valid = true;
5cd6d0e5
PP
377 struct bt_field_class *src_fc;
378 struct bt_field_class *tgt_fc;
44c440bc
PP
379 uint64_t src_i = 0, tgt_i = 0;
380
381 if (src_field_path->root != tgt_field_path->root) {
382 goto end;
383 }
384
5cd6d0e5
PP
385 src_fc = borrow_root_field_class(ctx, src_field_path->root);
386 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
387 BT_ASSERT(src_fc);
388 BT_ASSERT(tgt_fc);
389 BT_ASSERT(src_fc == tgt_fc);
44c440bc
PP
390
391 /* Find LCA */
392 while (src_i < src_field_path->indexes->len &&
393 tgt_i < tgt_field_path->indexes->len) {
394 bool advance;
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);
399
400 if (src_i != tgt_i) {
5cd6d0e5 401 /* Next field class is different: LCA is `tgt_fc` */
44c440bc
PP
402 break;
403 }
404
5cd6d0e5 405 src_fc = borrow_child_field_class(src_fc, src_index, &advance);
44c440bc
PP
406
407 if (advance) {
408 src_i++;
409 }
410
5cd6d0e5 411 tgt_fc = borrow_child_field_class(tgt_fc, tgt_index, &advance);
44c440bc
PP
412
413 if (advance) {
414 tgt_i++;
415 }
416 }
417
5cd6d0e5 418 /* Only structure field classes to the target */
44c440bc
PP
419 while (tgt_i < tgt_field_path->indexes->len) {
420 bool advance;
421 uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
422 tgt_field_path, tgt_i);
423
864cad70
PP
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) {
44c440bc
PP
427 is_valid = false;
428 goto end;
429 }
430
5cd6d0e5 431 tgt_fc = borrow_child_field_class(tgt_fc, tgt_index, &advance);
44c440bc
PP
432
433 if (advance) {
434 tgt_i++;
435 }
436 }
437
438end:
439 return is_valid;
440}
441
442BT_ASSERT_PRE_FUNC
443static inline
5cd6d0e5
PP
444bool field_path_is_valid(struct bt_field_class *src_fc,
445 struct bt_field_class *tgt_fc,
44c440bc
PP
446 struct bt_resolve_field_path_context *ctx)
447{
448 bool is_valid = true;
5cd6d0e5
PP
449 struct bt_field_path *src_field_path = find_field_class_in_ctx(
450 src_fc, ctx);
451 struct bt_field_path *tgt_field_path = find_field_class_in_ctx(
452 tgt_fc, ctx);
44c440bc
PP
453
454 if (!src_field_path) {
5cd6d0e5
PP
455 BT_ASSERT_PRE_MSG("Cannot find requesting field classe in "
456 "resolving context: %!+F", src_fc);
44c440bc
PP
457 is_valid = false;
458 goto end;
459 }
460
461 if (!tgt_field_path) {
5cd6d0e5
PP
462 BT_ASSERT_PRE_MSG("Cannot find target field classe in "
463 "resolving context: %!+F", tgt_fc);
44c440bc
PP
464 is_valid = false;
465 goto end;
466 }
467
468 /* Target must be before source */
469 if (!target_is_before_source(src_field_path, tgt_field_path)) {
5cd6d0e5
PP
470 BT_ASSERT_PRE_MSG("Target field classe is located after "
471 "requesting field classe: %![req-fc-]+F, %![tgt-fc-]+F",
472 src_fc, tgt_fc);
44c440bc
PP
473 is_valid = false;
474 goto end;
475 }
476
477 /*
478 * If target is in a different scope than source, there are no
5cd6d0e5 479 * array or variant field classes on the way to the target.
44c440bc 480 */
5cd6d0e5 481 if (!target_field_path_in_different_scope_has_struct_fc_only(
44c440bc 482 src_field_path, tgt_field_path, ctx)) {
5cd6d0e5
PP
483 BT_ASSERT_PRE_MSG("Target field classe is located in a "
484 "different scope than requesting field classe, "
485 "but within an array or a variant field classe: "
486 "%![req-fc-]+F, %![tgt-fc-]+F",
487 src_fc, tgt_fc);
44c440bc
PP
488 is_valid = false;
489 goto end;
490 }
491
5cd6d0e5
PP
492 /* Same scope: LCA must be a structure field classe */
493 if (!lca_is_structure_field_class(src_field_path, tgt_field_path, ctx)) {
44c440bc 494 BT_ASSERT_PRE_MSG("Lowest common ancestor of target and "
5cd6d0e5
PP
495 "requesting field classes is not a structure field classe: "
496 "%![req-fc-]+F, %![tgt-fc-]+F",
497 src_fc, tgt_fc);
44c440bc
PP
498 is_valid = false;
499 goto end;
500 }
501
502 /* Same scope: path from LCA to target has no array/variant FTs */
5cd6d0e5 503 if (!lca_to_target_has_struct_fc_only(src_field_path, tgt_field_path,
44c440bc
PP
504 ctx)) {
505 BT_ASSERT_PRE_MSG("Path from lowest common ancestor of target "
5cd6d0e5
PP
506 "and requesting field classes to target field classe "
507 "contains an array or a variant field classe: "
508 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc, tgt_fc);
44c440bc
PP
509 is_valid = false;
510 goto end;
511 }
512
513end:
65300d60
PP
514 bt_object_put_ref(src_field_path);
515 bt_object_put_ref(tgt_field_path);
44c440bc
PP
516 return is_valid;
517}
518
519static
5cd6d0e5
PP
520struct bt_field_path *resolve_field_path(struct bt_field_class *src_fc,
521 struct bt_field_class *tgt_fc,
44c440bc
PP
522 struct bt_resolve_field_path_context *ctx)
523{
5cd6d0e5
PP
524 BT_ASSERT_PRE(field_path_is_valid(src_fc, tgt_fc, ctx),
525 "Invalid target field classe: %![req-fc-]+F, %![tgt-fc-]+F",
526 src_fc, tgt_fc);
527 return find_field_class_in_ctx(tgt_fc, ctx);
44c440bc
PP
528}
529
530BT_HIDDEN
5cd6d0e5 531int bt_resolve_field_paths(struct bt_field_class *fc,
44c440bc
PP
532 struct bt_resolve_field_path_context *ctx)
533{
534 int ret = 0;
535
5cd6d0e5 536 BT_ASSERT(fc);
44c440bc 537
5cd6d0e5 538 /* Resolving part for dynamic array and variant field classes */
864cad70
PP
539 switch (fc->type) {
540 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
44c440bc 541 {
5cd6d0e5 542 struct bt_field_class_dynamic_array *dyn_array_fc = (void *) fc;
44c440bc 543
5cd6d0e5
PP
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) {
44c440bc
PP
549 ret = -1;
550 goto end;
551 }
552 }
553
554 break;
555 }
864cad70 556 case BT_FIELD_CLASS_TYPE_VARIANT:
44c440bc 557 {
5cd6d0e5
PP
558 struct bt_field_class_variant *var_fc = (void *) fc;
559
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) {
44c440bc
PP
566 ret = -1;
567 goto end;
568 }
569 }
570 }
571 default:
572 break;
573 }
574
575 /* Recursive part */
864cad70
PP
576 switch (fc->type) {
577 case BT_FIELD_CLASS_TYPE_STRUCTURE:
578 case BT_FIELD_CLASS_TYPE_VARIANT:
44c440bc 579 {
5cd6d0e5
PP
580 struct bt_field_class_named_field_class_container *container_fc =
581 (void *) fc;
44c440bc
PP
582 uint64_t i;
583
5cd6d0e5
PP
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(
587 container_fc, i);
44c440bc 588
5cd6d0e5 589 ret = bt_resolve_field_paths(named_fc->fc, ctx);
44c440bc
PP
590 if (ret) {
591 goto end;
592 }
593 }
594
595 break;
596 }
864cad70
PP
597 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
598 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
44c440bc 599 {
5cd6d0e5 600 struct bt_field_class_array *array_fc = (void *) fc;
44c440bc 601
5cd6d0e5 602 ret = bt_resolve_field_paths(array_fc->element_fc, ctx);
44c440bc
PP
603 break;
604 }
605 default:
606 break;
607 }
608
609end:
610 return ret;
611}
This page took 0.049211 seconds and 4 git commands to generate.