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