lib: add option field class and field types
[babeltrace.git] / src / lib / trace-ir / resolve-field-path.c
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 "LIB/RESOLVE-FIELD-PATH"
24 #include "lib/logging.h"
25
26 #include "lib/assert-pre.h"
27 #include "common/assert.h"
28 #include <babeltrace2/trace-ir/field-path-const.h>
29 #include <limits.h>
30 #include <stdint.h>
31 #include <inttypes.h>
32 #include <glib.h>
33
34 #include "field-class.h"
35 #include "field-path.h"
36 #include "resolve-field-path.h"
37
38 static
39 bool find_field_class_recursive(struct bt_field_class *fc,
40 struct bt_field_class *tgt_fc, struct bt_field_path *field_path)
41 {
42 bool found = false;
43
44 if (tgt_fc == fc) {
45 found = true;
46 goto end;
47 }
48
49 switch (fc->type) {
50 case BT_FIELD_CLASS_TYPE_OPTION:
51 {
52 struct bt_field_class_option *opt_fc = (void *) fc;
53
54 struct bt_field_path_item item = {
55 .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT,
56 .index = UINT64_C(-1),
57 };
58
59 bt_field_path_append_item(field_path, &item);
60 found = find_field_class_recursive(opt_fc->content_fc,
61 tgt_fc, field_path);
62 if (found) {
63 goto end;
64 }
65
66 bt_field_path_remove_last_item(field_path);
67 break;
68 }
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:
73 {
74 struct bt_field_class_named_field_class_container *container_fc =
75 (void *) fc;
76 uint64_t i;
77
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,
83 .index = i,
84 };
85
86 bt_field_path_append_item(field_path, &item);
87 found = find_field_class_recursive(named_fc->fc,
88 tgt_fc, field_path);
89 if (found) {
90 goto end;
91 }
92
93 bt_field_path_remove_last_item(field_path);
94 }
95
96 break;
97 }
98 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
99 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
100 {
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),
105 };
106
107 bt_field_path_append_item(field_path, &item);
108 found = find_field_class_recursive(array_fc->element_fc,
109 tgt_fc, field_path);
110 if (found) {
111 goto end;
112 }
113
114 bt_field_path_remove_last_item(field_path);
115 break;
116 }
117 default:
118 break;
119 }
120
121 end:
122 return found;
123 }
124
125 static
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)
129 {
130 int ret = 0;
131 struct bt_field_path *field_path = NULL;
132
133 if (!root_fc) {
134 goto end;
135 }
136
137 field_path = bt_field_path_create();
138 if (!field_path) {
139 ret = -1;
140 goto end;
141 }
142
143 field_path->root = root_scope;
144 if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) {
145 /* Not found here */
146 BT_OBJECT_PUT_REF_AND_RESET(field_path);
147 }
148
149 end:
150 *ret_field_path = field_path;
151 return ret;
152 }
153
154 static
155 struct bt_field_path *find_field_class_in_ctx(struct bt_field_class *fc,
156 struct bt_resolve_field_path_context *ctx)
157 {
158 struct bt_field_path *field_path = NULL;
159 int ret;
160
161 ret = find_field_class(ctx->packet_context, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT,
162 fc, &field_path);
163 if (ret || field_path) {
164 goto end;
165 }
166
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) {
170 goto end;
171 }
172
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) {
176 goto end;
177 }
178
179 ret = find_field_class(ctx->event_payload, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD,
180 fc, &field_path);
181 if (ret || field_path) {
182 goto end;
183 }
184
185 end:
186 return field_path;
187 }
188
189 BT_ASSERT_PRE_DEV_FUNC
190 static inline
191 bool target_is_before_source(struct bt_field_path *src_field_path,
192 struct bt_field_path *tgt_field_path)
193 {
194 bool is_valid = true;
195 uint64_t src_i = 0, tgt_i = 0;
196
197 if (tgt_field_path->root < src_field_path->root) {
198 goto end;
199 }
200
201 if (tgt_field_path->root > src_field_path->root) {
202 is_valid = false;
203 goto end;
204 }
205
206 BT_ASSERT(tgt_field_path->root == src_field_path->root);
207
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);
216
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) {
220 is_valid = false;
221 goto end;
222 }
223 }
224
225 src_i++;
226 tgt_i++;
227 }
228
229 end:
230 return is_valid;
231 }
232
233 BT_ASSERT_PRE_DEV_FUNC
234 static inline
235 struct bt_field_class *borrow_root_field_class(
236 struct bt_resolve_field_path_context *ctx, enum bt_field_path_scope scope)
237 {
238 switch (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;
247 default:
248 abort();
249 }
250
251 return NULL;
252 }
253
254 BT_ASSERT_PRE_DEV_FUNC
255 static inline
256 struct bt_field_class *borrow_child_field_class(
257 struct bt_field_class *parent_fc,
258 struct bt_field_path_item *fp_item)
259 {
260 struct bt_field_class *child_fc = NULL;
261
262 switch (parent_fc->type) {
263 case BT_FIELD_CLASS_TYPE_OPTION:
264 {
265 struct bt_field_class_option *opt_fc = (void *) parent_fc;
266
267 BT_ASSERT(fp_item->type ==
268 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT);
269 child_fc = opt_fc->content_fc;
270 break;
271 }
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:
276 {
277 struct bt_field_class_named_field_class_container *container_fc =
278 (void *) parent_fc;
279 struct bt_named_field_class *named_fc;
280
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;
284 break;
285 }
286 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
287 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
288 {
289 struct bt_field_class_array *array_fc = (void *) parent_fc;
290
291 BT_ASSERT(fp_item->type ==
292 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
293 child_fc = array_fc->element_fc;
294 break;
295 }
296 default:
297 break;
298 }
299
300 return child_fc;
301 }
302
303 BT_ASSERT_PRE_DEV_FUNC
304 static inline
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)
309 {
310 bool is_valid = true;
311 uint64_t i = 0;
312 struct bt_field_class *fc;
313
314 if (src_field_path->root == tgt_field_path->root) {
315 goto end;
316 }
317
318 fc = borrow_root_field_class(ctx, tgt_field_path->root);
319
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(
323 tgt_field_path, i);
324
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) {
331 is_valid = false;
332 goto end;
333 }
334
335 BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX);
336 fc = borrow_child_field_class(fc, fp_item);
337 }
338
339 end:
340 return is_valid;
341 }
342
343 BT_ASSERT_PRE_DEV_FUNC
344 static inline
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)
348 {
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;
354
355 if (src_field_path->root != tgt_field_path->root) {
356 goto end;
357 }
358
359 src_fc = borrow_root_field_class(ctx, src_field_path->root);
360 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
361 BT_ASSERT(src_fc);
362 BT_ASSERT(tgt_fc);
363
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);
372
373 if (src_fc != tgt_fc) {
374 if (!prev_fc) {
375 /*
376 * This is correct: the LCA is the root
377 * scope field class, which must be a
378 * structure field class.
379 */
380 break;
381 }
382
383 if (prev_fc->type != BT_FIELD_CLASS_TYPE_STRUCTURE) {
384 is_valid = false;
385 }
386
387 break;
388 }
389
390 prev_fc = src_fc;
391 src_fc = borrow_child_field_class(src_fc, src_fp_item);
392 tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
393 }
394
395 end:
396 return is_valid;
397 }
398
399 BT_ASSERT_PRE_DEV_FUNC
400 static inline
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)
404 {
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;
409
410 if (src_field_path->root != tgt_field_path->root) {
411 goto end;
412 }
413
414 src_fc = borrow_root_field_class(ctx, src_field_path->root);
415 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
416 BT_ASSERT(src_fc);
417 BT_ASSERT(tgt_fc);
418 BT_ASSERT(src_fc == tgt_fc);
419
420 /* Find LCA */
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);
429
430 if (src_i != tgt_i) {
431 /* Next field class is different: LCA is `tgt_fc` */
432 break;
433 }
434
435 src_fc = borrow_child_field_class(src_fc, src_fp_item);
436 tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
437 }
438
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);
444
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) {
451 is_valid = false;
452 goto end;
453 }
454
455 tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
456 }
457
458 end:
459 return is_valid;
460 }
461
462 BT_ASSERT_PRE_DEV_FUNC
463 static inline
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)
467 {
468 bool is_valid = true;
469 struct bt_field_path *src_field_path = find_field_class_in_ctx(
470 src_fc, ctx);
471 struct bt_field_path *tgt_field_path = find_field_class_in_ctx(
472 tgt_fc, ctx);
473
474 if (!src_field_path) {
475 BT_ASSERT_PRE_DEV_MSG("Cannot find requesting field class in "
476 "resolving context: %!+F", src_fc);
477 is_valid = false;
478 goto end;
479 }
480
481 if (!tgt_field_path) {
482 BT_ASSERT_PRE_DEV_MSG("Cannot find target field class in "
483 "resolving context: %!+F", tgt_fc);
484 is_valid = false;
485 goto end;
486 }
487
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",
492 src_fc, tgt_fc);
493 is_valid = false;
494 goto end;
495 }
496
497 /*
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.
500 */
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",
507 src_fc, tgt_fc);
508 is_valid = false;
509 goto end;
510 }
511
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",
517 src_fc, tgt_fc);
518 is_valid = false;
519 goto end;
520 }
521
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,
524 ctx)) {
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);
529 is_valid = false;
530 goto end;
531 }
532
533 end:
534 bt_object_put_ref(src_field_path);
535 bt_object_put_ref(tgt_field_path);
536 return is_valid;
537 }
538
539 static
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)
543 {
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",
546 src_fc, tgt_fc);
547 return find_field_class_in_ctx(tgt_fc, ctx);
548 }
549
550 BT_HIDDEN
551 int bt_resolve_field_paths(struct bt_field_class *fc,
552 struct bt_resolve_field_path_context *ctx)
553 {
554 int ret = 0;
555
556 BT_ASSERT(fc);
557
558 /* Resolving part for dynamic array and variant field classes */
559 switch (fc->type) {
560 case BT_FIELD_CLASS_TYPE_OPTION:
561 {
562 struct bt_field_class_option *opt_fc = (void *) fc;
563
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) {
569 ret = -1;
570 goto end;
571 }
572 }
573
574 break;
575 }
576 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
577 {
578 struct bt_field_class_array_dynamic *dyn_array_fc = (void *) fc;
579
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) {
585 ret = -1;
586 goto end;
587 }
588 }
589
590 break;
591 }
592 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
593 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
594 {
595 struct bt_field_class_variant_with_selector *var_fc =
596 (void *) fc;
597
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) {
604 ret = -1;
605 goto end;
606 }
607 }
608 }
609 default:
610 break;
611 }
612
613 /* Recursive part */
614 switch (fc->type) {
615 case BT_FIELD_CLASS_TYPE_OPTION:
616 {
617 struct bt_field_class_option *opt_fc = (void *) fc;
618
619 ret = bt_resolve_field_paths(opt_fc->content_fc, ctx);
620 break;
621 }
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:
626 {
627 struct bt_field_class_named_field_class_container *container_fc =
628 (void *) fc;
629 uint64_t i;
630
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];
634
635 ret = bt_resolve_field_paths(named_fc->fc, ctx);
636 if (ret) {
637 goto end;
638 }
639 }
640
641 break;
642 }
643 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
644 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
645 {
646 struct bt_field_class_array *array_fc = (void *) fc;
647
648 ret = bt_resolve_field_paths(array_fc->element_fc, ctx);
649 break;
650 }
651 default:
652 break;
653 }
654
655 end:
656 return ret;
657 }
This page took 0.052237 seconds and 5 git commands to generate.