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