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