3d4814bc36eed55a2aa70e1716c17cb61e4ab805
[babeltrace.git] / src / lib / trace-ir / resolve-field-path.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
5 */
6
7 #define BT_LOG_TAG "LIB/RESOLVE-FIELD-PATH"
8 #include "lib/logging.h"
9
10 #include "lib/assert-cond.h"
11 #include "common/assert.h"
12 #include <babeltrace2/trace-ir/field-path.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <glib.h>
16
17 #include "field-class.h"
18 #include "field-path.h"
19 #include "resolve-field-path.h"
20 #include "common/common.h"
21
22 static
23 bool find_field_class_recursive(struct bt_field_class *fc,
24 struct bt_field_class *tgt_fc, struct bt_field_path *field_path)
25 {
26 bool found = false;
27
28 if (tgt_fc == fc) {
29 found = true;
30 goto end;
31 }
32
33 if (bt_field_class_type_is(fc->type, BT_FIELD_CLASS_TYPE_OPTION)) {
34 struct bt_field_class_option *opt_fc = (void *) fc;
35 struct bt_field_path_item item = {
36 .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT,
37 .index = UINT64_C(-1),
38 };
39
40 bt_field_path_append_item(field_path, &item);
41 found = find_field_class_recursive(opt_fc->content_fc,
42 tgt_fc, field_path);
43 if (found) {
44 goto end;
45 }
46
47 bt_field_path_remove_last_item(field_path);
48 } else if (fc->type == BT_FIELD_CLASS_TYPE_STRUCTURE ||
49 bt_field_class_type_is(fc->type,
50 BT_FIELD_CLASS_TYPE_VARIANT)) {
51 struct bt_field_class_named_field_class_container *container_fc =
52 (void *) fc;
53 uint64_t i;
54
55 for (i = 0; i < container_fc->named_fcs->len; i++) {
56 struct bt_named_field_class *named_fc =
57 container_fc->named_fcs->pdata[i];
58 struct bt_field_path_item item = {
59 .type = BT_FIELD_PATH_ITEM_TYPE_INDEX,
60 .index = i,
61 };
62
63 bt_field_path_append_item(field_path, &item);
64 found = find_field_class_recursive(named_fc->fc,
65 tgt_fc, field_path);
66 if (found) {
67 goto end;
68 }
69
70 bt_field_path_remove_last_item(field_path);
71 }
72 } else if (bt_field_class_type_is(fc->type, BT_FIELD_CLASS_TYPE_ARRAY)) {
73 struct bt_field_class_array *array_fc = (void *) fc;
74 struct bt_field_path_item item = {
75 .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT,
76 .index = UINT64_C(-1),
77 };
78
79 bt_field_path_append_item(field_path, &item);
80 found = find_field_class_recursive(array_fc->element_fc,
81 tgt_fc, field_path);
82 if (found) {
83 goto end;
84 }
85
86 bt_field_path_remove_last_item(field_path);
87 }
88
89 end:
90 return found;
91 }
92
93 static
94 enum bt_resolve_field_xref_status find_field_class(
95 struct bt_field_class *root_fc,
96 enum bt_field_path_scope root_scope,
97 struct bt_field_class *tgt_fc,
98 struct bt_field_path **ret_field_path)
99 {
100 enum bt_resolve_field_xref_status ret;
101 struct bt_field_path *field_path = NULL;
102
103 if (!root_fc) {
104 ret = BT_RESOLVE_FIELD_XREF_STATUS_OK;
105 goto end;
106 }
107
108 field_path = bt_field_path_create();
109 if (!field_path) {
110 ret = BT_RESOLVE_FIELD_XREF_STATUS_MEMORY_ERROR;
111 goto end;
112 }
113
114 field_path->root = root_scope;
115 if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) {
116 /* Not found here */
117 BT_OBJECT_PUT_REF_AND_RESET(field_path);
118 }
119
120 ret = BT_RESOLVE_FIELD_XREF_STATUS_OK;
121
122 end:
123 *ret_field_path = field_path;
124 return ret;
125 }
126
127 static
128 enum bt_resolve_field_xref_status find_field_class_in_ctx(
129 struct bt_field_class *fc,
130 struct bt_resolve_field_xref_context *ctx,
131 struct bt_field_path **ret_field_path)
132 {
133 enum bt_resolve_field_xref_status ret;
134
135 *ret_field_path = NULL;
136
137 ret = find_field_class(ctx->packet_context,
138 BT_FIELD_PATH_SCOPE_PACKET_CONTEXT, fc, ret_field_path);
139 if (ret != BT_RESOLVE_FIELD_XREF_STATUS_OK || *ret_field_path) {
140 goto end;
141 }
142
143 ret = find_field_class(ctx->event_common_context,
144 BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT, fc, ret_field_path);
145 if (ret != BT_RESOLVE_FIELD_XREF_STATUS_OK || *ret_field_path) {
146 goto end;
147 }
148
149 ret = find_field_class(ctx->event_specific_context,
150 BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT, fc, ret_field_path);
151 if (ret != BT_RESOLVE_FIELD_XREF_STATUS_OK || *ret_field_path) {
152 goto end;
153 }
154
155 ret = find_field_class(ctx->event_payload,
156 BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD, fc, ret_field_path);
157 if (ret != BT_RESOLVE_FIELD_XREF_STATUS_OK || *ret_field_path) {
158 goto end;
159 }
160
161 end:
162 return ret;
163 }
164
165 BT_ASSERT_COND_DEV_FUNC
166 static inline
167 bool target_is_before_source(struct bt_field_path *src_field_path,
168 struct bt_field_path *tgt_field_path)
169 {
170 bool is_valid = true;
171 uint64_t src_i = 0, tgt_i = 0;
172
173 if (tgt_field_path->root < src_field_path->root) {
174 goto end;
175 }
176
177 if (tgt_field_path->root > src_field_path->root) {
178 is_valid = false;
179 goto end;
180 }
181
182 BT_ASSERT(tgt_field_path->root == src_field_path->root);
183
184 for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
185 tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
186 struct bt_field_path_item *src_fp_item =
187 bt_field_path_borrow_item_by_index_inline(
188 src_field_path, src_i);
189 struct bt_field_path_item *tgt_fp_item =
190 bt_field_path_borrow_item_by_index_inline(
191 tgt_field_path, tgt_i);
192
193 if (src_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX &&
194 tgt_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX) {
195 if (tgt_fp_item->index > src_fp_item->index) {
196 is_valid = false;
197 goto end;
198 }
199 }
200
201 src_i++;
202 tgt_i++;
203 }
204
205 end:
206 return is_valid;
207 }
208
209 BT_ASSERT_COND_DEV_FUNC
210 static inline
211 struct bt_field_class *borrow_root_field_class(
212 struct bt_resolve_field_xref_context *ctx,
213 enum bt_field_path_scope scope)
214 {
215 switch (scope) {
216 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
217 return ctx->packet_context;
218 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
219 return ctx->event_common_context;
220 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
221 return ctx->event_specific_context;
222 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
223 return ctx->event_payload;
224 default:
225 bt_common_abort();
226 }
227
228 return NULL;
229 }
230
231 BT_ASSERT_COND_DEV_FUNC
232 static inline
233 struct bt_field_class *borrow_child_field_class(
234 struct bt_field_class *parent_fc,
235 struct bt_field_path_item *fp_item)
236 {
237 struct bt_field_class *child_fc = NULL;
238
239 if (bt_field_class_type_is(parent_fc->type,
240 BT_FIELD_CLASS_TYPE_OPTION)) {
241 struct bt_field_class_option *opt_fc = (void *) parent_fc;
242
243 BT_ASSERT(fp_item->type ==
244 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT);
245 child_fc = opt_fc->content_fc;
246 } else if (parent_fc->type == BT_FIELD_CLASS_TYPE_STRUCTURE ||
247 bt_field_class_type_is(parent_fc->type,
248 BT_FIELD_CLASS_TYPE_VARIANT)) {
249 struct bt_field_class_named_field_class_container *container_fc =
250 (void *) parent_fc;
251 struct bt_named_field_class *named_fc;
252
253 BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX);
254 named_fc = container_fc->named_fcs->pdata[fp_item->index];
255 child_fc = named_fc->fc;
256 } else if (bt_field_class_type_is(parent_fc->type,
257 BT_FIELD_CLASS_TYPE_ARRAY)) {
258 struct bt_field_class_array *array_fc = (void *) parent_fc;
259
260 BT_ASSERT(fp_item->type ==
261 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
262 child_fc = array_fc->element_fc;
263 }
264
265 return child_fc;
266 }
267
268 BT_ASSERT_COND_DEV_FUNC
269 static inline
270 bool target_field_path_in_different_scope_has_struct_fc_only(
271 struct bt_field_path *src_field_path,
272 struct bt_field_path *tgt_field_path,
273 struct bt_resolve_field_xref_context *ctx)
274 {
275 bool is_valid = true;
276 uint64_t i = 0;
277 struct bt_field_class *fc;
278
279 if (src_field_path->root == tgt_field_path->root) {
280 goto end;
281 }
282
283 fc = borrow_root_field_class(ctx, tgt_field_path->root);
284
285 for (i = 0; i < tgt_field_path->items->len; i++) {
286 struct bt_field_path_item *fp_item =
287 bt_field_path_borrow_item_by_index_inline(
288 tgt_field_path, i);
289
290 if (bt_field_class_type_is(fc->type,
291 BT_FIELD_CLASS_TYPE_ARRAY) ||
292 bt_field_class_type_is(fc->type,
293 BT_FIELD_CLASS_TYPE_OPTION) ||
294 bt_field_class_type_is(fc->type,
295 BT_FIELD_CLASS_TYPE_VARIANT)) {
296 is_valid = false;
297 goto end;
298 }
299
300 BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX);
301 fc = borrow_child_field_class(fc, fp_item);
302 }
303
304 end:
305 return is_valid;
306 }
307
308 BT_ASSERT_COND_DEV_FUNC
309 static inline
310 bool lca_is_structure_field_class(struct bt_field_path *src_field_path,
311 struct bt_field_path *tgt_field_path,
312 struct bt_resolve_field_xref_context *ctx)
313 {
314 bool is_valid = true;
315 struct bt_field_class *src_fc;
316 struct bt_field_class *tgt_fc;
317 struct bt_field_class *prev_fc = NULL;
318 uint64_t src_i = 0, tgt_i = 0;
319
320 if (src_field_path->root != tgt_field_path->root) {
321 goto end;
322 }
323
324 src_fc = borrow_root_field_class(ctx, src_field_path->root);
325 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
326 BT_ASSERT(src_fc);
327 BT_ASSERT(tgt_fc);
328
329 for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
330 tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
331 struct bt_field_path_item *src_fp_item =
332 bt_field_path_borrow_item_by_index_inline(
333 src_field_path, src_i);
334 struct bt_field_path_item *tgt_fp_item =
335 bt_field_path_borrow_item_by_index_inline(
336 tgt_field_path, tgt_i);
337
338 if (src_fc != tgt_fc) {
339 if (!prev_fc) {
340 /*
341 * This is correct: the LCA is the root
342 * scope field class, which must be a
343 * structure field class.
344 */
345 break;
346 }
347
348 if (prev_fc->type != BT_FIELD_CLASS_TYPE_STRUCTURE) {
349 is_valid = false;
350 }
351
352 break;
353 }
354
355 prev_fc = src_fc;
356 src_fc = borrow_child_field_class(src_fc, src_fp_item);
357 tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
358 }
359
360 end:
361 return is_valid;
362 }
363
364 BT_ASSERT_COND_DEV_FUNC
365 static inline
366 bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path,
367 struct bt_field_path *tgt_field_path,
368 struct bt_resolve_field_xref_context *ctx)
369 {
370 bool is_valid = true;
371 struct bt_field_class *src_fc;
372 struct bt_field_class *tgt_fc;
373 uint64_t src_i = 0, tgt_i = 0;
374
375 if (src_field_path->root != tgt_field_path->root) {
376 goto end;
377 }
378
379 src_fc = borrow_root_field_class(ctx, src_field_path->root);
380 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
381 BT_ASSERT(src_fc);
382 BT_ASSERT(tgt_fc);
383 BT_ASSERT(src_fc == tgt_fc);
384
385 /* Find LCA */
386 for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
387 tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
388 struct bt_field_path_item *src_fp_item =
389 bt_field_path_borrow_item_by_index_inline(
390 src_field_path, src_i);
391 struct bt_field_path_item *tgt_fp_item =
392 bt_field_path_borrow_item_by_index_inline(
393 tgt_field_path, tgt_i);
394
395 if (src_i != tgt_i) {
396 /* Next field class is different: LCA is `tgt_fc` */
397 break;
398 }
399
400 src_fc = borrow_child_field_class(src_fc, src_fp_item);
401 tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
402 }
403
404 /* Only structure field classes to the target */
405 for (; tgt_i < tgt_field_path->items->len; tgt_i++) {
406 struct bt_field_path_item *tgt_fp_item =
407 bt_field_path_borrow_item_by_index_inline(
408 tgt_field_path, tgt_i);
409
410 if (bt_field_class_type_is(tgt_fc->type,
411 BT_FIELD_CLASS_TYPE_ARRAY) ||
412 bt_field_class_type_is(tgt_fc->type,
413 BT_FIELD_CLASS_TYPE_OPTION) ||
414 bt_field_class_type_is(tgt_fc->type,
415 BT_FIELD_CLASS_TYPE_VARIANT)) {
416 is_valid = false;
417 goto end;
418 }
419
420 tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
421 }
422
423 end:
424 return is_valid;
425 }
426
427 BT_ASSERT_COND_DEV_FUNC
428 static inline
429 bool field_path_is_valid(struct bt_field_class *src_fc,
430 struct bt_field_class *tgt_fc,
431 struct bt_resolve_field_xref_context *ctx)
432 {
433 struct bt_field_path *src_field_path;
434 struct bt_field_path *tgt_field_path = NULL;
435 enum bt_resolve_field_xref_status status;
436 bool is_valid;
437
438 status = find_field_class_in_ctx(src_fc, ctx, &src_field_path);
439 BT_ASSERT(status == BT_RESOLVE_FIELD_XREF_STATUS_OK);
440
441 if (!src_field_path) {
442 BT_ASSERT_COND_DEV_MSG("Cannot find requesting field class in "
443 "resolving context: %!+F", src_fc);
444 is_valid = false;
445 goto end;
446 }
447
448 status = find_field_class_in_ctx(tgt_fc, ctx, &tgt_field_path);
449 BT_ASSERT(status == BT_RESOLVE_FIELD_XREF_STATUS_OK);
450
451 if (!tgt_field_path) {
452 BT_ASSERT_COND_DEV_MSG("Cannot find target field class in "
453 "resolving context: %!+F", tgt_fc);
454 is_valid = false;
455 goto end;
456 }
457
458 /* Target must be before source */
459 if (!target_is_before_source(src_field_path, tgt_field_path)) {
460 BT_ASSERT_COND_DEV_MSG("Target field class is located after "
461 "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
462 src_fc, tgt_fc);
463 is_valid = false;
464 goto end;
465 }
466
467 /*
468 * If target is in a different scope than source, there are no
469 * array or variant field classes on the way to the target.
470 */
471 if (!target_field_path_in_different_scope_has_struct_fc_only(
472 src_field_path, tgt_field_path, ctx)) {
473 BT_ASSERT_COND_DEV_MSG("Target field class is located in a "
474 "different scope than requesting field class, "
475 "but within an array or a variant field class: "
476 "%![req-fc-]+F, %![tgt-fc-]+F",
477 src_fc, tgt_fc);
478 is_valid = false;
479 goto end;
480 }
481
482 /* Same scope: LCA must be a structure field class */
483 if (!lca_is_structure_field_class(src_field_path, tgt_field_path, ctx)) {
484 BT_ASSERT_COND_DEV_MSG("Lowest common ancestor of target and "
485 "requesting field classes is not a structure field class: "
486 "%![req-fc-]+F, %![tgt-fc-]+F",
487 src_fc, tgt_fc);
488 is_valid = false;
489 goto end;
490 }
491
492 /* Same scope: path from LCA to target has no array/variant FTs */
493 if (!lca_to_target_has_struct_fc_only(src_field_path, tgt_field_path,
494 ctx)) {
495 BT_ASSERT_COND_DEV_MSG("Path from lowest common ancestor of target "
496 "and requesting field classes to target field class "
497 "contains an array or a variant field class: "
498 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc, tgt_fc);
499 is_valid = false;
500 goto end;
501 }
502
503 is_valid = true;
504
505 end:
506 bt_object_put_ref(src_field_path);
507 bt_object_put_ref(tgt_field_path);
508 return is_valid;
509 }
510
511 static
512 enum bt_resolve_field_xref_status resolve_field_path(
513 struct bt_field_class *src_fc,
514 struct bt_field_class *tgt_fc,
515 struct bt_resolve_field_xref_context *ctx,
516 const char *api_func,
517 struct bt_field_path **ret_field_path)
518 {
519 BT_ASSERT_PRE_DEV_FROM_FUNC(api_func, "valid-field-class",
520 field_path_is_valid(src_fc, tgt_fc, ctx),
521 "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
522 src_fc, tgt_fc);
523 return find_field_class_in_ctx(tgt_fc, ctx, ret_field_path);
524 }
525
526 enum bt_resolve_field_xref_status bt_resolve_field_paths(
527 struct bt_field_class *fc,
528 struct bt_resolve_field_xref_context *ctx,
529 const char *api_func)
530 {
531 enum bt_resolve_field_xref_status status;
532
533 BT_ASSERT(fc);
534
535 /* Resolving part for dynamic array and variant field classes */
536 if (bt_field_class_type_is(fc->type,
537 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD)) {
538 struct bt_field_class_option_with_selector_field *opt_fc = (void *) fc;
539
540 if (opt_fc->selector_field_xref_kind == FIELD_XREF_KIND_PATH) {
541 BT_ASSERT(opt_fc->selector_field.path.class);
542 BT_ASSERT(!opt_fc->selector_field.path.path);
543 status = resolve_field_path(
544 fc, opt_fc->selector_field.path.class, ctx, __func__,
545 &opt_fc->selector_field.path.path);
546 if (status != BT_RESOLVE_FIELD_XREF_STATUS_OK) {
547 goto end;
548 }
549 }
550 } else if (fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) {
551 struct bt_field_class_array_dynamic *dyn_array_fc = (void *) fc;
552
553 if (dyn_array_fc->length_field.xref_kind == FIELD_XREF_KIND_PATH) {
554 BT_ASSERT(dyn_array_fc->length_field.path.class);
555 BT_ASSERT(!dyn_array_fc->length_field.path.path);
556 status = resolve_field_path(
557 fc, dyn_array_fc->length_field.path.class, ctx, __func__,
558 &dyn_array_fc->length_field.path.path);
559 if (status != BT_RESOLVE_FIELD_XREF_STATUS_OK) {
560 goto end;
561 }
562 }
563 } else if (bt_field_class_type_is(fc->type,
564 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) {
565 struct bt_field_class_variant_with_selector_field *var_fc =
566 (void *) fc;
567
568 if (var_fc->selector_field_xref_kind == FIELD_XREF_KIND_PATH) {
569 BT_ASSERT(var_fc->selector_field.path.class);
570 BT_ASSERT(!var_fc->selector_field.path.path);
571 status = resolve_field_path(fc,
572 (void *) var_fc->selector_field.path.class, ctx,
573 __func__, &var_fc->selector_field.path.path);
574 if (status != BT_RESOLVE_FIELD_XREF_STATUS_OK) {
575 goto end;
576 }
577 }
578 }
579
580 /* Recursive part */
581 if (bt_field_class_type_is(fc->type, BT_FIELD_CLASS_TYPE_OPTION)) {
582 struct bt_field_class_option *opt_fc = (void *) fc;
583
584 status = bt_resolve_field_paths(opt_fc->content_fc, ctx, api_func);
585 if (status != BT_RESOLVE_FIELD_XREF_STATUS_OK) {
586 goto end;
587 }
588 } else if (fc->type == BT_FIELD_CLASS_TYPE_STRUCTURE ||
589 bt_field_class_type_is(fc->type,
590 BT_FIELD_CLASS_TYPE_VARIANT)) {
591 struct bt_field_class_named_field_class_container *container_fc =
592 (void *) fc;
593 uint64_t i;
594
595 for (i = 0; i < container_fc->named_fcs->len; i++) {
596 struct bt_named_field_class *named_fc =
597 container_fc->named_fcs->pdata[i];
598
599 status = bt_resolve_field_paths(named_fc->fc, ctx,
600 api_func);
601 if (status != BT_RESOLVE_FIELD_XREF_STATUS_OK) {
602 goto end;
603 }
604 }
605 } else if (bt_field_class_type_is(fc->type,
606 BT_FIELD_CLASS_TYPE_ARRAY)) {
607 struct bt_field_class_array *array_fc = (void *) fc;
608
609 status = bt_resolve_field_paths(array_fc->element_fc, ctx,
610 api_func);
611 if (status != BT_RESOLVE_FIELD_XREF_STATUS_OK) {
612 goto end;
613 }
614 }
615
616 status = BT_RESOLVE_FIELD_XREF_STATUS_OK;
617
618 end:
619 return status;
620 }
This page took 0.041564 seconds and 5 git commands to generate.