9f0026c7bd1574fc8cf22506da25ccf0700e45b2
[babeltrace.git] / plugins / ctf / fs-sink / translate-trace-ir-to-ctf-ir.c
1 /*
2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRANSLATE-TRACE-IR-TO-CTF-IR"
24 #include "logging.h"
25
26 #include <babeltrace/babeltrace.h>
27 #include <babeltrace/babeltrace-internal.h>
28 #include <babeltrace/common-internal.h>
29 #include <babeltrace/assert-internal.h>
30 #include <stdio.h>
31 #include <stdbool.h>
32 #include <string.h>
33 #include <glib.h>
34
35 #include "fs-sink-ctf-meta.h"
36
37 struct field_path_elem {
38 uint64_t index_in_parent;
39 GString *name;
40
41 /* Weak */
42 const bt_field_class *ir_fc;
43
44 /* Weak */
45 struct fs_sink_ctf_field_class *parent_fc;
46 };
47
48 struct ctx {
49 /* Weak */
50 struct fs_sink_ctf_stream_class *cur_sc;
51
52 /* Weak */
53 struct fs_sink_ctf_event_class *cur_ec;
54
55 bt_scope cur_scope;
56
57 /*
58 * Array of `struct field_path_elem` */
59 GArray *cur_path;
60 };
61
62 static inline
63 struct field_path_elem *cur_path_stack_at(struct ctx *ctx, uint64_t i)
64 {
65 BT_ASSERT(i < ctx->cur_path->len);
66 return &g_array_index(ctx->cur_path, struct field_path_elem, i);
67 }
68
69 static inline
70 struct field_path_elem *cur_path_stack_top(struct ctx *ctx)
71 {
72 BT_ASSERT(ctx->cur_path->len > 0);
73 return cur_path_stack_at(ctx, ctx->cur_path->len - 1);
74 }
75
76 static inline
77 bool is_reserved_member_name(const char *name, const char *reserved_name)
78 {
79 bool is_reserved = false;
80
81 if (strcmp(name, reserved_name) == 0) {
82 is_reserved = true;
83 goto end;
84 }
85
86 if (name[0] == '_' && strcmp(&name[1], reserved_name) == 0) {
87 is_reserved = true;
88 goto end;
89 }
90
91 end:
92 return is_reserved;
93 }
94
95 static inline
96 int cur_path_stack_push(struct ctx *ctx,
97 uint64_t index_in_parent, const char *ir_name,
98 const bt_field_class *ir_fc,
99 struct fs_sink_ctf_field_class *parent_fc)
100 {
101 int ret = 0;
102 struct field_path_elem *field_path_elem;
103
104 g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1);
105 field_path_elem = cur_path_stack_top(ctx);
106 field_path_elem->index_in_parent = index_in_parent;
107 field_path_elem->name = g_string_new(ir_name);
108
109 if (ir_name) {
110 if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) {
111 if (is_reserved_member_name(ir_name, "packet_size") ||
112 is_reserved_member_name(ir_name, "content_size") ||
113 is_reserved_member_name(ir_name, "timestamp_begin") ||
114 is_reserved_member_name(ir_name, "timestamp_end") ||
115 is_reserved_member_name(ir_name, "events_discarded") ||
116 is_reserved_member_name(ir_name, "packet_seq_num")) {
117 BT_LOGE("Unsupported reserved TSDL structure field class member "
118 "or variant field class option name: name=\"%s\"",
119 ir_name);
120 ret = -1;
121 goto end;
122 }
123 }
124
125 ret = fs_sink_ctf_protect_name(field_path_elem->name);
126 if (ret) {
127 BT_LOGE("Unsupported non-TSDL structure field class member "
128 "or variant field class option name: name=\"%s\"",
129 ir_name);
130 goto end;
131 }
132 }
133
134 field_path_elem->ir_fc = ir_fc;
135 field_path_elem->parent_fc = parent_fc;
136
137 end:
138 return ret;
139 }
140
141 static inline
142 void cur_path_stack_pop(struct ctx *ctx)
143 {
144 struct field_path_elem *field_path_elem;
145
146 BT_ASSERT(ctx->cur_path->len > 0);
147 field_path_elem = cur_path_stack_top(ctx);
148
149 if (field_path_elem->name) {
150 g_string_free(field_path_elem->name, TRUE);
151 field_path_elem->name = NULL;
152 }
153
154 g_array_set_size(ctx->cur_path, ctx->cur_path->len - 1);
155 }
156
157 static inline
158 struct field_path_elem *get_field_path_elem(
159 GArray *full_field_path, uint64_t i)
160 {
161 return &g_array_index(full_field_path, struct field_path_elem,
162 i);
163 }
164
165
166 /*
167 * Creates a relative field ref (a single name) from IR field path
168 * `tgt_ir_field_path`.
169 *
170 * This function tries to locate the target field class recursively from
171 * the top to the bottom of the context's current path using only the
172 * target field class's own name. This is because many CTF reading tools
173 * do not support a relative field ref with more than one element, for
174 * example `prev_struct.len`.
175 *
176 * Returns a negative value if this resolving operation failed.
177 */
178 static
179 int create_relative_field_ref(struct ctx *ctx,
180 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
181 {
182 int ret = 0;
183 struct fs_sink_ctf_field_class *tgt_fc = NULL;
184 uint64_t i;
185 int64_t si;
186 const char *tgt_fc_name;
187 struct field_path_elem *field_path_elem;
188
189 /* Get target field class's name */
190 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
191 case BT_SCOPE_PACKET_CONTEXT:
192 BT_ASSERT(ctx->cur_sc);
193 tgt_fc = ctx->cur_sc->packet_context_fc;
194 break;
195 case BT_SCOPE_EVENT_COMMON_CONTEXT:
196 BT_ASSERT(ctx->cur_sc);
197 tgt_fc = ctx->cur_sc->event_common_context_fc;
198 break;
199 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
200 BT_ASSERT(ctx->cur_ec);
201 tgt_fc = ctx->cur_ec->spec_context_fc;
202 break;
203 case BT_SCOPE_EVENT_PAYLOAD:
204 BT_ASSERT(ctx->cur_ec);
205 tgt_fc = ctx->cur_ec->payload_fc;
206 break;
207 default:
208 abort();
209 }
210
211 i = 0;
212
213 while (i < bt_field_path_get_index_count(tgt_ir_field_path)) {
214 uint64_t index = bt_field_path_get_index_by_index(
215 tgt_ir_field_path, i);
216 struct fs_sink_ctf_named_field_class *named_fc = NULL;
217
218 BT_ASSERT(tgt_fc);
219
220 switch (tgt_fc->type) {
221 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
222 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
223 (void *) tgt_fc, index);
224 break;
225 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
226 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
227 (void *) tgt_fc, index);
228 break;
229 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
230 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
231 {
232 struct fs_sink_ctf_field_class_array_base *array_base_fc =
233 (void *) tgt_fc;
234
235 tgt_fc = array_base_fc->elem_fc;
236 break;
237 }
238 default:
239 abort();
240 }
241
242 if (named_fc) {
243 tgt_fc = named_fc->fc;
244 tgt_fc_name = named_fc->name->str;
245 i++;
246 }
247 }
248
249 BT_ASSERT(tgt_fc);
250 BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
251 BT_ASSERT(tgt_fc_name);
252
253 /* Find target field class having this name in current context */
254 for (si = ctx->cur_path->len - 1; si >= 0; si--) {
255 struct fs_sink_ctf_field_class *fc;
256 struct fs_sink_ctf_field_class_struct *struct_fc;
257 struct fs_sink_ctf_field_class_variant *var_fc;
258 struct fs_sink_ctf_named_field_class *named_fc;
259 uint64_t len;
260
261 field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
262 fc = field_path_elem->parent_fc;
263 if (!fc) {
264 /* Reached stack's bottom */
265 ret = -1;
266 goto end;
267 }
268
269 switch (fc->type) {
270 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
271 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
272 break;
273 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
274 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
275 continue;
276 default:
277 /* Not supported by TSDL 1.8 */
278 ret = -1;
279 goto end;
280 }
281
282 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
283 struct_fc = (void *) fc;
284 len = struct_fc->members->len;
285 } else {
286 var_fc = (void *) fc;
287 len = var_fc->options->len;
288 }
289
290 for (i = 0; i < len; i++) {
291 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
292 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
293 struct_fc, i);
294 } else {
295 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
296 var_fc, i);
297 }
298
299 if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
300 if (named_fc->fc == tgt_fc) {
301 g_string_assign(tgt_field_ref,
302 tgt_fc_name);
303 } else {
304 /*
305 * Using only the target field
306 * class's name, we're not
307 * reaching the target field
308 * class. This is not supported
309 * by TSDL 1.8.
310 */
311 ret = -1;
312 }
313
314 goto end;
315 }
316 }
317 }
318
319 end:
320 return ret;
321 }
322
323 /*
324 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
325 *
326 * Returns a negative value if this resolving operation failed.
327 */
328 static
329 int create_absolute_field_ref(struct ctx *ctx,
330 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
331 {
332 int ret = 0;
333 struct fs_sink_ctf_field_class *fc = NULL;
334 uint64_t i;
335
336 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
337 case BT_SCOPE_PACKET_CONTEXT:
338 BT_ASSERT(ctx->cur_sc);
339 fc = ctx->cur_sc->packet_context_fc;
340 g_string_assign(tgt_field_ref, "stream.packet.context");
341 break;
342 case BT_SCOPE_EVENT_COMMON_CONTEXT:
343 BT_ASSERT(ctx->cur_sc);
344 fc = ctx->cur_sc->event_common_context_fc;
345 g_string_assign(tgt_field_ref, "stream.event.context");
346 break;
347 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
348 BT_ASSERT(ctx->cur_ec);
349 fc = ctx->cur_ec->spec_context_fc;
350 g_string_assign(tgt_field_ref, "event.context");
351 break;
352 case BT_SCOPE_EVENT_PAYLOAD:
353 BT_ASSERT(ctx->cur_ec);
354 fc = ctx->cur_ec->payload_fc;
355 g_string_assign(tgt_field_ref, "event.fields");
356 break;
357 default:
358 abort();
359 }
360
361 BT_ASSERT(fc);
362
363 for (i = 0; i < bt_field_path_get_index_count(tgt_ir_field_path); i++) {
364 uint64_t index = bt_field_path_get_index_by_index(
365 tgt_ir_field_path, i);
366 struct fs_sink_ctf_named_field_class *named_fc = NULL;
367
368 switch (fc->type) {
369 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
370 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
371 (void *) fc, index);
372 break;
373 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
374 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
375 (void *) fc, index);
376 break;
377 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
378 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
379 /* Not supported by TSDL 1.8 */
380 ret = -1;
381 goto end;
382 default:
383 abort();
384 }
385
386 BT_ASSERT(named_fc);
387 g_string_append_c(tgt_field_ref, '.');
388 g_string_append(tgt_field_ref, named_fc->name->str);
389 fc = named_fc->fc;
390 }
391
392 end:
393 return ret;
394 }
395
396 /*
397 * Resolves a target field class located at `tgt_ir_field_path`, writing
398 * the resolved field ref to `tgt_field_ref` and setting
399 * `*create_before` according to whether or not the target field must be
400 * created immediately before (in which case `tgt_field_ref` is
401 * irrelevant).
402 */
403 static
404 void resolve_field_class(struct ctx *ctx,
405 const bt_field_path *tgt_ir_field_path,
406 GString *tgt_field_ref, bool *create_before)
407 {
408 int ret;
409 bt_scope tgt_scope;
410
411 *create_before = false;
412
413 if (!tgt_ir_field_path) {
414 *create_before = true;
415 goto end;
416 }
417
418 tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
419
420 if (tgt_scope == ctx->cur_scope) {
421 /*
422 * Try, in this order:
423 *
424 * 1. Use a relative path, using only the target field
425 * class's name. This is what is the most commonly
426 * supported by popular CTF reading tools.
427 *
428 * 2. Use an absolute path. This could fail if there's
429 * an array field class from the current root's field
430 * class to the target field class.
431 *
432 * 3. Create the target field class before the
433 * requesting field class (fallback).
434 */
435 ret = create_relative_field_ref(ctx, tgt_ir_field_path,
436 tgt_field_ref);
437 if (ret) {
438 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
439 tgt_field_ref);
440 if (ret) {
441 *create_before = true;
442 ret = 0;
443 goto end;
444 }
445 }
446 } else {
447 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
448 tgt_field_ref);
449
450 /* It must always work in previous scopes */
451 BT_ASSERT(ret == 0);
452 }
453
454 end:
455 return;
456 }
457
458 static
459 int translate_field_class(struct ctx *ctx);
460
461 static inline
462 void append_to_parent_field_class(struct ctx *ctx,
463 struct fs_sink_ctf_field_class *fc)
464 {
465 struct fs_sink_ctf_field_class *parent_fc =
466 cur_path_stack_top(ctx)->parent_fc;
467
468 switch (parent_fc->type) {
469 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
470 fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
471 cur_path_stack_top(ctx)->name->str, fc);
472 break;
473 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
474 fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
475 cur_path_stack_top(ctx)->name->str, fc);
476 break;
477 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
478 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
479 {
480 struct fs_sink_ctf_field_class_array_base *array_base_fc =
481 (void *) parent_fc;
482
483 BT_ASSERT(!array_base_fc->elem_fc);
484 array_base_fc->elem_fc = fc;
485 array_base_fc->base.alignment = fc->alignment;
486 break;
487 }
488 default:
489 abort();
490 }
491 }
492
493 static inline
494 void update_parent_field_class_alignment(struct ctx *ctx,
495 unsigned int alignment)
496 {
497 struct fs_sink_ctf_field_class *parent_fc =
498 cur_path_stack_top(ctx)->parent_fc;
499
500 switch (parent_fc->type) {
501 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
502 fs_sink_ctf_field_class_struct_align_at_least(
503 (void *) parent_fc, alignment);
504 break;
505 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
506 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
507 {
508 struct fs_sink_ctf_field_class_array_base *array_base_fc =
509 (void *) parent_fc;
510
511 array_base_fc->base.alignment = alignment;
512 break;
513 }
514 default:
515 break;
516 }
517 }
518
519 static inline
520 int translate_structure_field_class_members(struct ctx *ctx,
521 struct fs_sink_ctf_field_class_struct *struct_fc,
522 const bt_field_class *ir_fc)
523 {
524 int ret = 0;
525 uint64_t i;
526
527 for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
528 const bt_field_class_structure_member *member;
529 const char *name;
530 const bt_field_class *memb_ir_fc;
531
532 member =
533 bt_field_class_structure_borrow_member_by_index_const(
534 ir_fc, i);
535 name = bt_field_class_structure_member_get_name(member);
536 memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
537 member);
538 ret = cur_path_stack_push(ctx, i, name, memb_ir_fc,
539 (void *) struct_fc);
540 if (ret) {
541 BT_LOGE("Cannot translate structure field class member: "
542 "name=\"%s\"", name);
543 goto end;
544 }
545
546 ret = translate_field_class(ctx);
547 if (ret) {
548 BT_LOGE("Cannot translate structure field class member: "
549 "name=\"%s\"", name);
550 goto end;
551 }
552
553 cur_path_stack_pop(ctx);
554 }
555
556 end:
557 return ret;
558 }
559
560 static inline
561 int translate_structure_field_class(struct ctx *ctx)
562 {
563 int ret;
564 struct fs_sink_ctf_field_class_struct *fc =
565 fs_sink_ctf_field_class_struct_create_empty(
566 cur_path_stack_top(ctx)->ir_fc,
567 cur_path_stack_top(ctx)->index_in_parent);
568
569 BT_ASSERT(fc);
570 append_to_parent_field_class(ctx, (void *) fc);
571 ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
572 if (ret) {
573 goto end;
574 }
575
576 update_parent_field_class_alignment(ctx, fc->base.alignment);
577
578 end:
579 return ret;
580 }
581
582 static inline
583 int translate_variant_field_class(struct ctx *ctx)
584 {
585 int ret = 0;
586 uint64_t i;
587 struct fs_sink_ctf_field_class_variant *fc =
588 fs_sink_ctf_field_class_variant_create_empty(
589 cur_path_stack_top(ctx)->ir_fc,
590 cur_path_stack_top(ctx)->index_in_parent);
591
592 BT_ASSERT(fc);
593
594 /* Resolve tag field class before appending to parent */
595 resolve_field_class(ctx,
596 bt_field_class_variant_borrow_selector_field_path_const(
597 fc->base.ir_fc), fc->tag_ref, &fc->tag_is_before);
598
599 append_to_parent_field_class(ctx, (void *) fc);
600
601 for (i = 0; i < bt_field_class_variant_get_option_count(fc->base.ir_fc);
602 i++) {
603 const bt_field_class_variant_option *opt;
604 const char *name;
605 const bt_field_class *opt_ir_fc;
606
607 opt = bt_field_class_variant_borrow_option_by_index_const(
608 fc->base.ir_fc, i);
609 name = bt_field_class_variant_option_get_name(opt);
610 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
611 opt);
612 ret = cur_path_stack_push(ctx, i, name, opt_ir_fc, (void *) fc);
613 if (ret) {
614 BT_LOGE("Cannot translate variant field class option: "
615 "name=\"%s\"", name);
616 goto end;
617 }
618
619 ret = translate_field_class(ctx);
620 if (ret) {
621 BT_LOGE("Cannot translate variant field class option: "
622 "name=\"%s\"", name);
623 goto end;
624 }
625
626 cur_path_stack_pop(ctx);
627 }
628
629 end:
630 return ret;
631 }
632
633 static inline
634 int translate_static_array_field_class(struct ctx *ctx)
635 {
636 struct fs_sink_ctf_field_class_array *fc =
637 fs_sink_ctf_field_class_array_create_empty(
638 cur_path_stack_top(ctx)->ir_fc,
639 cur_path_stack_top(ctx)->index_in_parent);
640 const bt_field_class *elem_ir_fc =
641 bt_field_class_array_borrow_element_field_class_const(
642 fc->base.base.ir_fc);
643 int ret;
644
645 BT_ASSERT(fc);
646 append_to_parent_field_class(ctx, (void *) fc);
647 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
648 (void *) fc);
649 if (ret) {
650 BT_LOGE_STR("Cannot translate static array field class element.");
651 goto end;
652 }
653
654 ret = translate_field_class(ctx);
655 if (ret) {
656 BT_LOGE_STR("Cannot translate static array field class element.");
657 goto end;
658 }
659
660 cur_path_stack_pop(ctx);
661 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
662
663 end:
664 return ret;
665 }
666
667 static inline
668 int translate_dynamic_array_field_class(struct ctx *ctx)
669 {
670 struct fs_sink_ctf_field_class_sequence *fc =
671 fs_sink_ctf_field_class_sequence_create_empty(
672 cur_path_stack_top(ctx)->ir_fc,
673 cur_path_stack_top(ctx)->index_in_parent);
674 const bt_field_class *elem_ir_fc =
675 bt_field_class_array_borrow_element_field_class_const(
676 fc->base.base.ir_fc);
677 int ret;
678
679 BT_ASSERT(fc);
680
681 /* Resolve length field class before appending to parent */
682 resolve_field_class(ctx,
683 bt_field_class_dynamic_array_borrow_length_field_path_const(
684 fc->base.base.ir_fc),
685 fc->length_ref, &fc->length_is_before);
686
687 append_to_parent_field_class(ctx, (void *) fc);
688 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
689 (void *) fc);
690 if (ret) {
691 BT_LOGE_STR("Cannot translate dynamic array field class element.");
692 goto end;
693 }
694
695 ret = translate_field_class(ctx);
696 if (ret) {
697 BT_LOGE_STR("Cannot translate dynamic array field class element.");
698 goto end;
699 }
700
701 cur_path_stack_pop(ctx);
702 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
703
704 end:
705 return ret;
706 }
707
708 static inline
709 int translate_integer_field_class(struct ctx *ctx)
710 {
711 struct fs_sink_ctf_field_class_int *fc =
712 fs_sink_ctf_field_class_int_create(
713 cur_path_stack_top(ctx)->ir_fc,
714 cur_path_stack_top(ctx)->index_in_parent);
715
716 BT_ASSERT(fc);
717 append_to_parent_field_class(ctx, (void *) fc);
718 return 0;
719 }
720
721 static inline
722 int translate_real_field_class(struct ctx *ctx)
723 {
724 struct fs_sink_ctf_field_class_float *fc =
725 fs_sink_ctf_field_class_float_create(
726 cur_path_stack_top(ctx)->ir_fc,
727 cur_path_stack_top(ctx)->index_in_parent);
728
729 BT_ASSERT(fc);
730 append_to_parent_field_class(ctx, (void *) fc);
731 return 0;
732 }
733
734 static inline
735 int translate_string_field_class(struct ctx *ctx)
736 {
737 struct fs_sink_ctf_field_class_string *fc =
738 fs_sink_ctf_field_class_string_create(
739 cur_path_stack_top(ctx)->ir_fc,
740 cur_path_stack_top(ctx)->index_in_parent);
741
742 BT_ASSERT(fc);
743 append_to_parent_field_class(ctx, (void *) fc);
744 return 0;
745 }
746
747 /*
748 * Translates a field class, recursively.
749 *
750 * The field class's IR field class, parent field class, and index
751 * within its parent are in the context's current path's top element
752 * (cur_path_stack_top()).
753 */
754 static
755 int translate_field_class(struct ctx *ctx)
756 {
757 int ret;
758
759 switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
760 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
761 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
762 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
763 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
764 ret = translate_integer_field_class(ctx);
765 break;
766 case BT_FIELD_CLASS_TYPE_REAL:
767 ret = translate_real_field_class(ctx);
768 break;
769 case BT_FIELD_CLASS_TYPE_STRING:
770 ret = translate_string_field_class(ctx);
771 break;
772 case BT_FIELD_CLASS_TYPE_STRUCTURE:
773 ret = translate_structure_field_class(ctx);
774 break;
775 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
776 ret = translate_static_array_field_class(ctx);
777 break;
778 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
779 ret = translate_dynamic_array_field_class(ctx);
780 break;
781 case BT_FIELD_CLASS_TYPE_VARIANT:
782 ret = translate_variant_field_class(ctx);
783 break;
784 default:
785 abort();
786 }
787
788 return ret;
789 }
790
791 static
792 int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
793 struct fs_sink_ctf_field_class *parent_fc)
794 {
795 int ret = 0;
796 GString *field_ref = NULL;
797 bool is_before;
798 const char *tgt_type;
799 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
800 (void *) parent_fc;
801 uint64_t i;
802 unsigned int suffix = 0;
803
804 if (!fc_name || !parent_fc ||
805 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
806 /* Not supported */
807 ret = -1;
808 goto end;
809 }
810
811 switch (fc->type) {
812 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
813 {
814 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
815
816 field_ref = seq_fc->length_ref;
817 is_before = seq_fc->length_is_before;
818 tgt_type = "len";
819 break;
820 }
821 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
822 {
823 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
824
825 field_ref = var_fc->tag_ref;
826 is_before = var_fc->tag_is_before;
827 tgt_type = "tag";
828 break;
829 }
830 default:
831 abort();
832 }
833
834 BT_ASSERT(field_ref);
835
836 if (!is_before) {
837 goto end;
838 }
839
840 /* Initial field ref */
841 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
842
843 /*
844 * Make sure field ref does not clash with an existing field
845 * class name within the same parent structure field class.
846 */
847 while (true) {
848 bool name_ok = true;
849
850 for (i = 0; i < parent_struct_fc->members->len; i++) {
851 struct fs_sink_ctf_named_field_class *named_fc =
852 fs_sink_ctf_field_class_struct_borrow_member_by_index(
853 parent_struct_fc, i);
854
855 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
856 /* Name clash */
857 name_ok = false;
858 break;
859 }
860 }
861
862 if (name_ok) {
863 /* No clash: we're done */
864 break;
865 }
866
867 /* Append suffix and try again */
868 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
869 suffix);
870 suffix++;
871 }
872
873 end:
874 return ret;
875 }
876
877 /*
878 * This function recursively sets field refs of sequence and variant
879 * field classes when they are immediately before, avoiding name clashes
880 * with existing field class names.
881 *
882 * It can fail at this point if, for example, a sequence field class of
883 * which to set the length's field ref has something else than a
884 * structure field class as its parent: in this case, there's no
885 * location to place the length field class immediately before the
886 * sequence field class.
887 */
888 static
889 int set_field_refs(struct fs_sink_ctf_field_class *fc, const char *fc_name,
890 struct fs_sink_ctf_field_class *parent_fc)
891 {
892 int ret = 0;
893 BT_ASSERT(fc);
894
895 switch (fc->type) {
896 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
897 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
898 {
899 uint64_t i;
900 uint64_t len;
901 struct fs_sink_ctf_field_class_struct *struct_fc;
902 struct fs_sink_ctf_field_class_variant *var_fc;
903 struct fs_sink_ctf_named_field_class *named_fc;
904
905 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
906 struct_fc = (void *) fc;
907 len = struct_fc->members->len;
908 } else {
909 var_fc = (void *) fc;
910 len = var_fc->options->len;
911 ret = set_field_ref(fc, fc_name, parent_fc);
912 if (ret) {
913 goto end;
914 }
915 }
916
917 for (i = 0; i < len; i++) {
918 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
919 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
920 struct_fc, i);
921 } else {
922 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
923 var_fc, i);
924 }
925
926 ret = set_field_refs(named_fc->fc, named_fc->name->str,
927 fc);
928 if (ret) {
929 goto end;
930 }
931 }
932
933 break;
934 }
935 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
936 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
937 {
938 struct fs_sink_ctf_field_class_array_base *array_base_fc =
939 (void *) fc;
940
941 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
942 ret = set_field_ref(fc, fc_name, parent_fc);
943 if (ret) {
944 goto end;
945 }
946 }
947
948 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
949 if (ret) {
950 goto end;
951 }
952
953 break;
954 }
955 default:
956 break;
957 }
958
959 end:
960 return ret;
961 }
962
963 /*
964 * This function translates a root scope trace IR field class to
965 * a CTF IR field class.
966 *
967 * The resulting CTF IR field class is written to `*fc` so that it
968 * exists as the parent object's (stream class or event class) true root
969 * field class during the recursive translation for resolving purposes.
970 * This is also why this function creates the empty structure field
971 * class and then calls translate_structure_field_class_members() to
972 * fill it.
973 */
974 static
975 int translate_scope_field_class(struct ctx *ctx, bt_scope scope,
976 struct fs_sink_ctf_field_class **fc,
977 const bt_field_class *ir_fc)
978 {
979 int ret = 0;
980
981 if (!ir_fc) {
982 goto end;
983 }
984
985 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
986 BT_FIELD_CLASS_TYPE_STRUCTURE);
987 BT_ASSERT(fc);
988 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
989 ir_fc, UINT64_C(-1));
990 BT_ASSERT(*fc);
991 ctx->cur_scope = scope;
992 BT_ASSERT(ctx->cur_path->len == 0);
993 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, ir_fc, NULL);
994 if (ret) {
995 BT_LOGE("Cannot translate scope structure field class: "
996 "scope=%d", scope);
997 goto end;
998 }
999
1000 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
1001 if (ret) {
1002 BT_LOGE("Cannot translate scope structure field class: "
1003 "scope=%d", scope);
1004 goto end;
1005 }
1006
1007 cur_path_stack_pop(ctx);
1008
1009 /* Set field refs for preceding targets */
1010 ret = set_field_refs(*fc, NULL, NULL);
1011
1012 end:
1013 return ret;
1014 }
1015
1016 static inline
1017 void ctx_init(struct ctx *ctx)
1018 {
1019 memset(ctx, 0, sizeof(struct ctx));
1020 ctx->cur_path = g_array_new(FALSE, TRUE,
1021 sizeof(struct field_path_elem));
1022 BT_ASSERT(ctx->cur_path);
1023 }
1024
1025 static inline
1026 void ctx_fini(struct ctx *ctx)
1027 {
1028 if (ctx->cur_path) {
1029 g_array_free(ctx->cur_path, TRUE);
1030 ctx->cur_path = NULL;
1031 }
1032 }
1033
1034 static
1035 int translate_event_class(struct fs_sink_ctf_stream_class *sc,
1036 const bt_event_class *ir_ec,
1037 struct fs_sink_ctf_event_class **out_ec)
1038 {
1039 int ret = 0;
1040 struct ctx ctx;
1041 struct fs_sink_ctf_event_class *ec;
1042
1043 BT_ASSERT(sc);
1044 BT_ASSERT(ir_ec);
1045
1046 ctx_init(&ctx);
1047 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1048 BT_ASSERT(ec);
1049 ctx.cur_sc = sc;
1050 ctx.cur_ec = ec;
1051 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
1052 &ec->spec_context_fc,
1053 bt_event_class_borrow_specific_context_field_class_const(
1054 ir_ec));
1055 if (ret) {
1056 goto end;
1057 }
1058
1059 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_PAYLOAD,
1060 &ec->payload_fc,
1061 bt_event_class_borrow_payload_field_class_const(ir_ec));
1062 if (ret) {
1063 goto end;
1064 }
1065
1066 end:
1067 ctx_fini(&ctx);
1068 *out_ec = ec;
1069 return ret;
1070 }
1071
1072 BT_HIDDEN
1073 int try_translate_event_class_trace_ir_to_ctf_ir(
1074 struct fs_sink_ctf_stream_class *sc,
1075 const bt_event_class *ir_ec,
1076 struct fs_sink_ctf_event_class **out_ec)
1077 {
1078 int ret = 0;
1079
1080 BT_ASSERT(sc);
1081 BT_ASSERT(ir_ec);
1082
1083 /* Check in hash table first */
1084 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
1085 if (likely(*out_ec)) {
1086 goto end;
1087 }
1088
1089 ret = translate_event_class(sc, ir_ec, out_ec);
1090
1091 end:
1092 return ret;
1093 }
1094
1095 bool default_clock_class_name_exists(struct fs_sink_ctf_trace_class *tc,
1096 const char *name)
1097 {
1098 bool exists = false;
1099 uint64_t i;
1100
1101 for (i = 0; i < tc->stream_classes->len; i++) {
1102 struct fs_sink_ctf_stream_class *sc =
1103 tc->stream_classes->pdata[i];
1104
1105 if (sc->default_clock_class_name->len == 0) {
1106 /* No default clock class */
1107 continue;
1108 }
1109
1110 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1111 exists = true;
1112 goto end;
1113 }
1114 }
1115
1116 end:
1117 return exists;
1118 }
1119
1120 static
1121 void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1122 {
1123 unsigned int suffix = 0;
1124 char buf[16];
1125
1126 g_string_assign(sc->default_clock_class_name, "");
1127 sprintf(buf, "default");
1128
1129 while (default_clock_class_name_exists(sc->tc, buf)) {
1130 sprintf(buf, "default%u", suffix);
1131 suffix++;
1132 }
1133
1134 g_string_assign(sc->default_clock_class_name, buf);
1135 }
1136
1137 static
1138 int translate_stream_class(struct fs_sink_ctf_trace_class *tc,
1139 const bt_stream_class *ir_sc,
1140 struct fs_sink_ctf_stream_class **out_sc)
1141 {
1142 int ret = 0;
1143 struct ctx ctx;
1144
1145 BT_ASSERT(tc);
1146 BT_ASSERT(ir_sc);
1147 ctx_init(&ctx);
1148 *out_sc = fs_sink_ctf_stream_class_create(tc, ir_sc);
1149 BT_ASSERT(*out_sc);
1150
1151 /* Set default clock class's protected name, if any */
1152 if ((*out_sc)->default_clock_class) {
1153 const char *name = bt_clock_class_get_name(
1154 (*out_sc)->default_clock_class);
1155
1156 if (!bt_stream_class_default_clock_is_always_known(ir_sc)) {
1157 BT_LOGE("Unsupported stream clock which can have an unknown value: "
1158 "sc-name=\"%s\"",
1159 bt_stream_class_get_name(ir_sc));
1160 goto error;
1161 }
1162
1163 if (name) {
1164 /* Try original name, protected */
1165 g_string_assign((*out_sc)->default_clock_class_name,
1166 name);
1167 ret = fs_sink_ctf_protect_name(
1168 (*out_sc)->default_clock_class_name);
1169 if (ret) {
1170 /* Invalid: create a new name */
1171 make_unique_default_clock_class_name(*out_sc);
1172 ret = 0;
1173 }
1174 } else {
1175 /* No name: create a name */
1176 make_unique_default_clock_class_name(*out_sc);
1177 }
1178 }
1179
1180 ctx.cur_sc = *out_sc;
1181 ret = translate_scope_field_class(&ctx, BT_SCOPE_PACKET_CONTEXT,
1182 &(*out_sc)->packet_context_fc,
1183 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1184 if (ret) {
1185 goto error;
1186 }
1187
1188 if ((*out_sc)->packet_context_fc) {
1189 /*
1190 * Make sure the structure field class's alignment is
1191 * enough: 8 is what we use for our own special members
1192 * in the packet context.
1193 */
1194 fs_sink_ctf_field_class_struct_align_at_least(
1195 (void *) (*out_sc)->packet_context_fc, 8);
1196 }
1197
1198 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_COMMON_CONTEXT,
1199 &(*out_sc)->event_common_context_fc,
1200 bt_stream_class_borrow_event_common_context_field_class_const(
1201 ir_sc));
1202 if (ret) {
1203 goto error;
1204 }
1205
1206 goto end;
1207
1208 error:
1209 fs_sink_ctf_stream_class_destroy(*out_sc);
1210 *out_sc = NULL;
1211
1212 end:
1213 ctx_fini(&ctx);
1214 return ret;
1215 }
1216
1217 BT_HIDDEN
1218 int try_translate_stream_class_trace_ir_to_ctf_ir(
1219 struct fs_sink_ctf_trace_class *tc,
1220 const bt_stream_class *ir_sc,
1221 struct fs_sink_ctf_stream_class **out_sc)
1222 {
1223 int ret = 0;
1224 uint64_t i;
1225
1226 BT_ASSERT(tc);
1227 BT_ASSERT(ir_sc);
1228
1229 for (i = 0; i < tc->stream_classes->len; i++) {
1230 *out_sc = tc->stream_classes->pdata[i];
1231
1232 if ((*out_sc)->ir_sc == ir_sc) {
1233 goto end;
1234 }
1235 }
1236
1237 ret = translate_stream_class(tc, ir_sc, out_sc);
1238
1239 end:
1240 return ret;
1241 }
1242
1243 BT_HIDDEN
1244 struct fs_sink_ctf_trace_class *translate_trace_class_trace_ir_to_ctf_ir(
1245 const bt_trace_class *ir_tc)
1246 {
1247 uint64_t count;
1248 uint64_t i;
1249 struct fs_sink_ctf_trace_class *tc = NULL;
1250
1251 /* Check that trace class's environment is TSDL-compatible */
1252 count = bt_trace_class_get_environment_entry_count(ir_tc);
1253 for (i = 0; i < count; i++) {
1254 const char *name;
1255 const bt_value *val;
1256
1257 bt_trace_class_borrow_environment_entry_by_index_const(
1258 ir_tc, i, &name, &val);
1259
1260 if (!fs_sink_ctf_ist_valid_identifier(name)) {
1261 BT_LOGE("Unsupported trace class's environment entry name: "
1262 "name=\"%s\"", name);
1263 goto end;
1264 }
1265
1266 switch (bt_value_get_type(val)) {
1267 case BT_VALUE_TYPE_INTEGER:
1268 case BT_VALUE_TYPE_STRING:
1269 break;
1270 default:
1271 BT_LOGE("Unsupported trace class's environment entry value type: "
1272 "type=%s",
1273 bt_common_value_type_string(
1274 bt_value_get_type(val)));
1275 goto end;
1276 }
1277 }
1278
1279 tc = fs_sink_ctf_trace_class_create(ir_tc);
1280 BT_ASSERT(tc);
1281
1282 end:
1283 return tc;
1284 }
This page took 0.08711 seconds and 3 git commands to generate.