ctf.fs: bt_ctf_notif_iter_create(): assert() that all medops exist
[babeltrace.git] / formats / ctf / ir / resolve.c
CommitLineData
09840de5
PP
1/*
2 * resolve.c
3 *
4 * Babeltrace - CTF IR: Type resolving internal
5 *
6 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
8 *
9 * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 * Philippe Proulx <pproulx@efficios.com>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * SOFTWARE.
29 */
30
31#include <babeltrace/ctf-ir/event.h>
32#include <babeltrace/ctf-ir/stream-class.h>
33#include <babeltrace/ctf-ir/resolve-internal.h>
2e33ac5a 34#include <babeltrace/ctf-ir/field-types.h>
b011f6b0
PP
35#include <babeltrace/ctf-ir/field-path.h>
36#include <babeltrace/ctf-ir/field-path-internal.h>
09840de5
PP
37#include <babeltrace/ctf-ir/event-internal.h>
38#include <babeltrace/ref.h>
39#include <babeltrace/babeltrace-internal.h>
40#include <babeltrace/values.h>
41#include <limits.h>
42#include <glib.h>
43
44#define _printf_error(fmt, args...) \
45 printf_verbose("[resolving] " fmt, ## args)
46
47typedef GPtrArray type_stack;
48
49/*
50 * A stack frame.
51 *
52 * `type` contains a compound field type (structure, variant, array,
53 * or sequence) and `index` indicates the index of the field type in
54 * the upper frame (-1 for array and sequence field types).
55 *
56 * `type` is owned by the stack frame.
57 */
58struct type_stack_frame {
59 struct bt_ctf_field_type *type;
60 int index;
61};
62
63/*
64 * The current context of the resolving engine.
65 *
66 * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2)
67 * in the following order:
68 *
69 * * Packet header
70 * * Packet context
71 * * Event header
72 * * Stream event context
73 * * Event context
74 * * Event payload
75 */
76struct resolve_context {
77 struct bt_value *environment;
78 struct bt_ctf_field_type *scopes[6];
79
46df6b28
PP
80 /* Root scope being visited */
81 enum bt_ctf_scope root_scope;
09840de5
PP
82 type_stack *type_stack;
83 struct bt_ctf_field_type *cur_field_type;
84};
85
86/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
87static const char * const absolute_path_prefixes[] = {
46df6b28
PP
88 [BT_CTF_SCOPE_ENV] = "env.",
89 [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = "trace.packet.header.",
90 [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = "stream.packet.context.",
91 [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = "stream.event.header.",
92 [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = "stream.event.context.",
93 [BT_CTF_SCOPE_EVENT_CONTEXT] = "event.context.",
94 [BT_CTF_SCOPE_EVENT_FIELDS] = "event.fields.",
09840de5
PP
95};
96
97/* Number of path tokens used for the absolute prefixes */
98static const int absolute_path_prefix_ptoken_counts[] = {
46df6b28
PP
99 [BT_CTF_SCOPE_ENV] = 1,
100 [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = 3,
101 [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = 3,
102 [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = 3,
103 [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = 3,
104 [BT_CTF_SCOPE_EVENT_CONTEXT] = 2,
105 [BT_CTF_SCOPE_EVENT_FIELDS] = 2,
09840de5
PP
106};
107
108/*
109 * Destroys a type stack frame.
110 */
111static
112void type_stack_destroy_notify(gpointer data)
113{
114 struct type_stack_frame *frame = data;
115
116 BT_PUT(frame->type);
117 g_free(frame);
118}
119
120/*
121 * Creates a type stack.
122 *
123 * Return value is owned by the caller.
124 */
125static
126type_stack *type_stack_create(void)
127{
128 return g_ptr_array_new_with_free_func(type_stack_destroy_notify);
129}
130
131/*
132 * Destroys a type stack.
133 */
134static
135void type_stack_destroy(type_stack *stack)
136{
137 g_ptr_array_free(stack, TRUE);
138}
139
140/*
141 * Pushes a field type onto a type stack.
142 *
143 * `type` is owned by the caller (stack frame gets a new reference).
144 */
145static
146int type_stack_push(type_stack *stack, struct bt_ctf_field_type *type)
147{
148 int ret = 0;
149 struct type_stack_frame *frame = NULL;
150
151 if (!stack || !type) {
152 ret = -1;
153 goto end;
154 }
155
156 frame = g_new0(struct type_stack_frame, 1);
157 if (!frame) {
158 ret = -1;
159 goto end;
160 }
161
162 frame->type = bt_get(type);
163 g_ptr_array_add(stack, frame);
164
165end:
166 return ret;
167}
168
169/*
170 * Checks whether or not `stack` is empty.
171 */
172static
173bool type_stack_empty(type_stack *stack)
174{
175 return stack->len == 0;
176}
177
178/*
179 * Returns the number of frames in `stack`.
180 */
181static
182size_t type_stack_size(type_stack *stack)
183{
184 return stack->len;
185}
186
187/*
188 * Returns the top frame of `stack`.
189 *
190 * Return value is owned by `stack`.
191 */
192static
193struct type_stack_frame *type_stack_peek(type_stack *stack)
194{
195 struct type_stack_frame *entry = NULL;
196
197 if (!stack || type_stack_empty(stack)) {
198 goto end;
199 }
200
201 entry = g_ptr_array_index(stack, stack->len - 1);
202end:
203 return entry;
204}
205
206/*
207 * Returns the frame at index `index` in `stack`.
208 *
209 * Return value is owned by `stack`.
210 */
211static
212struct type_stack_frame *type_stack_at(type_stack *stack,
213 size_t index)
214{
215 struct type_stack_frame *entry = NULL;
216
217 if (!stack || index >= stack->len) {
218 goto end;
219 }
220
221 entry = g_ptr_array_index(stack, index);
222
223end:
224 return entry;
225}
226
227/*
228 * Removes the top frame of `stack`.
229 */
230static
231void type_stack_pop(type_stack *stack)
232{
233 if (!type_stack_empty(stack)) {
234 /*
235 * This will call the frame's destructor and free it, as
236 * well as put its contained field type.
237 */
238 g_ptr_array_set_size(stack, stack->len - 1);
239 }
240}
241
242/*
243 * Returns the scope field type of `scope` in the context `ctx`.
244 *
245 * Return value is owned by `ctx` on success.
246 */
247static
248struct bt_ctf_field_type *get_type_from_ctx(struct resolve_context *ctx,
46df6b28 249 enum bt_ctf_scope scope)
09840de5 250{
46df6b28
PP
251 assert(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER &&
252 scope <= BT_CTF_SCOPE_EVENT_FIELDS);
09840de5 253
46df6b28 254 return ctx->scopes[scope - BT_CTF_SCOPE_TRACE_PACKET_HEADER];
09840de5
PP
255}
256
257/*
258 * Returns the CTF scope from a path string. May return
259 * CTF_NODE_UNKNOWN if the path is found to be relative.
260 */
261static
46df6b28 262enum bt_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
09840de5 263{
46df6b28
PP
264 enum bt_ctf_scope scope;
265 enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN;
09840de5
PP
266 const size_t prefixes_count = sizeof(absolute_path_prefixes) /
267 sizeof(*absolute_path_prefixes);
268
46df6b28
PP
269 for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_SCOPE_ENV +
270 prefixes_count; scope++) {
09840de5
PP
271 /*
272 * Chech if path string starts with a known absolute
273 * path prefix.
274 *
275 * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
276 */
46df6b28
PP
277 if (strncmp(pathstr, absolute_path_prefixes[scope],
278 strlen(absolute_path_prefixes[scope]))) {
09840de5
PP
279 /* Prefix does not match: try the next one */
280 continue;
281 }
282
283 /* Found it! */
46df6b28 284 ret = scope;
09840de5
PP
285 goto end;
286 }
287
288end:
289 return ret;
290}
291
292/*
293 * Destroys a path token.
294 */
295static
296void ptokens_destroy_func(gpointer ptoken, gpointer data)
297{
298 g_string_free(ptoken, TRUE);
299}
300
301/*
302 * Destroys a path token list.
303 */
304static
305void ptokens_destroy(GList *ptokens)
306{
307 if (!ptokens) {
308 return;
309 }
310
311 g_list_foreach(ptokens, ptokens_destroy_func, NULL);
312 g_list_free(ptokens);
313}
314
315/*
316 * Returns the string contained in a path token.
317 */
318static
319const char *ptoken_get_string(GList *ptoken)
320{
321 GString *tokenstr = (GString *) ptoken->data;
322
323 return tokenstr->str;
324}
325
326/*
327 * Converts a path string to a path token list, that is, splits the
328 * individual words of a path string into a list of individual
329 * strings.
330 *
331 * Return value is owned by the caller on success.
332 */
333static
334GList *pathstr_to_ptokens(const char *pathstr)
335{
336 const char *at = pathstr;
337 const char *last = at;
338 GList *ptokens = NULL;
339
340 for (;;) {
341 if (*at == '.' || *at == '\0') {
342 GString *tokenstr;
343
344 if (at == last) {
345 /* Error: empty token */
346 _printf_error("Empty token in path string at position %d\n",
347 (int) (at - pathstr));
348 goto error;
349 }
350
351 tokenstr = g_string_new(NULL);
352 g_string_append_len(tokenstr, last, at - last);
353 ptokens = g_list_append(ptokens, tokenstr);
354 last = at + 1;
355 }
356
357 if (*at == '\0') {
358 break;
359 }
360
361 at++;
362 }
363
364 return ptokens;
365
366error:
367 ptokens_destroy(ptokens);
368 return NULL;
369}
370
371/*
372 * Converts a path token list to a field path object. The path token
373 * list is relative from `type`. The index of the source looking for
374 * its target within `type` is indicated by `src_index`. This can be
375 * `INT_MAX` if the source is contained in `type`.
376 *
377 * `ptokens` is owned by the caller. `field_path` is an output parameter
378 * owned by the caller that must be filled here. `type` is owned by the
379 * caller.
380 */
381static
382int ptokens_to_field_path(GList *ptokens, struct bt_ctf_field_path *field_path,
383 struct bt_ctf_field_type *type, int src_index)
384{
385 int ret = 0;
386 GList *cur_ptoken = ptokens;
387 bool first_level_done = false;
388
389 /* Get our own reference */
390 bt_get(type);
391
392 /* Locate target */
393 while (cur_ptoken) {
394 int child_index;
395 struct bt_ctf_field_type *child_type;
396 const char *field_name = ptoken_get_string(cur_ptoken);
397 enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
398
399 /* Find to which index corresponds the current path token */
400 if (type_id == CTF_TYPE_ARRAY || type_id == CTF_TYPE_SEQUENCE) {
401 child_index = -1;
402 } else {
403 child_index = bt_ctf_field_type_get_field_index(type,
404 field_name);
405 if (child_index < 0) {
406 /*
407 * Error: field name does not exist or
408 * wrong current type.
409 */
410 _printf_error("Cannot get index of field type named \"%s\"\n",
411 field_name);
412 ret = -1;
413 goto end;
414 } else if (child_index > src_index &&
415 !first_level_done) {
416 _printf_error("Child type is located after source index (%d)\n",
417 src_index);
418 ret = -1;
419 goto end;
420 }
421
422 /* Next path token */
423 cur_ptoken = g_list_next(cur_ptoken);
424 first_level_done = true;
425 }
426
427 /* Create new field path entry */
b011f6b0 428 g_array_append_val(field_path->indexes, child_index);
09840de5
PP
429
430 /* Get child field type */
431 child_type = bt_ctf_field_type_get_field_at_index(type,
432 child_index);
433 if (!child_type) {
434 _printf_error("Cannot get child type at index %d (field \"%s\")\n",
435 child_index, field_name);
436 ret = -1;
437 goto end;
438 }
439
440 /* Move child type to current type */
441 BT_MOVE(type, child_type);
442 }
443
444end:
445 bt_put(type);
446 return ret;
447}
448
449/*
450 * Converts a known absolute path token list to a field path object
451 * within the resolving context `ctx`.
452 *
453 * `ptokens` is owned by the caller. `field_path` is an output parameter
454 * owned by the caller that must be filled here.
455 */
456static
457int absolute_ptokens_to_field_path(GList *ptokens,
458 struct bt_ctf_field_path *field_path,
459 struct resolve_context *ctx)
460{
461 int ret = 0;
462 GList *cur_ptoken;
463 struct bt_ctf_field_type *type;
464
465 /* Skip absolute path tokens */
466 cur_ptoken = g_list_nth(ptokens,
467 absolute_path_prefix_ptoken_counts[field_path->root]);
468
469 /* Start with root type */
470 type = get_type_from_ctx(ctx, field_path->root);
471 if (!type) {
472 /* Error: root type is not available */
46df6b28 473 _printf_error("Root type with scope type %d is not available\n",
09840de5
PP
474 field_path->root);
475 ret = -1;
476 goto end;
477 }
478
479 /* Locate target */
480 ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX);
481
482end:
483 return ret;
484}
485
486/*
487 * Converts a known relative path token list to a field path object
488 * within the resolving context `ctx`.
489 *
490 * `ptokens` is owned by the caller. `field_path` is an output parameter
491 * owned by the caller that must be filled here.
492 */
493static
494int relative_ptokens_to_field_path(GList *ptokens,
495 struct bt_ctf_field_path *field_path,
496 struct resolve_context *ctx)
497{
498 int ret = 0;
499 int parent_pos_in_stack;
500 struct bt_ctf_field_path *tail_field_path = bt_ctf_field_path_create();
501
502 if (!tail_field_path) {
503 _printf_error("Cannot create field path\n");
504 ret = -1;
505 goto end;
506 }
507
508 parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1;
509
510 while (parent_pos_in_stack >= 0) {
511 struct bt_ctf_field_type *parent_type =
512 type_stack_at(ctx->type_stack,
513 parent_pos_in_stack)->type;
514 int cur_index = type_stack_at(ctx->type_stack,
515 parent_pos_in_stack)->index;
516
517 /* Locate target from current parent type */
518 ret = ptokens_to_field_path(ptokens, tail_field_path,
519 parent_type, cur_index);
520 if (ret) {
521 /* Not found... yet */
522 bt_ctf_field_path_clear(tail_field_path);
523 } else {
524 /* Found: stitch tail field path to head field path */
525 int i = 0;
526 int tail_field_path_len =
b011f6b0 527 tail_field_path->indexes->len;
09840de5
PP
528
529 while (true) {
530 struct bt_ctf_field_type *cur_type =
531 type_stack_at(ctx->type_stack, i)->type;
532 int index = type_stack_at(
533 ctx->type_stack, i)->index;
534
535 if (cur_type == parent_type) {
536 break;
537 }
538
b011f6b0 539 g_array_append_val(field_path->indexes,
09840de5
PP
540 index);
541 i++;
542 }
543
544 for (i = 0; i < tail_field_path_len; i++) {
545 int index = g_array_index(
b011f6b0 546 tail_field_path->indexes,
09840de5
PP
547 int, i);
548
b011f6b0 549 g_array_append_val(field_path->indexes,
09840de5
PP
550 index);
551 }
552 break;
553 }
554
555 parent_pos_in_stack--;
556 }
557
558 if (parent_pos_in_stack < 0) {
559 /* Not found: look in previous scopes */
560 field_path->root--;
561
46df6b28 562 while (field_path->root >= BT_CTF_SCOPE_TRACE_PACKET_HEADER) {
09840de5
PP
563 struct bt_ctf_field_type *root_type;
564 bt_ctf_field_path_clear(field_path);
565
566 root_type = get_type_from_ctx(ctx, field_path->root);
567 if (!root_type) {
568 field_path->root--;
569 continue;
570 }
571
572 /* Locate target in previous scope */
573 ret = ptokens_to_field_path(ptokens, field_path,
574 root_type, INT_MAX);
575 if (ret) {
576 /* Not found yet */
577 field_path->root--;
578 continue;
579 }
580
581 /* Found */
582 break;
583 }
584 }
585
586end:
b011f6b0 587 BT_PUT(tail_field_path);
09840de5
PP
588 return ret;
589}
590
591/*
592 * Converts a path string to a field path object within the resolving
593 * context `ctx`.
594 *
595 * Return value is owned by the caller on success.
596 */
597static
598struct bt_ctf_field_path *pathstr_to_field_path(const char *pathstr,
599 struct resolve_context *ctx)
600{
601 int ret;
46df6b28 602 enum bt_ctf_scope root_scope;
09840de5
PP
603 GList *ptokens = NULL;
604 struct bt_ctf_field_path *field_path = NULL;
605
606 /* Create field path */
607 field_path = bt_ctf_field_path_create();
608 if (!field_path) {
609 _printf_error("Cannot create field path\n");
610 ret = -1;
611 goto end;
612 }
613
614 /* Convert path string to path tokens */
615 ptokens = pathstr_to_ptokens(pathstr);
616 if (!ptokens) {
617 _printf_error("Cannot convert path string \"%s\" to path tokens\n",
618 pathstr);
619 ret = -1;
620 goto end;
621 }
622
623 /* Absolute or relative path? */
46df6b28 624 root_scope = get_root_scope_from_absolute_pathstr(pathstr);
09840de5 625
46df6b28
PP
626 if (root_scope == BT_CTF_SCOPE_UNKNOWN) {
627 /* Relative path: start with current root scope */
628 field_path->root = ctx->root_scope;
09840de5
PP
629 ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
630 if (ret) {
631 _printf_error("Cannot get relative field path of path string \"%s\"\n",
632 pathstr);
46df6b28
PP
633 _printf_error(" Starting at root scope %d, finished at root scope %d\n",
634 ctx->root_scope, field_path->root);
09840de5
PP
635 goto end;
636 }
46df6b28 637 } else if (root_scope == BT_CTF_SCOPE_ENV) {
09840de5
PP
638 _printf_error("Sequence field types referring the trace environment are not supported as of this version\n");
639 ret = -1;
640 goto end;
641 } else {
46df6b28
PP
642 /* Absolute path: use found root scope */
643 field_path->root = root_scope;
09840de5
PP
644 ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
645 if (ret) {
646 _printf_error("Cannot get absolute field path of path string \"%s\"\n",
647 pathstr);
46df6b28 648 _printf_error(" Looking in root scope %d\n", root_scope);
09840de5
PP
649 goto end;
650 }
651 }
652
653end:
654 if (ret) {
b011f6b0 655 BT_PUT(field_path);
09840de5
PP
656 }
657
658 ptokens_destroy(ptokens);
659
660 return field_path;
661}
662
663/*
664 * Retrieves a field type by following the field path `field_path` in
665 * the resolving context `ctx`.
666 *
667 * Return value is owned by the caller on success.
668 */
669static
670struct bt_ctf_field_type *field_path_to_field_type(
671 struct bt_ctf_field_path *field_path,
672 struct resolve_context *ctx)
673{
674 int i;
675 struct bt_ctf_field_type *type;
676
677 /* Start with root type */
678 type = get_type_from_ctx(ctx, field_path->root);
679 bt_get(type);
680 if (!type) {
681 /* Error: root type is not available */
46df6b28 682 _printf_error("Root type with scope type %d is not available\n",
09840de5
PP
683 field_path->root);
684 goto error;
685 }
686
687 /* Locate target */
b011f6b0 688 for (i = 0; i < field_path->indexes->len; i++) {
09840de5
PP
689 struct bt_ctf_field_type *child_type;
690 int child_index =
b011f6b0 691 g_array_index(field_path->indexes, int, i);
09840de5
PP
692
693 /* Get child field type */
694 child_type = bt_ctf_field_type_get_field_at_index(type,
695 child_index);
696 if (!child_type) {
697 _printf_error("Cannot get field type field at index %d\n",
698 child_index);
699 goto error;
700 }
701
702 /* Move child type to current type */
703 BT_MOVE(type, child_type);
704 }
705
706 return type;
707
708error:
709 BT_PUT(type);
710 return type;
711}
712
713/*
714 * Returns the equivalent field path object of the context type stack.
715 *
716 * Return value is owned by the caller on success.
717 */
718static
719struct bt_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx)
720{
721 int i;
722 struct bt_ctf_field_path *field_path;
723
724 /* Create field path */
725 field_path = bt_ctf_field_path_create();
726 if (!field_path) {
727 _printf_error("Cannot create field path\n");
728 goto error;
729 }
730
46df6b28 731 field_path->root = ctx->root_scope;
09840de5
PP
732
733 for (i = 0; i < type_stack_size(ctx->type_stack); i++) {
734 struct type_stack_frame *frame;
735
736 frame = type_stack_at(ctx->type_stack, i);
b011f6b0 737 g_array_append_val(field_path->indexes, frame->index);
09840de5
PP
738 }
739
740 return field_path;
741
742error:
b011f6b0
PP
743 BT_PUT(field_path);
744 return field_path;
09840de5
PP
745}
746
747/*
748 * Returns the lowest common ancestor of two field path objects
749 * having the same root scope.
750 *
751 * `field_path1` and `field_path2` are owned by the caller.
752 */
753int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1,
754 struct bt_ctf_field_path *field_path2)
755{
756 int lca_index = 0;
757 int field_path1_len, field_path2_len;
758
759 /*
760 * Start from both roots and find the first mismatch.
761 */
762 assert(field_path1->root == field_path2->root);
b011f6b0
PP
763 field_path1_len = field_path1->indexes->len;
764 field_path2_len = field_path2->indexes->len;
09840de5
PP
765
766 while (true) {
767 int target_index, ctx_index;
768
769 if (lca_index == field_path2_len ||
770 lca_index == field_path1_len) {
771 /*
772 * This means that both field paths never split.
773 * This is invalid because the target cannot be
774 * an ancestor of the source.
775 */
776 _printf_error("In source and target: one is an ancestor of the other\n");
777 lca_index = -1;
778 break;
779 }
780
b011f6b0 781 target_index = g_array_index(field_path1->indexes, int,
09840de5 782 lca_index);
b011f6b0 783 ctx_index = g_array_index(field_path2->indexes, int,
09840de5
PP
784 lca_index);
785
786 if (target_index != ctx_index) {
787 /* LCA index is the previous */
788 break;
789 }
790
791 lca_index++;
792 }
793
794 return lca_index;
795}
796
797/*
798 * Validates a target field path.
799 *
800 * `target_field_path` and `target_type` are owned by the caller.
801 */
802static
803int validate_target_field_path(struct bt_ctf_field_path *target_field_path,
804 struct bt_ctf_field_type *target_type,
805 struct resolve_context *ctx)
806{
807 int ret = 0;
808 struct bt_ctf_field_path *ctx_field_path;
b011f6b0 809 int target_field_path_len = target_field_path->indexes->len;
09840de5
PP
810 int lca_index;
811 int ctx_cur_field_type_id;
812 int target_type_id;
813
814 /* Get context field path */
815 ctx_field_path = get_ctx_stack_field_path(ctx);
816 if (!ctx_field_path) {
817 _printf_error("Cannot get source field path\n");
818 ret = -1;
819 goto end;
820 }
821
822 /*
823 * Make sure the target is not a root.
824 */
825 if (target_field_path_len == 0) {
826 _printf_error("Target field path's length is 0 (targeting the root)\n");
827 ret = -1;
828 goto end;
829 }
830
831 /*
832 * Make sure the root of the target field path is not located
833 * after the context field path's root.
834 */
835 if (target_field_path->root > ctx_field_path->root) {
836 _printf_error("Target is located after source\n");
837 ret = -1;
838 goto end;
839 }
840
841 if (target_field_path->root == ctx_field_path->root) {
842 int target_index, ctx_index;
843
844 /*
845 * Find the index of the lowest common ancestor of both field
846 * paths.
847 */
848 lca_index = get_field_paths_lca_index(target_field_path,
849 ctx_field_path);
850 if (lca_index < 0) {
851 _printf_error("Cannot get least common ancestor\n");
852 ret = -1;
853 goto end;
854 }
855
856 /*
857 * Make sure the target field path is located before the
858 * context field path.
859 */
b011f6b0 860 target_index = g_array_index(target_field_path->indexes,
09840de5 861 int, lca_index);
b011f6b0 862 ctx_index = g_array_index(ctx_field_path->indexes,
09840de5
PP
863 int, lca_index);
864
865 if (target_index >= ctx_index) {
866 _printf_error("Target index (%d) is greater or equal to source index (%d) in LCA\n",
867 target_index, ctx_index);
868 ret = -1;
869 goto end;
870 }
871 }
872
873 /*
874 * Make sure the target type has the right type and properties.
875 */
876 ctx_cur_field_type_id = bt_ctf_field_type_get_type_id(
877 ctx->cur_field_type);
878 target_type_id = bt_ctf_field_type_get_type_id(target_type);
879
880 if (ctx_cur_field_type_id == CTF_TYPE_VARIANT) {
881 if (target_type_id != CTF_TYPE_ENUM) {
882 _printf_error("Variant type's tag field type is not an enumeration\n");
883 ret = -1;
884 goto end;
885 }
886 } else if (ctx_cur_field_type_id == CTF_TYPE_SEQUENCE) {
887 if (target_type_id != CTF_TYPE_INTEGER ||
888 bt_ctf_field_type_integer_get_signed(
889 target_type)) {
890 _printf_error("Sequence type's length field type is not an unsigned integer\n");
891 ret = -1;
892 goto end;
893 }
894 } else {
895 assert(false);
896 }
897
898end:
b011f6b0 899 BT_PUT(ctx_field_path);
09840de5
PP
900 return ret;
901}
902
903/*
904 * Resolves a variant or sequence field type `type`.
905 *
906 * `type` is owned by the caller.
907 */
908static
909int resolve_sequence_or_variant_type(struct bt_ctf_field_type *type,
910 struct resolve_context *ctx)
911{
912 int ret = 0;
913 const char *pathstr;
914 int type_id = bt_ctf_field_type_get_type_id(type);
915 struct bt_ctf_field_path *target_field_path = NULL;
916 struct bt_ctf_field_type *target_type = NULL;
917
918 /* Get path string */
919 switch (type_id) {
920 case CTF_TYPE_SEQUENCE:
921 pathstr =
922 bt_ctf_field_type_sequence_get_length_field_name(type);
923 break;
924 case CTF_TYPE_VARIANT:
925 pathstr =
926 bt_ctf_field_type_variant_get_tag_name(type);
927 break;
928 default:
929 assert(false);
5febb458
JG
930 ret = -1;
931 goto end;
09840de5
PP
932 }
933
934 /* Get target field path out of path string */
935 target_field_path = pathstr_to_field_path(pathstr, ctx);
936 if (!target_field_path) {
937 _printf_error("Cannot get target field path for path string \"%s\"\n",
938 pathstr);
939 ret = -1;
940 goto end;
941 }
942
943 /* Get target field type */
944 target_type = field_path_to_field_type(target_field_path, ctx);
945 if (!target_type) {
946 _printf_error("Cannot get target field type for path string \"%s\"\n",
947 pathstr);
948 ret = -1;
949 goto end;
950 }
951
952 ret = validate_target_field_path(target_field_path, target_type, ctx);
953 if (ret) {
954 _printf_error("Invalid target field path for path string \"%s\"\n",
955 pathstr);
956 goto end;
957 }
958
959 /* Set target field path and target field type */
960 if (type_id == CTF_TYPE_SEQUENCE) {
961 ret = bt_ctf_field_type_sequence_set_length_field_path(
962 type, target_field_path);
963 if (ret) {
964 _printf_error("Cannot set sequence field type's length field path\n");
965 goto end;
966 }
09840de5
PP
967 } else if (type_id == CTF_TYPE_VARIANT) {
968 ret = bt_ctf_field_type_variant_set_tag_field_path(
969 type, target_field_path);
970 if (ret) {
971 _printf_error("Cannot set variant field type's tag field path\n");
972 goto end;
973 }
974
4b5fcb78
PP
975 ret = bt_ctf_field_type_variant_set_tag_field_type(
976 type, target_type);
09840de5
PP
977 if (ret) {
978 _printf_error("Cannot set variant field type's tag field type\n");
979 goto end;
980 }
981 } else {
982 assert(false);
983 }
984
985end:
b011f6b0 986 BT_PUT(target_field_path);
09840de5
PP
987 BT_PUT(target_type);
988 return ret;
989}
990
991/*
992 * Resolves a field type `type`.
993 *
994 * `type` is owned by the caller.
995 */
996static
997int resolve_type(struct bt_ctf_field_type *type, struct resolve_context *ctx)
998{
999 int ret = 0;
1000 int type_id;
1001
1002 if (!type) {
1003 /* Type is not available; still valid */
1004 goto end;
1005 }
1006
1007 type_id = bt_ctf_field_type_get_type_id(type);
1008 ctx->cur_field_type = type;
1009
1010 /* Resolve sequence/variant field type */
1011 switch (type_id) {
1012 case CTF_TYPE_SEQUENCE:
1013 case CTF_TYPE_VARIANT:
1014 ret = resolve_sequence_or_variant_type(type, ctx);
1015 if (ret) {
1016 _printf_error("Cannot resolve sequence or variant field type's length/tag\n");
1017 goto end;
1018 }
1019 break;
1020 default:
1021 break;
1022 }
1023
1024 /* Recurse into compound types */
1025 switch (type_id) {
1026 case CTF_TYPE_STRUCT:
1027 case CTF_TYPE_VARIANT:
1028 case CTF_TYPE_SEQUENCE:
1029 case CTF_TYPE_ARRAY:
1030 {
1031 int field_count, f_index;
1032
1033 ret = type_stack_push(ctx->type_stack, type);
1034 if (ret) {
1035 _printf_error("Cannot push field type on type stack\n");
1036 _printf_error(" Stack size: %zu\n",
1037 type_stack_size(ctx->type_stack));
1038 goto end;
1039 }
1040
1041 field_count = bt_ctf_field_type_get_field_count(type);
1042 if (field_count < 0) {
1043 _printf_error("Cannot get field type field count\n");
1044 ret = field_count;
1045 goto end;
1046 }
1047
1048 for (f_index = 0; f_index < field_count; f_index++) {
1049 struct bt_ctf_field_type *child_type =
1050 bt_ctf_field_type_get_field_at_index(type,
1051 f_index);
1052
1053 if (!child_type) {
1054 _printf_error("Cannot get field type field at index %d/%d\n",
1055 f_index, field_count);
1056 ret = -1;
1057 goto end;
1058 }
1059
1060 if (type_id == CTF_TYPE_ARRAY ||
1061 type_id == CTF_TYPE_SEQUENCE) {
1062 type_stack_peek(ctx->type_stack)->index = -1;
1063 } else {
1064 type_stack_peek(ctx->type_stack)->index =
1065 f_index;
1066 }
1067
1068 ret = resolve_type(child_type, ctx);
1069 BT_PUT(child_type);
1070 if (ret) {
1071 goto end;
1072 }
1073 }
1074
1075 type_stack_pop(ctx->type_stack);
1076 break;
1077 }
1078 default:
1079 break;
1080 }
1081
1082end:
1083 return ret;
1084}
1085
1086/*
1087 * Resolves the root field type corresponding to the scope `root_scope`.
1088 */
1089static
e2d83ebb 1090int resolve_root_type(enum bt_ctf_scope root_scope, struct resolve_context *ctx)
09840de5
PP
1091{
1092 int ret;
1093
1094 assert(type_stack_size(ctx->type_stack) == 0);
46df6b28
PP
1095 ctx->root_scope = root_scope;
1096 ret = resolve_type(get_type_from_ctx(ctx, root_scope), ctx);
1097 ctx->root_scope = BT_CTF_SCOPE_UNKNOWN;
09840de5
PP
1098
1099 return ret;
1100}
1101
1102BT_HIDDEN
1103int bt_ctf_resolve_types(
1104 struct bt_value *environment,
1105 struct bt_ctf_field_type *packet_header_type,
1106 struct bt_ctf_field_type *packet_context_type,
1107 struct bt_ctf_field_type *event_header_type,
1108 struct bt_ctf_field_type *stream_event_ctx_type,
1109 struct bt_ctf_field_type *event_context_type,
1110 struct bt_ctf_field_type *event_payload_type,
1111 enum bt_ctf_resolve_flag flags)
1112{
1113 int ret = 0;
1114 struct resolve_context ctx = {
1115 .environment = environment,
1116 .scopes = {
1117 packet_header_type,
1118 packet_context_type,
1119 event_header_type,
1120 stream_event_ctx_type,
1121 event_context_type,
1122 event_payload_type,
1123 },
46df6b28 1124 .root_scope = BT_CTF_SCOPE_UNKNOWN,
09840de5
PP
1125 };
1126
1127 /* Initialize type stack */
1128 ctx.type_stack = type_stack_create();
1129 if (!ctx.type_stack) {
1130 printf_error("Cannot create type stack\n");
1131 ret = -1;
1132 goto end;
1133 }
1134
1135 /* Resolve packet header type */
1136 if (flags & BT_CTF_RESOLVE_FLAG_PACKET_HEADER) {
46df6b28 1137 ret = resolve_root_type(BT_CTF_SCOPE_TRACE_PACKET_HEADER, &ctx);
09840de5
PP
1138 if (ret) {
1139 _printf_error("Cannot resolve trace packet header type\n");
1140 goto end;
1141 }
1142 }
1143
1144 /* Resolve packet context type */
1145 if (flags & BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT) {
46df6b28 1146 ret = resolve_root_type(BT_CTF_SCOPE_STREAM_PACKET_CONTEXT, &ctx);
09840de5
PP
1147 if (ret) {
1148 _printf_error("Cannot resolve stream packet context type\n");
1149 goto end;
1150 }
1151 }
1152
1153 /* Resolve event header type */
1154 if (flags & BT_CTF_RESOLVE_FLAG_EVENT_HEADER) {
46df6b28 1155 ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_HEADER, &ctx);
09840de5
PP
1156 if (ret) {
1157 _printf_error("Cannot resolve stream event header type\n");
1158 goto end;
1159 }
1160 }
1161
1162 /* Resolve stream event context type */
1163 if (flags & BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) {
46df6b28 1164 ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_CONTEXT, &ctx);
09840de5
PP
1165 if (ret) {
1166 _printf_error("Cannot resolve stream event context type\n");
1167 goto end;
1168 }
1169 }
1170
1171 /* Resolve event context type */
1172 if (flags & BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT) {
46df6b28 1173 ret = resolve_root_type(BT_CTF_SCOPE_EVENT_CONTEXT, &ctx);
09840de5
PP
1174 if (ret) {
1175 _printf_error("Cannot resolve event context type\n");
1176 goto end;
1177 }
1178 }
1179
1180 /* Resolve event payload type */
1181 if (flags & BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) {
46df6b28 1182 ret = resolve_root_type(BT_CTF_SCOPE_EVENT_FIELDS, &ctx);
09840de5
PP
1183 if (ret) {
1184 _printf_error("Cannot resolve event payload type\n");
1185 goto end;
1186 }
1187 }
1188
1189end:
1190 type_stack_destroy(ctx.type_stack);
1191
1192 return ret;
1193}
This page took 0.072889 seconds and 4 git commands to generate.