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