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