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