Fix -Wmissing-prototypes/-Wmissing-declarations warnings
[babeltrace.git] / src / plugins / ctf / fs-sink / translate-trace-ir-to-ctf-ir.c
CommitLineData
46bdd3e0
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
85623cd6 23#define BT_COMP_LOG_SELF_COMP (ctx->self_comp)
a708ff31 24#define BT_LOG_OUTPUT_LEVEL (ctx->log_level)
b03487ab 25#define BT_LOG_TAG "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"
3fa1b6a3 26#include "logging/comp-logging.h"
46bdd3e0 27
f3847c75
SM
28#include "translate-trace-ir-to-ctf-ir.h"
29
71c5da58 30#include <babeltrace2/babeltrace.h>
85e7137b 31#include "common/macros.h"
57952005
MJ
32#include "common/common.h"
33#include "common/assert.h"
46bdd3e0
PP
34#include <stdio.h>
35#include <stdbool.h>
36#include <string.h>
37#include <glib.h>
38
85623cd6 39#include "fs-sink.h"
46bdd3e0
PP
40#include "fs-sink-ctf-meta.h"
41
42struct field_path_elem {
43 uint64_t index_in_parent;
44 GString *name;
45
46 /* Weak */
47 const bt_field_class *ir_fc;
48
49 /* Weak */
50 struct fs_sink_ctf_field_class *parent_fc;
51};
52
53struct ctx {
a708ff31 54 bt_logging_level log_level;
85623cd6 55 bt_self_component *self_comp;
a708ff31 56
46bdd3e0
PP
57 /* Weak */
58 struct fs_sink_ctf_stream_class *cur_sc;
59
60 /* Weak */
61 struct fs_sink_ctf_event_class *cur_ec;
62
056995e5 63 bt_field_path_scope cur_scope;
46bdd3e0
PP
64
65 /*
66 * Array of `struct field_path_elem` */
67 GArray *cur_path;
68};
69
70static inline
71struct field_path_elem *cur_path_stack_at(struct ctx *ctx, uint64_t i)
72{
73 BT_ASSERT(i < ctx->cur_path->len);
74 return &g_array_index(ctx->cur_path, struct field_path_elem, i);
75}
76
77static inline
78struct field_path_elem *cur_path_stack_top(struct ctx *ctx)
79{
80 BT_ASSERT(ctx->cur_path->len > 0);
81 return cur_path_stack_at(ctx, ctx->cur_path->len - 1);
82}
83
84static inline
85bool is_reserved_member_name(const char *name, const char *reserved_name)
86{
87 bool is_reserved = false;
88
89 if (strcmp(name, reserved_name) == 0) {
90 is_reserved = true;
91 goto end;
92 }
93
94 if (name[0] == '_' && strcmp(&name[1], reserved_name) == 0) {
95 is_reserved = true;
96 goto end;
97 }
98
99end:
100 return is_reserved;
101}
102
02b61fe0
PP
103static const char *reserved_tsdl_keywords[] = {
104 "align",
105 "callsite",
106 "const",
107 "char",
108 "clock",
109 "double",
110 "enum",
111 "env",
112 "event",
113 "floating_point",
114 "float",
115 "integer",
116 "int",
117 "long",
118 "short",
119 "signed",
120 "stream",
121 "string",
122 "struct",
123 "trace",
124 "typealias",
125 "typedef",
126 "unsigned",
127 "variant",
128 "void",
129 "_Bool",
130 "_Complex",
131 "_Imaginary",
132};
133
134static inline
135bool ist_valid_identifier(const char *name)
136{
137 const char *at;
138 uint64_t i;
139 bool ist_valid = true;
140
141 /* Make sure the name is not a reserved keyword */
142 for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords);
143 i++) {
144 if (strcmp(name, reserved_tsdl_keywords[i]) == 0) {
145 ist_valid = false;
146 goto end;
147 }
148 }
149
150 /* Make sure the name is not an empty string */
151 if (strlen(name) == 0) {
152 ist_valid = false;
153 goto end;
154 }
155
156 /* Make sure the name starts with a letter or `_` */
157 if (!isalpha(name[0]) && name[0] != '_') {
158 ist_valid = false;
159 goto end;
160 }
161
162 /* Make sure the name only contains letters, digits, and `_` */
163 for (at = name; *at != '\0'; at++) {
164 if (!isalnum(*at) && *at != '_') {
165 ist_valid = false;
166 goto end;
167 }
168 }
169
170end:
171 return ist_valid;
172}
173
174static inline
175bool must_protect_identifier(const char *name)
176{
177 uint64_t i;
178 bool must_protect = false;
179
180 /* Protect a reserved keyword */
181 for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords);
182 i++) {
183 if (strcmp(name, reserved_tsdl_keywords[i]) == 0) {
184 must_protect = true;
185 goto end;
186 }
187 }
188
189 /* Protect an identifier which already starts with `_` */
190 if (name[0] == '_') {
191 must_protect = true;
192 goto end;
193 }
194
195end:
196 return must_protect;
197}
198
46bdd3e0
PP
199static inline
200int cur_path_stack_push(struct ctx *ctx,
02b61fe0
PP
201 uint64_t index_in_parent, const char *name,
202 bool force_protect_name, const bt_field_class *ir_fc,
46bdd3e0
PP
203 struct fs_sink_ctf_field_class *parent_fc)
204{
205 int ret = 0;
206 struct field_path_elem *field_path_elem;
207
208 g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1);
209 field_path_elem = cur_path_stack_top(ctx);
210 field_path_elem->index_in_parent = index_in_parent;
02b61fe0
PP
211 field_path_elem->name = g_string_new(NULL);
212
213 if (name) {
214 if (force_protect_name) {
215 g_string_assign(field_path_elem->name, "_");
216 }
217
218 g_string_append(field_path_elem->name, name);
46bdd3e0 219
056995e5 220 if (ctx->cur_scope == BT_FIELD_PATH_SCOPE_PACKET_CONTEXT) {
02b61fe0
PP
221 if (is_reserved_member_name(name, "packet_size") ||
222 is_reserved_member_name(name, "content_size") ||
223 is_reserved_member_name(name, "timestamp_begin") ||
224 is_reserved_member_name(name, "timestamp_end") ||
225 is_reserved_member_name(name, "events_discarded") ||
226 is_reserved_member_name(name, "packet_seq_num")) {
85623cd6 227 BT_COMP_LOGE("Unsupported reserved TSDL structure field class member "
46bdd3e0 228 "or variant field class option name: name=\"%s\"",
02b61fe0 229 name);
46bdd3e0
PP
230 ret = -1;
231 goto end;
232 }
233 }
234
02b61fe0
PP
235 if (!ist_valid_identifier(field_path_elem->name->str)) {
236 ret = -1;
85623cd6 237 BT_COMP_LOGE("Unsupported non-TSDL structure field class member "
46bdd3e0 238 "or variant field class option name: name=\"%s\"",
02b61fe0 239 field_path_elem->name->str);
46bdd3e0
PP
240 goto end;
241 }
242 }
243
244 field_path_elem->ir_fc = ir_fc;
245 field_path_elem->parent_fc = parent_fc;
246
247end:
248 return ret;
249}
250
251static inline
252void cur_path_stack_pop(struct ctx *ctx)
253{
254 struct field_path_elem *field_path_elem;
255
256 BT_ASSERT(ctx->cur_path->len > 0);
257 field_path_elem = cur_path_stack_top(ctx);
258
259 if (field_path_elem->name) {
260 g_string_free(field_path_elem->name, TRUE);
261 field_path_elem->name = NULL;
262 }
263
264 g_array_set_size(ctx->cur_path, ctx->cur_path->len - 1);
265}
266
46bdd3e0
PP
267/*
268 * Creates a relative field ref (a single name) from IR field path
269 * `tgt_ir_field_path`.
270 *
271 * This function tries to locate the target field class recursively from
272 * the top to the bottom of the context's current path using only the
273 * target field class's own name. This is because many CTF reading tools
274 * do not support a relative field ref with more than one element, for
275 * example `prev_struct.len`.
276 *
277 * Returns a negative value if this resolving operation failed.
278 */
279static
280int create_relative_field_ref(struct ctx *ctx,
02b61fe0
PP
281 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
282 struct fs_sink_ctf_field_class **user_tgt_fc)
46bdd3e0
PP
283{
284 int ret = 0;
285 struct fs_sink_ctf_field_class *tgt_fc = NULL;
286 uint64_t i;
287 int64_t si;
08cdcf01 288 const char *tgt_fc_name = NULL;
46bdd3e0
PP
289 struct field_path_elem *field_path_elem;
290
291 /* Get target field class's name */
292 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
056995e5 293 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
46bdd3e0
PP
294 BT_ASSERT(ctx->cur_sc);
295 tgt_fc = ctx->cur_sc->packet_context_fc;
296 break;
056995e5 297 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
46bdd3e0
PP
298 BT_ASSERT(ctx->cur_sc);
299 tgt_fc = ctx->cur_sc->event_common_context_fc;
300 break;
056995e5 301 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
46bdd3e0
PP
302 BT_ASSERT(ctx->cur_ec);
303 tgt_fc = ctx->cur_ec->spec_context_fc;
304 break;
056995e5 305 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
46bdd3e0
PP
306 BT_ASSERT(ctx->cur_ec);
307 tgt_fc = ctx->cur_ec->payload_fc;
308 break;
309 default:
310 abort();
311 }
312
313 i = 0;
314
1d4afa5f
PP
315 while (i < bt_field_path_get_item_count(tgt_ir_field_path)) {
316 const bt_field_path_item *fp_item =
317 bt_field_path_borrow_item_by_index_const(
318 tgt_ir_field_path, i);
46bdd3e0
PP
319 struct fs_sink_ctf_named_field_class *named_fc = NULL;
320
321 BT_ASSERT(tgt_fc);
1d4afa5f 322 BT_ASSERT(fp_item);
46bdd3e0 323
c27259b0
PP
324 if (bt_field_path_item_get_type(fp_item) ==
325 BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT) {
326 /* Not supported by CTF 1.8 */
327 ret = -1;
328 goto end;
329 }
330
567cee92 331 switch (tgt_fc->type) {
46bdd3e0 332 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1d4afa5f
PP
333 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
334 BT_FIELD_PATH_ITEM_TYPE_INDEX);
46bdd3e0 335 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1d4afa5f
PP
336 (void *) tgt_fc,
337 bt_field_path_item_index_get_index(fp_item));
46bdd3e0
PP
338 break;
339 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1d4afa5f
PP
340 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
341 BT_FIELD_PATH_ITEM_TYPE_INDEX);
46bdd3e0 342 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1d4afa5f
PP
343 (void *) tgt_fc,
344 bt_field_path_item_index_get_index(fp_item));
46bdd3e0
PP
345 break;
346 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
347 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
348 {
349 struct fs_sink_ctf_field_class_array_base *array_base_fc =
350 (void *) tgt_fc;
351
1d4afa5f
PP
352 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
353 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
46bdd3e0
PP
354 tgt_fc = array_base_fc->elem_fc;
355 break;
356 }
357 default:
358 abort();
359 }
360
361 if (named_fc) {
362 tgt_fc = named_fc->fc;
363 tgt_fc_name = named_fc->name->str;
364 i++;
365 }
366 }
367
368 BT_ASSERT(tgt_fc);
567cee92 369 BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
46bdd3e0
PP
370 BT_ASSERT(tgt_fc_name);
371
372 /* Find target field class having this name in current context */
373 for (si = ctx->cur_path->len - 1; si >= 0; si--) {
374 struct fs_sink_ctf_field_class *fc;
ce706c97
JG
375 struct fs_sink_ctf_field_class_struct *struct_fc = NULL;
376 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
46bdd3e0
PP
377 struct fs_sink_ctf_named_field_class *named_fc;
378 uint64_t len;
379
380 field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
381 fc = field_path_elem->parent_fc;
382 if (!fc) {
383 /* Reached stack's bottom */
384 ret = -1;
385 goto end;
386 }
387
388 switch (fc->type) {
389 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
390 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
391 break;
392 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
393 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
394 continue;
395 default:
396 /* Not supported by TSDL 1.8 */
397 ret = -1;
398 goto end;
399 }
400
401 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
402 struct_fc = (void *) fc;
403 len = struct_fc->members->len;
404 } else {
405 var_fc = (void *) fc;
406 len = var_fc->options->len;
407 }
408
409 for (i = 0; i < len; i++) {
410 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
411 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
412 struct_fc, i);
413 } else {
414 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
415 var_fc, i);
416 }
417
418 if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
419 if (named_fc->fc == tgt_fc) {
420 g_string_assign(tgt_field_ref,
421 tgt_fc_name);
02b61fe0
PP
422
423 if (user_tgt_fc) {
424 *user_tgt_fc = tgt_fc;
425 }
46bdd3e0
PP
426 } else {
427 /*
428 * Using only the target field
429 * class's name, we're not
430 * reaching the target field
431 * class. This is not supported
432 * by TSDL 1.8.
433 */
434 ret = -1;
435 }
436
437 goto end;
438 }
439 }
440 }
441
442end:
443 return ret;
444}
445
446/*
447 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
448 *
449 * Returns a negative value if this resolving operation failed.
450 */
451static
452int create_absolute_field_ref(struct ctx *ctx,
02b61fe0
PP
453 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
454 struct fs_sink_ctf_field_class **user_tgt_fc)
46bdd3e0
PP
455{
456 int ret = 0;
457 struct fs_sink_ctf_field_class *fc = NULL;
458 uint64_t i;
459
460 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
056995e5 461 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
46bdd3e0
PP
462 BT_ASSERT(ctx->cur_sc);
463 fc = ctx->cur_sc->packet_context_fc;
464 g_string_assign(tgt_field_ref, "stream.packet.context");
465 break;
056995e5 466 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
46bdd3e0
PP
467 BT_ASSERT(ctx->cur_sc);
468 fc = ctx->cur_sc->event_common_context_fc;
469 g_string_assign(tgt_field_ref, "stream.event.context");
470 break;
056995e5 471 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
46bdd3e0
PP
472 BT_ASSERT(ctx->cur_ec);
473 fc = ctx->cur_ec->spec_context_fc;
474 g_string_assign(tgt_field_ref, "event.context");
475 break;
056995e5 476 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
46bdd3e0
PP
477 BT_ASSERT(ctx->cur_ec);
478 fc = ctx->cur_ec->payload_fc;
479 g_string_assign(tgt_field_ref, "event.fields");
480 break;
481 default:
482 abort();
483 }
484
485 BT_ASSERT(fc);
486
1d4afa5f
PP
487 for (i = 0; i < bt_field_path_get_item_count(tgt_ir_field_path); i++) {
488 const bt_field_path_item *fp_item =
489 bt_field_path_borrow_item_by_index_const(
490 tgt_ir_field_path, i);
46bdd3e0
PP
491 struct fs_sink_ctf_named_field_class *named_fc = NULL;
492
1d4afa5f
PP
493 if (bt_field_path_item_get_type(fp_item) !=
494 BT_FIELD_PATH_ITEM_TYPE_INDEX) {
495 /* Not supported by TSDL 1.8 */
496 ret = -1;
497 goto end;
498 }
499
46bdd3e0
PP
500 switch (fc->type) {
501 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1d4afa5f
PP
502 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
503 BT_FIELD_PATH_ITEM_TYPE_INDEX);
46bdd3e0 504 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1d4afa5f
PP
505 (void *) fc,
506 bt_field_path_item_index_get_index(fp_item));
46bdd3e0
PP
507 break;
508 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1d4afa5f
PP
509 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
510 BT_FIELD_PATH_ITEM_TYPE_INDEX);
46bdd3e0 511 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1d4afa5f
PP
512 (void *) fc,
513 bt_field_path_item_index_get_index(fp_item));
46bdd3e0 514 break;
46bdd3e0
PP
515 default:
516 abort();
517 }
518
519 BT_ASSERT(named_fc);
520 g_string_append_c(tgt_field_ref, '.');
521 g_string_append(tgt_field_ref, named_fc->name->str);
522 fc = named_fc->fc;
523 }
524
02b61fe0
PP
525 if (user_tgt_fc) {
526 *user_tgt_fc = fc;
527 }
528
46bdd3e0
PP
529end:
530 return ret;
531}
532
533/*
534 * Resolves a target field class located at `tgt_ir_field_path`, writing
535 * the resolved field ref to `tgt_field_ref` and setting
536 * `*create_before` according to whether or not the target field must be
537 * created immediately before (in which case `tgt_field_ref` is
538 * irrelevant).
539 */
540static
541void resolve_field_class(struct ctx *ctx,
542 const bt_field_path *tgt_ir_field_path,
02b61fe0
PP
543 GString *tgt_field_ref, bool *create_before,
544 struct fs_sink_ctf_field_class **user_tgt_fc)
46bdd3e0
PP
545{
546 int ret;
056995e5 547 bt_field_path_scope tgt_scope;
46bdd3e0
PP
548
549 *create_before = false;
550
551 if (!tgt_ir_field_path) {
552 *create_before = true;
553 goto end;
554 }
555
556 tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
557
558 if (tgt_scope == ctx->cur_scope) {
559 /*
560 * Try, in this order:
561 *
562 * 1. Use a relative path, using only the target field
563 * class's name. This is what is the most commonly
564 * supported by popular CTF reading tools.
565 *
566 * 2. Use an absolute path. This could fail if there's
567 * an array field class from the current root's field
568 * class to the target field class.
569 *
570 * 3. Create the target field class before the
571 * requesting field class (fallback).
572 */
573 ret = create_relative_field_ref(ctx, tgt_ir_field_path,
02b61fe0 574 tgt_field_ref, user_tgt_fc);
46bdd3e0
PP
575 if (ret) {
576 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
02b61fe0 577 tgt_field_ref, user_tgt_fc);
46bdd3e0
PP
578 if (ret) {
579 *create_before = true;
46bdd3e0
PP
580 goto end;
581 }
582 }
583 } else {
584 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
02b61fe0 585 tgt_field_ref, user_tgt_fc);
46bdd3e0
PP
586
587 /* It must always work in previous scopes */
588 BT_ASSERT(ret == 0);
589 }
590
591end:
592 return;
593}
594
595static
596int translate_field_class(struct ctx *ctx);
597
598static inline
599void append_to_parent_field_class(struct ctx *ctx,
600 struct fs_sink_ctf_field_class *fc)
601{
602 struct fs_sink_ctf_field_class *parent_fc =
603 cur_path_stack_top(ctx)->parent_fc;
604
605 switch (parent_fc->type) {
606 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
607 fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
608 cur_path_stack_top(ctx)->name->str, fc);
609 break;
c27259b0
PP
610 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
611 {
612 struct fs_sink_ctf_field_class_option *opt_fc =
613 (void *) parent_fc;
614
615 BT_ASSERT(!opt_fc->content_fc);
616 opt_fc->content_fc = fc;
617 opt_fc->base.alignment = fc->alignment;
618 break;
619 }
46bdd3e0
PP
620 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
621 fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
622 cur_path_stack_top(ctx)->name->str, fc);
623 break;
624 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
625 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
626 {
627 struct fs_sink_ctf_field_class_array_base *array_base_fc =
628 (void *) parent_fc;
629
630 BT_ASSERT(!array_base_fc->elem_fc);
631 array_base_fc->elem_fc = fc;
632 array_base_fc->base.alignment = fc->alignment;
633 break;
634 }
635 default:
636 abort();
637 }
638}
639
640static inline
641void update_parent_field_class_alignment(struct ctx *ctx,
642 unsigned int alignment)
643{
644 struct fs_sink_ctf_field_class *parent_fc =
645 cur_path_stack_top(ctx)->parent_fc;
646
647 switch (parent_fc->type) {
648 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
649 fs_sink_ctf_field_class_struct_align_at_least(
650 (void *) parent_fc, alignment);
651 break;
652 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
653 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
654 {
655 struct fs_sink_ctf_field_class_array_base *array_base_fc =
656 (void *) parent_fc;
657
658 array_base_fc->base.alignment = alignment;
659 break;
660 }
661 default:
662 break;
663 }
664}
665
666static inline
667int translate_structure_field_class_members(struct ctx *ctx,
668 struct fs_sink_ctf_field_class_struct *struct_fc,
669 const bt_field_class *ir_fc)
670{
671 int ret = 0;
672 uint64_t i;
673
674 for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
675 const bt_field_class_structure_member *member;
676 const char *name;
677 const bt_field_class *memb_ir_fc;
678
679 member =
680 bt_field_class_structure_borrow_member_by_index_const(
681 ir_fc, i);
682 name = bt_field_class_structure_member_get_name(member);
683 memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
684 member);
02b61fe0 685 ret = cur_path_stack_push(ctx, i, name, true, memb_ir_fc,
46bdd3e0
PP
686 (void *) struct_fc);
687 if (ret) {
85623cd6 688 BT_COMP_LOGE("Cannot translate structure field class member: "
46bdd3e0
PP
689 "name=\"%s\"", name);
690 goto end;
691 }
692
693 ret = translate_field_class(ctx);
694 if (ret) {
85623cd6 695 BT_COMP_LOGE("Cannot translate structure field class member: "
46bdd3e0
PP
696 "name=\"%s\"", name);
697 goto end;
698 }
699
700 cur_path_stack_pop(ctx);
701 }
702
703end:
704 return ret;
705}
706
707static inline
708int translate_structure_field_class(struct ctx *ctx)
709{
710 int ret;
711 struct fs_sink_ctf_field_class_struct *fc =
712 fs_sink_ctf_field_class_struct_create_empty(
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 ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
719 if (ret) {
720 goto end;
721 }
722
723 update_parent_field_class_alignment(ctx, fc->base.alignment);
724
725end:
726 return ret;
727}
728
02b61fe0 729/*
2388fb87
PP
730 * This function protects a given variant FC option name (with the `_`
731 * prefix) if required. On success, `name_buf->str` contains the variant
732 * FC option name to use (original option name or protected if
733 * required).
02b61fe0
PP
734 *
735 * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
736 * close as possible to an original CTF trace as decoded by
737 * `src.ctf.fs`.
738 *
739 * This scenario is valid in CTF 1.8:
740 *
741 * enum {
742 * HELLO,
743 * MEOW
744 * } tag;
745 *
746 * variant <tag> {
747 * int HELLO;
748 * string MEOW;
749 * };
750 *
751 * Once in trace IR, the enumeration FC mapping names and variant FC
752 * option names are kept as is. For this reason, we don't want to
753 * protect the variant FC option names here (by prepending `_`): this
754 * would make the variant FC option name and the enumeration FC mapping
755 * name not match.
756 *
757 * This scenario is also valid in CTF 1.8:
758 *
759 * enum {
760 * _HELLO,
761 * MEOW
762 * } tag;
763 *
764 * variant <tag> {
765 * int _HELLO;
766 * string MEOW;
767 * };
768 *
769 * Once in trace IR, the enumeration FC mapping names are kept as is,
770 * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
771 * for presentation, as recommended by CTF 1.8). When going back to
772 * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
773 * the corresponding enumeration FC mapping name.
774 *
775 * This scenario is also valid in CTF 1.8:
776 *
777 * enum {
778 * __HELLO,
779 * MEOW
780 * } tag;
781 *
782 * variant <tag> {
783 * int __HELLO;
784 * string MEOW;
785 * };
786 *
787 * Once in trace IR, the enumeration FC mapping names are kept as is,
788 * but the `__HELLO` variant FC option name becomes `_HELLO`
789 * (unprotected). When going back to TSDL, we need to protect `_HELLO`
790 * so that it becomes `__HELLO` to match the corresponding enumeration
791 * FC mapping name.
792 *
793 * `src.ctf.fs` always uses the _same_ integer range sets for a selector
794 * FC mapping and a corresponding variant FC option. We can use that
795 * fact to find the original variant FC option names by matching variant
796 * FC options and enumeration FC mappings by range set.
797 */
798static
2388fb87 799int maybe_protect_variant_option_name(const bt_field_class *ir_var_fc,
02b61fe0 800 const bt_field_class *ir_tag_fc, uint64_t opt_i,
2388fb87 801 GString *name_buf)
02b61fe0
PP
802{
803 int ret = 0;
804 uint64_t i;
805 bt_field_class_type ir_var_fc_type;
806 const void *opt_ranges = NULL;
807 const char *mapping_label = NULL;
808 const char *ir_opt_name;
809 const bt_field_class_variant_option *base_var_opt;
810 bool force_protect = false;
811
02b61fe0
PP
812 ir_var_fc_type = bt_field_class_get_type(ir_var_fc);
813 base_var_opt = bt_field_class_variant_borrow_option_by_index_const(
814 ir_var_fc, opt_i);
815 BT_ASSERT(base_var_opt);
816 ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt);
817 BT_ASSERT(ir_opt_name);
818
819 /*
820 * Check if the variant FC option name is required to be
821 * protected (reserved TSDL keyword or starts with `_`). In that
822 * case, the name of the selector FC mapping we find must match
823 * exactly the protected name.
824 */
825 force_protect = must_protect_identifier(ir_opt_name);
826 if (force_protect) {
02b61fe0
PP
827 g_string_assign(name_buf, "_");
828 g_string_append(name_buf, ir_opt_name);
829 } else {
830 g_string_assign(name_buf, ir_opt_name);
831 }
832
833 /* Borrow option's ranges */
8bc207af 834 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD) {
02b61fe0
PP
835 /* No ranges: we're done */
836 goto end;
8bc207af
PP
837 } if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
838 const bt_field_class_variant_with_selector_field_integer_unsigned_option *var_opt =
839 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
02b61fe0
PP
840 ir_var_fc, opt_i);
841 opt_ranges =
8bc207af 842 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
02b61fe0
PP
843 var_opt);
844 } else {
8bc207af
PP
845 const bt_field_class_variant_with_selector_field_integer_signed_option *var_opt =
846 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
02b61fe0
PP
847 ir_var_fc, opt_i);
848 opt_ranges =
8bc207af 849 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
02b61fe0
PP
850 var_opt);
851 }
852
853 /* Find corresponding mapping by range set in selector FC */
854 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_tag_fc);
855 i++) {
8bc207af 856 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD) {
02b61fe0 857 const bt_field_class_enumeration_mapping *mapping_base;
60bbfc7c 858 const bt_field_class_enumeration_unsigned_mapping *mapping;
02b61fe0
PP
859 const bt_integer_range_set_unsigned *mapping_ranges;
860
60bbfc7c 861 mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
02b61fe0 862 ir_tag_fc, i);
60bbfc7c 863 mapping_ranges = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
02b61fe0
PP
864 mapping);
865
e1c423f9 866 if (bt_integer_range_set_unsigned_is_equal(opt_ranges,
02b61fe0
PP
867 mapping_ranges)) {
868 /* We have a winner */
869 mapping_base =
60bbfc7c 870 bt_field_class_enumeration_unsigned_mapping_as_mapping_const(
02b61fe0
PP
871 mapping);
872 mapping_label =
873 bt_field_class_enumeration_mapping_get_label(
874 mapping_base);
875 break;
876 }
877 } else {
878 const bt_field_class_enumeration_mapping *mapping_base;
60bbfc7c 879 const bt_field_class_enumeration_signed_mapping *mapping;
02b61fe0
PP
880 const bt_integer_range_set_signed *mapping_ranges;
881
60bbfc7c 882 mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
02b61fe0 883 ir_tag_fc, i);
60bbfc7c 884 mapping_ranges = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
02b61fe0
PP
885 mapping);
886
e1c423f9 887 if (bt_integer_range_set_signed_is_equal(opt_ranges,
02b61fe0
PP
888 mapping_ranges)) {
889 /* We have a winner */
890 mapping_base =
60bbfc7c 891 bt_field_class_enumeration_signed_mapping_as_mapping_const(
02b61fe0
PP
892 mapping);
893 mapping_label =
894 bt_field_class_enumeration_mapping_get_label(
895 mapping_base);
896 break;
897 }
898 }
899 }
900
901 if (!mapping_label) {
902 /* Range set not found: invalid selector for CTF 1.8 */
903 ret = -1;
904 goto end;
905 }
906
907 /*
908 * If the enumeration FC mapping name is not the same as the
909 * variant FC option name and we didn't protect already, try
910 * protecting the option name and check again.
911 */
912 if (strcmp(mapping_label, name_buf->str) != 0) {
913 if (force_protect) {
914 ret = -1;
915 goto end;
916 }
917
918 if (mapping_label[0] == '\0') {
919 ret = -1;
920 goto end;
921 }
922
923 g_string_assign(name_buf, "_");
924 g_string_append(name_buf, ir_opt_name);
925
926 if (strcmp(mapping_label, name_buf->str) != 0) {
927 ret = -1;
928 goto end;
929 }
02b61fe0
PP
930 }
931
932end:
933 return ret;
934}
935
c27259b0
PP
936static inline
937int translate_option_field_class(struct ctx *ctx)
938{
939 struct fs_sink_ctf_field_class_option *fc =
940 fs_sink_ctf_field_class_option_create_empty(
941 cur_path_stack_top(ctx)->ir_fc,
942 cur_path_stack_top(ctx)->index_in_parent);
943 const bt_field_class *content_ir_fc =
944 bt_field_class_option_borrow_field_class_const(fc->base.ir_fc);
945 int ret;
946
947 BT_ASSERT(fc);
948
949 /*
950 * CTF 1.8 does not support the option field class type. To
951 * write something anyway, this component translates this type
952 * to a variant field class where the options are:
953 *
954 * * An empty structure field class.
955 * * The optional field class itself.
956 *
957 * The "tag" is always generated/before in that case (an 8-bit
958 * unsigned enumeration field class).
959 */
960 append_to_parent_field_class(ctx, (void *) fc);
961 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, content_ir_fc,
962 (void *) fc);
963 if (ret) {
964 BT_COMP_LOGE_STR("Cannot translate option field class content.");
965 goto end;
966 }
967
968 ret = translate_field_class(ctx);
969 if (ret) {
970 BT_COMP_LOGE_STR("Cannot translate option field class content.");
971 goto end;
972 }
973
974 cur_path_stack_pop(ctx);
975 update_parent_field_class_alignment(ctx, fc->base.alignment);
976
977end:
978 return ret;
979}
980
46bdd3e0
PP
981static inline
982int translate_variant_field_class(struct ctx *ctx)
983{
984 int ret = 0;
985 uint64_t i;
986 struct fs_sink_ctf_field_class_variant *fc =
987 fs_sink_ctf_field_class_variant_create_empty(
988 cur_path_stack_top(ctx)->ir_fc,
989 cur_path_stack_top(ctx)->index_in_parent);
02b61fe0
PP
990 bt_field_class_type ir_fc_type;
991 const bt_field_path *ir_selector_field_path = NULL;
992 struct fs_sink_ctf_field_class *tgt_fc = NULL;
993 GString *name_buf = g_string_new(NULL);
994 bt_value *prot_opt_names = bt_value_array_create();
995 uint64_t opt_count;
46bdd3e0
PP
996
997 BT_ASSERT(fc);
02b61fe0
PP
998 BT_ASSERT(name_buf);
999 BT_ASSERT(prot_opt_names);
1000 ir_fc_type = bt_field_class_get_type(fc->base.ir_fc);
1001 opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc);
1002
94847783
PP
1003 if (bt_field_class_type_is(ir_fc_type,
1004 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) {
8bc207af 1005 ir_selector_field_path = bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
02b61fe0
PP
1006 fc->base.ir_fc);
1007 BT_ASSERT(ir_selector_field_path);
1008 }
46bdd3e0
PP
1009
1010 /* Resolve tag field class before appending to parent */
02b61fe0
PP
1011 resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref,
1012 &fc->tag_is_before, &tgt_fc);
1013
1014 if (ir_selector_field_path && tgt_fc) {
1015 uint64_t mapping_count;
1016 uint64_t option_count;
1017
1018 /* CTF 1.8: selector FC must be an enumeration FC */
1019 bt_field_class_type type = bt_field_class_get_type(
1020 tgt_fc->ir_fc);
1021
94847783
PP
1022 if (!bt_field_class_type_is(type,
1023 BT_FIELD_CLASS_TYPE_ENUMERATION)) {
02b61fe0
PP
1024 fc->tag_is_before = true;
1025 goto validate_opts;
1026 }
1027
1028 /*
2388fb87 1029 * Call maybe_protect_variant_option_name() for each
02b61fe0
PP
1030 * option below. In that case we also want selector FC
1031 * to contain as many mappings as the variant FC has
1032 * options.
1033 */
1034 mapping_count = bt_field_class_enumeration_get_mapping_count(
1035 tgt_fc->ir_fc);
1036 option_count = bt_field_class_variant_get_option_count(
1037 fc->base.ir_fc);
1038
1039 if (mapping_count != option_count) {
1040 fc->tag_is_before = true;
1041 goto validate_opts;
1042 }
1043 } else {
1044 /*
1045 * No compatible selector field class for CTF 1.8:
1046 * create the appropriate selector field class.
1047 */
1048 fc->tag_is_before = true;
2388fb87 1049 goto validate_opts;
02b61fe0
PP
1050 }
1051
1052validate_opts:
1053 /*
1054 * First pass: detect any option name clash with option name
1055 * protection. In that case, we don't fail: just create the
1056 * selector field class before the variant field class.
1057 *
1058 * After this, `prot_opt_names` contains the final option names,
1059 * potentially protected if needed. They can still be invalid
1060 * TSDL identifiers however; this will be checked by
1061 * cur_path_stack_push().
1062 */
1063 for (i = 0; i < opt_count; i++) {
2388fb87
PP
1064 if (!fc->tag_is_before) {
1065 BT_ASSERT(tgt_fc->ir_fc);
1066 ret = maybe_protect_variant_option_name(fc->base.ir_fc,
1067 tgt_fc->ir_fc, i, name_buf);
1068 if (ret) {
1069 fc->tag_is_before = true;
1070 }
02b61fe0
PP
1071 }
1072
1073 ret = bt_value_array_append_string_element(prot_opt_names,
1074 name_buf->str);
1075 if (ret) {
1076 goto end;
1077 }
1078 }
1079
1080 for (i = 0; i < opt_count; i++) {
1081 uint64_t j;
1082 const bt_value *opt_name_a =
1083 bt_value_array_borrow_element_by_index_const(
1084 prot_opt_names, i);
1085
1086 for (j = 0; j < opt_count; j++) {
1087 const bt_value *opt_name_b;
1088
1089 if (i == j) {
1090 continue;
1091 }
46bdd3e0 1092
02b61fe0
PP
1093 opt_name_b =
1094 bt_value_array_borrow_element_by_index_const(
1095 prot_opt_names, j);
e1c423f9 1096 if (bt_value_is_equal(opt_name_a, opt_name_b)) {
02b61fe0
PP
1097 /*
1098 * Variant FC option names are not
1099 * unique when protected.
1100 */
1101 fc->tag_is_before = true;
1102 goto append_to_parent;
1103 }
1104 }
1105 }
1106
1107append_to_parent:
46bdd3e0
PP
1108 append_to_parent_field_class(ctx, (void *) fc);
1109
02b61fe0 1110 for (i = 0; i < opt_count; i++) {
46bdd3e0 1111 const bt_field_class_variant_option *opt;
46bdd3e0 1112 const bt_field_class *opt_ir_fc;
02b61fe0
PP
1113 const bt_value *prot_opt_name_val =
1114 bt_value_array_borrow_element_by_index_const(
1115 prot_opt_names, i);
1116 const char *prot_opt_name = bt_value_string_get(
1117 prot_opt_name_val);
46bdd3e0 1118
02b61fe0 1119 BT_ASSERT(prot_opt_name);
46bdd3e0
PP
1120 opt = bt_field_class_variant_borrow_option_by_index_const(
1121 fc->base.ir_fc, i);
46bdd3e0
PP
1122 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
1123 opt);
02b61fe0
PP
1124
1125 /*
1126 * We don't ask cur_path_stack_push() to protect the
1127 * option name because it's already protected at this
1128 * point.
1129 */
1130 ret = cur_path_stack_push(ctx, i, prot_opt_name, false,
1131 opt_ir_fc, (void *) fc);
46bdd3e0 1132 if (ret) {
85623cd6 1133 BT_COMP_LOGE("Cannot translate variant field class option: "
02b61fe0 1134 "name=\"%s\"", prot_opt_name);
46bdd3e0
PP
1135 goto end;
1136 }
1137
1138 ret = translate_field_class(ctx);
1139 if (ret) {
85623cd6 1140 BT_COMP_LOGE("Cannot translate variant field class option: "
02b61fe0 1141 "name=\"%s\"", prot_opt_name);
46bdd3e0
PP
1142 goto end;
1143 }
1144
1145 cur_path_stack_pop(ctx);
1146 }
1147
1148end:
02b61fe0
PP
1149 if (name_buf) {
1150 g_string_free(name_buf, TRUE);
1151 }
1152
1153 bt_value_put_ref(prot_opt_names);
46bdd3e0
PP
1154 return ret;
1155}
1156
1157static inline
1158int translate_static_array_field_class(struct ctx *ctx)
1159{
1160 struct fs_sink_ctf_field_class_array *fc =
1161 fs_sink_ctf_field_class_array_create_empty(
1162 cur_path_stack_top(ctx)->ir_fc,
1163 cur_path_stack_top(ctx)->index_in_parent);
1164 const bt_field_class *elem_ir_fc =
1165 bt_field_class_array_borrow_element_field_class_const(
1166 fc->base.base.ir_fc);
1167 int ret;
1168
1169 BT_ASSERT(fc);
1170 append_to_parent_field_class(ctx, (void *) fc);
02b61fe0 1171 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
46bdd3e0
PP
1172 (void *) fc);
1173 if (ret) {
85623cd6 1174 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
46bdd3e0
PP
1175 goto end;
1176 }
1177
1178 ret = translate_field_class(ctx);
1179 if (ret) {
85623cd6 1180 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
46bdd3e0
PP
1181 goto end;
1182 }
1183
1184 cur_path_stack_pop(ctx);
1185 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1186
1187end:
1188 return ret;
1189}
1190
1191static inline
1192int translate_dynamic_array_field_class(struct ctx *ctx)
1193{
1194 struct fs_sink_ctf_field_class_sequence *fc =
1195 fs_sink_ctf_field_class_sequence_create_empty(
1196 cur_path_stack_top(ctx)->ir_fc,
1197 cur_path_stack_top(ctx)->index_in_parent);
1198 const bt_field_class *elem_ir_fc =
1199 bt_field_class_array_borrow_element_field_class_const(
1200 fc->base.base.ir_fc);
1201 int ret;
1202
1203 BT_ASSERT(fc);
1204
1205 /* Resolve length field class before appending to parent */
b8ddb4f0
PP
1206 if (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc) ==
1207 BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) {
1208 resolve_field_class(ctx,
1209 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1210 fc->base.base.ir_fc),
1211 fc->length_ref, &fc->length_is_before, NULL);
1212 }
46bdd3e0
PP
1213
1214 append_to_parent_field_class(ctx, (void *) fc);
02b61fe0 1215 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
46bdd3e0
PP
1216 (void *) fc);
1217 if (ret) {
85623cd6 1218 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
46bdd3e0
PP
1219 goto end;
1220 }
1221
1222 ret = translate_field_class(ctx);
1223 if (ret) {
85623cd6 1224 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
46bdd3e0
PP
1225 goto end;
1226 }
1227
1228 cur_path_stack_pop(ctx);
1229 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1230
1231end:
1232 return ret;
1233}
1234
dc9cc972
PP
1235static inline
1236int translate_bool_field_class(struct ctx *ctx)
1237{
1238 struct fs_sink_ctf_field_class_bool *fc =
1239 fs_sink_ctf_field_class_bool_create(
1240 cur_path_stack_top(ctx)->ir_fc,
1241 cur_path_stack_top(ctx)->index_in_parent);
1242
1243 BT_ASSERT(fc);
1244 append_to_parent_field_class(ctx, (void *) fc);
1245 return 0;
1246}
1247
adec7d09
PP
1248static inline
1249int translate_bit_array_field_class(struct ctx *ctx)
1250{
1251 struct fs_sink_ctf_field_class_bit_array *fc =
1252 fs_sink_ctf_field_class_bit_array_create(
1253 cur_path_stack_top(ctx)->ir_fc,
1254 cur_path_stack_top(ctx)->index_in_parent);
1255
1256 BT_ASSERT(fc);
1257 append_to_parent_field_class(ctx, (void *) fc);
1258 return 0;
1259}
1260
46bdd3e0
PP
1261static inline
1262int translate_integer_field_class(struct ctx *ctx)
1263{
1264 struct fs_sink_ctf_field_class_int *fc =
1265 fs_sink_ctf_field_class_int_create(
1266 cur_path_stack_top(ctx)->ir_fc,
1267 cur_path_stack_top(ctx)->index_in_parent);
1268
1269 BT_ASSERT(fc);
1270 append_to_parent_field_class(ctx, (void *) fc);
1271 return 0;
1272}
1273
1274static inline
1275int translate_real_field_class(struct ctx *ctx)
1276{
1277 struct fs_sink_ctf_field_class_float *fc =
1278 fs_sink_ctf_field_class_float_create(
1279 cur_path_stack_top(ctx)->ir_fc,
1280 cur_path_stack_top(ctx)->index_in_parent);
1281
1282 BT_ASSERT(fc);
1283 append_to_parent_field_class(ctx, (void *) fc);
1284 return 0;
1285}
1286
1287static inline
1288int translate_string_field_class(struct ctx *ctx)
1289{
1290 struct fs_sink_ctf_field_class_string *fc =
1291 fs_sink_ctf_field_class_string_create(
1292 cur_path_stack_top(ctx)->ir_fc,
1293 cur_path_stack_top(ctx)->index_in_parent);
1294
1295 BT_ASSERT(fc);
1296 append_to_parent_field_class(ctx, (void *) fc);
1297 return 0;
1298}
1299
1300/*
1301 * Translates a field class, recursively.
1302 *
1303 * The field class's IR field class, parent field class, and index
1304 * within its parent are in the context's current path's top element
1305 * (cur_path_stack_top()).
1306 */
1307static
1308int translate_field_class(struct ctx *ctx)
1309{
1310 int ret;
94847783
PP
1311 bt_field_class_type ir_fc_type =
1312 bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc);
46bdd3e0 1313
94847783 1314 if (ir_fc_type == BT_FIELD_CLASS_TYPE_BOOL) {
dc9cc972 1315 ret = translate_bool_field_class(ctx);
94847783 1316 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_BIT_ARRAY) {
adec7d09 1317 ret = translate_bit_array_field_class(ctx);
94847783
PP
1318 } else if (bt_field_class_type_is(ir_fc_type,
1319 BT_FIELD_CLASS_TYPE_INTEGER)) {
46bdd3e0 1320 ret = translate_integer_field_class(ctx);
94847783
PP
1321 } else if (bt_field_class_type_is(ir_fc_type,
1322 BT_FIELD_CLASS_TYPE_REAL)) {
46bdd3e0 1323 ret = translate_real_field_class(ctx);
94847783 1324 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_STRING) {
46bdd3e0 1325 ret = translate_string_field_class(ctx);
94847783 1326 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
46bdd3e0 1327 ret = translate_structure_field_class(ctx);
94847783 1328 } else if (ir_fc_type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY) {
46bdd3e0 1329 ret = translate_static_array_field_class(ctx);
94847783
PP
1330 } else if (bt_field_class_type_is(ir_fc_type,
1331 BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) {
46bdd3e0 1332 ret = translate_dynamic_array_field_class(ctx);
94847783
PP
1333 } else if (bt_field_class_type_is(ir_fc_type,
1334 BT_FIELD_CLASS_TYPE_OPTION)) {
c27259b0 1335 ret = translate_option_field_class(ctx);
94847783
PP
1336 } else if (bt_field_class_type_is(ir_fc_type,
1337 BT_FIELD_CLASS_TYPE_VARIANT)) {
46bdd3e0 1338 ret = translate_variant_field_class(ctx);
94847783 1339 } else {
46bdd3e0
PP
1340 abort();
1341 }
1342
1343 return ret;
1344}
1345
1346static
1347int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
1348 struct fs_sink_ctf_field_class *parent_fc)
1349{
1350 int ret = 0;
1351 GString *field_ref = NULL;
1352 bool is_before;
1353 const char *tgt_type;
1354 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
1355 (void *) parent_fc;
1356 uint64_t i;
1357 unsigned int suffix = 0;
1358
1359 if (!fc_name || !parent_fc ||
1360 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1361 /* Not supported */
1362 ret = -1;
1363 goto end;
1364 }
1365
1366 switch (fc->type) {
c27259b0
PP
1367 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
1368 {
1369 /*
1370 * CTF 1.8 does not support the option field class type.
1371 * To write something anyway, this component translates
1372 * this type to a variant field class where the options
1373 * are:
1374 *
1375 * * An empty structure field class.
1376 * * The optional field class itself.
1377 *
1378 * Because the option field class becomes a CTF variant
1379 * field class, we use the term "tag" too here.
1380 *
1381 * The "tag" is always generated/before in that case (an
1382 * 8-bit unsigned enumeration field class).
1383 */
1384 struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc;
1385
1386 field_ref = opt_fc->tag_ref;
1387 is_before = true;
1388 tgt_type = "tag";
1389 break;
1390 }
46bdd3e0
PP
1391 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1392 {
1393 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
1394
1395 field_ref = seq_fc->length_ref;
1396 is_before = seq_fc->length_is_before;
1397 tgt_type = "len";
1398 break;
1399 }
1400 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1401 {
1402 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
1403
1404 field_ref = var_fc->tag_ref;
1405 is_before = var_fc->tag_is_before;
1406 tgt_type = "tag";
1407 break;
1408 }
1409 default:
1410 abort();
1411 }
1412
1413 BT_ASSERT(field_ref);
1414
1415 if (!is_before) {
1416 goto end;
1417 }
1418
1419 /* Initial field ref */
1420 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
1421
1422 /*
1423 * Make sure field ref does not clash with an existing field
1424 * class name within the same parent structure field class.
1425 */
1426 while (true) {
1427 bool name_ok = true;
1428
1429 for (i = 0; i < parent_struct_fc->members->len; i++) {
1430 struct fs_sink_ctf_named_field_class *named_fc =
1431 fs_sink_ctf_field_class_struct_borrow_member_by_index(
1432 parent_struct_fc, i);
1433
1434 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
1435 /* Name clash */
1436 name_ok = false;
1437 break;
1438 }
1439 }
1440
1441 if (name_ok) {
1442 /* No clash: we're done */
1443 break;
1444 }
1445
1446 /* Append suffix and try again */
1447 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
1448 suffix);
1449 suffix++;
1450 }
1451
1452end:
1453 return ret;
1454}
1455
1456/*
1457 * This function recursively sets field refs of sequence and variant
1458 * field classes when they are immediately before, avoiding name clashes
1459 * with existing field class names.
1460 *
1461 * It can fail at this point if, for example, a sequence field class of
1462 * which to set the length's field ref has something else than a
1463 * structure field class as its parent: in this case, there's no
1464 * location to place the length field class immediately before the
1465 * sequence field class.
1466 */
1467static
60439780
PP
1468int set_field_refs(struct fs_sink_ctf_field_class * const fc,
1469 const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
46bdd3e0
PP
1470{
1471 int ret = 0;
c5fe2e6f 1472 enum fs_sink_ctf_field_class_type fc_type;
46bdd3e0
PP
1473 BT_ASSERT(fc);
1474
c5fe2e6f
FD
1475 fc_type = fc->type;
1476
1477 switch (fc_type) {
c27259b0
PP
1478 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
1479 {
1480 struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc;
1481
1482 ret = set_field_ref(fc, fc_name, parent_fc);
1483 if (ret) {
1484 goto end;
1485 }
1486
1487 ret = set_field_refs(opt_fc->content_fc, NULL, fc);
1488 if (ret) {
1489 goto end;
1490 }
1491
1492 break;
1493 }
46bdd3e0
PP
1494 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1495 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1496 {
1497 uint64_t i;
1498 uint64_t len;
a5e289cf 1499 struct fs_sink_ctf_field_class_struct *struct_fc = NULL;
5ccbae23 1500 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
46bdd3e0
PP
1501 struct fs_sink_ctf_named_field_class *named_fc;
1502
c5fe2e6f 1503 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
46bdd3e0
PP
1504 struct_fc = (void *) fc;
1505 len = struct_fc->members->len;
1506 } else {
1507 var_fc = (void *) fc;
1508 len = var_fc->options->len;
1509 ret = set_field_ref(fc, fc_name, parent_fc);
1510 if (ret) {
1511 goto end;
1512 }
1513 }
1514
1515 for (i = 0; i < len; i++) {
c5fe2e6f 1516 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
46bdd3e0
PP
1517 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1518 struct_fc, i);
1519 } else {
1520 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1521 var_fc, i);
1522 }
1523
1524 ret = set_field_refs(named_fc->fc, named_fc->name->str,
1525 fc);
1526 if (ret) {
1527 goto end;
1528 }
1529 }
1530
1531 break;
1532 }
1533 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
1534 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1535 {
1536 struct fs_sink_ctf_field_class_array_base *array_base_fc =
1537 (void *) fc;
1538
c5fe2e6f 1539 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
46bdd3e0
PP
1540 ret = set_field_ref(fc, fc_name, parent_fc);
1541 if (ret) {
1542 goto end;
1543 }
1544 }
1545
1546 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
1547 if (ret) {
1548 goto end;
1549 }
1550
1551 break;
1552 }
1553 default:
1554 break;
1555 }
1556
1557end:
1558 return ret;
1559}
1560
1561/*
1562 * This function translates a root scope trace IR field class to
1563 * a CTF IR field class.
1564 *
1565 * The resulting CTF IR field class is written to `*fc` so that it
1566 * exists as the parent object's (stream class or event class) true root
1567 * field class during the recursive translation for resolving purposes.
1568 * This is also why this function creates the empty structure field
1569 * class and then calls translate_structure_field_class_members() to
1570 * fill it.
1571 */
1572static
056995e5 1573int translate_scope_field_class(struct ctx *ctx, bt_field_path_scope scope,
46bdd3e0
PP
1574 struct fs_sink_ctf_field_class **fc,
1575 const bt_field_class *ir_fc)
1576{
1577 int ret = 0;
1578
1579 if (!ir_fc) {
1580 goto end;
1581 }
1582
1583 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
1584 BT_FIELD_CLASS_TYPE_STRUCTURE);
1585 BT_ASSERT(fc);
1586 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
1587 ir_fc, UINT64_C(-1));
1588 BT_ASSERT(*fc);
1589 ctx->cur_scope = scope;
1590 BT_ASSERT(ctx->cur_path->len == 0);
02b61fe0 1591 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
46bdd3e0 1592 if (ret) {
85623cd6 1593 BT_COMP_LOGE("Cannot translate scope structure field class: "
46bdd3e0
PP
1594 "scope=%d", scope);
1595 goto end;
1596 }
1597
1598 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
1599 if (ret) {
85623cd6 1600 BT_COMP_LOGE("Cannot translate scope structure field class: "
46bdd3e0
PP
1601 "scope=%d", scope);
1602 goto end;
1603 }
1604
1605 cur_path_stack_pop(ctx);
1606
1607 /* Set field refs for preceding targets */
1608 ret = set_field_refs(*fc, NULL, NULL);
1609
1610end:
1611 return ret;
1612}
1613
1614static inline
85623cd6 1615void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
46bdd3e0
PP
1616{
1617 memset(ctx, 0, sizeof(struct ctx));
1618 ctx->cur_path = g_array_new(FALSE, TRUE,
1619 sizeof(struct field_path_elem));
1620 BT_ASSERT(ctx->cur_path);
85623cd6
PP
1621 ctx->log_level = fs_sink->log_level;
1622 ctx->self_comp = fs_sink->self_comp;
46bdd3e0
PP
1623}
1624
1625static inline
1626void ctx_fini(struct ctx *ctx)
1627{
1628 if (ctx->cur_path) {
1629 g_array_free(ctx->cur_path, TRUE);
1630 ctx->cur_path = NULL;
1631 }
1632}
1633
1634static
85623cd6
PP
1635int translate_event_class(struct fs_sink_comp *fs_sink,
1636 struct fs_sink_ctf_stream_class *sc,
46bdd3e0 1637 const bt_event_class *ir_ec,
85623cd6 1638 struct fs_sink_ctf_event_class **out_ec)
46bdd3e0
PP
1639{
1640 int ret = 0;
1641 struct ctx ctx;
1642 struct fs_sink_ctf_event_class *ec;
1643
1644 BT_ASSERT(sc);
1645 BT_ASSERT(ir_ec);
1646
85623cd6 1647 ctx_init(&ctx, fs_sink);
46bdd3e0
PP
1648 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1649 BT_ASSERT(ec);
1650 ctx.cur_sc = sc;
1651 ctx.cur_ec = ec;
056995e5 1652 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT,
46bdd3e0
PP
1653 &ec->spec_context_fc,
1654 bt_event_class_borrow_specific_context_field_class_const(
1655 ir_ec));
1656 if (ret) {
1657 goto end;
1658 }
1659
056995e5 1660 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD,
46bdd3e0
PP
1661 &ec->payload_fc,
1662 bt_event_class_borrow_payload_field_class_const(ir_ec));
1663 if (ret) {
1664 goto end;
1665 }
1666
1667end:
1668 ctx_fini(&ctx);
1669 *out_ec = ec;
1670 return ret;
1671}
1672
1673BT_HIDDEN
1674int try_translate_event_class_trace_ir_to_ctf_ir(
85623cd6 1675 struct fs_sink_comp *fs_sink,
46bdd3e0
PP
1676 struct fs_sink_ctf_stream_class *sc,
1677 const bt_event_class *ir_ec,
85623cd6 1678 struct fs_sink_ctf_event_class **out_ec)
46bdd3e0
PP
1679{
1680 int ret = 0;
1681
1682 BT_ASSERT(sc);
1683 BT_ASSERT(ir_ec);
1684
1685 /* Check in hash table first */
1686 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
85e7137b 1687 if (G_LIKELY(*out_ec)) {
46bdd3e0
PP
1688 goto end;
1689 }
1690
85623cd6 1691 ret = translate_event_class(fs_sink, sc, ir_ec, out_ec);
46bdd3e0
PP
1692
1693end:
1694 return ret;
1695}
1696
f3847c75 1697static
cd03c43c 1698bool default_clock_class_name_exists(struct fs_sink_ctf_trace *trace,
46bdd3e0
PP
1699 const char *name)
1700{
1701 bool exists = false;
1702 uint64_t i;
1703
cd03c43c 1704 for (i = 0; i < trace->stream_classes->len; i++) {
46bdd3e0 1705 struct fs_sink_ctf_stream_class *sc =
cd03c43c 1706 trace->stream_classes->pdata[i];
46bdd3e0
PP
1707
1708 if (sc->default_clock_class_name->len == 0) {
1709 /* No default clock class */
1710 continue;
1711 }
1712
1713 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1714 exists = true;
1715 goto end;
1716 }
1717 }
1718
1719end:
1720 return exists;
1721}
1722
1723static
1724void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1725{
1726 unsigned int suffix = 0;
1727 char buf[16];
1728
1729 g_string_assign(sc->default_clock_class_name, "");
1730 sprintf(buf, "default");
1731
cd03c43c 1732 while (default_clock_class_name_exists(sc->trace, buf)) {
46bdd3e0
PP
1733 sprintf(buf, "default%u", suffix);
1734 suffix++;
1735 }
1736
1737 g_string_assign(sc->default_clock_class_name, buf);
1738}
1739
1740static
85623cd6 1741int translate_stream_class(struct fs_sink_comp *fs_sink,
cd03c43c 1742 struct fs_sink_ctf_trace *trace,
46bdd3e0 1743 const bt_stream_class *ir_sc,
85623cd6 1744 struct fs_sink_ctf_stream_class **out_sc)
46bdd3e0
PP
1745{
1746 int ret = 0;
1747 struct ctx ctx;
1748
cd03c43c 1749 BT_ASSERT(trace);
46bdd3e0 1750 BT_ASSERT(ir_sc);
85623cd6 1751 ctx_init(&ctx, fs_sink);
cd03c43c 1752 *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
46bdd3e0
PP
1753 BT_ASSERT(*out_sc);
1754
1755 /* Set default clock class's protected name, if any */
1756 if ((*out_sc)->default_clock_class) {
1757 const char *name = bt_clock_class_get_name(
1758 (*out_sc)->default_clock_class);
1759
46bdd3e0
PP
1760 if (name) {
1761 /* Try original name, protected */
02b61fe0
PP
1762 g_string_assign((*out_sc)->default_clock_class_name,
1763 "");
1764
1765 if (must_protect_identifier(name)) {
1766 g_string_assign(
1767 (*out_sc)->default_clock_class_name,
1768 "_");
1769 }
1770
46bdd3e0
PP
1771 g_string_assign((*out_sc)->default_clock_class_name,
1772 name);
02b61fe0
PP
1773 if (!ist_valid_identifier(
1774 (*out_sc)->default_clock_class_name->str)) {
46bdd3e0
PP
1775 /* Invalid: create a new name */
1776 make_unique_default_clock_class_name(*out_sc);
46bdd3e0
PP
1777 }
1778 } else {
1779 /* No name: create a name */
1780 make_unique_default_clock_class_name(*out_sc);
1781 }
1782 }
1783
1784 ctx.cur_sc = *out_sc;
056995e5 1785 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT,
46bdd3e0
PP
1786 &(*out_sc)->packet_context_fc,
1787 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1788 if (ret) {
1789 goto error;
1790 }
1791
1792 if ((*out_sc)->packet_context_fc) {
1793 /*
1794 * Make sure the structure field class's alignment is
1795 * enough: 8 is what we use for our own special members
1796 * in the packet context.
1797 */
1798 fs_sink_ctf_field_class_struct_align_at_least(
1799 (void *) (*out_sc)->packet_context_fc, 8);
1800 }
1801
056995e5 1802 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT,
46bdd3e0
PP
1803 &(*out_sc)->event_common_context_fc,
1804 bt_stream_class_borrow_event_common_context_field_class_const(
1805 ir_sc));
1806 if (ret) {
1807 goto error;
1808 }
1809
1810 goto end;
1811
1812error:
1813 fs_sink_ctf_stream_class_destroy(*out_sc);
1814 *out_sc = NULL;
1815
1816end:
1817 ctx_fini(&ctx);
1818 return ret;
1819}
1820
1821BT_HIDDEN
1822int try_translate_stream_class_trace_ir_to_ctf_ir(
85623cd6 1823 struct fs_sink_comp *fs_sink,
cd03c43c 1824 struct fs_sink_ctf_trace *trace,
46bdd3e0 1825 const bt_stream_class *ir_sc,
85623cd6 1826 struct fs_sink_ctf_stream_class **out_sc)
46bdd3e0
PP
1827{
1828 int ret = 0;
1829 uint64_t i;
1830
cd03c43c 1831 BT_ASSERT(trace);
46bdd3e0
PP
1832 BT_ASSERT(ir_sc);
1833
cd03c43c
PP
1834 for (i = 0; i < trace->stream_classes->len; i++) {
1835 *out_sc = trace->stream_classes->pdata[i];
46bdd3e0
PP
1836
1837 if ((*out_sc)->ir_sc == ir_sc) {
1838 goto end;
1839 }
1840 }
1841
cd03c43c 1842 ret = translate_stream_class(fs_sink, trace, ir_sc, out_sc);
46bdd3e0
PP
1843
1844end:
1845 return ret;
1846}
1847
1848BT_HIDDEN
cd03c43c
PP
1849struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(
1850 struct fs_sink_comp *fs_sink, const bt_trace *ir_trace)
46bdd3e0
PP
1851{
1852 uint64_t count;
1853 uint64_t i;
cd03c43c 1854 struct fs_sink_ctf_trace *trace = NULL;
46bdd3e0 1855
cd03c43c
PP
1856 /* Check that trace's environment is TSDL-compatible */
1857 count = bt_trace_get_environment_entry_count(ir_trace);
46bdd3e0
PP
1858 for (i = 0; i < count; i++) {
1859 const char *name;
1860 const bt_value *val;
1861
cd03c43c
PP
1862 bt_trace_borrow_environment_entry_by_index_const(
1863 ir_trace, i, &name, &val);
46bdd3e0 1864
02b61fe0 1865 if (!ist_valid_identifier(name)) {
85623cd6
PP
1866 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1867 fs_sink->self_comp,
a708ff31 1868 "Unsupported trace class's environment entry name: "
46bdd3e0
PP
1869 "name=\"%s\"", name);
1870 goto end;
1871 }
1872
1873 switch (bt_value_get_type(val)) {
68d9d039 1874 case BT_VALUE_TYPE_SIGNED_INTEGER:
46bdd3e0
PP
1875 case BT_VALUE_TYPE_STRING:
1876 break;
1877 default:
85623cd6
PP
1878 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1879 fs_sink->self_comp,
a708ff31 1880 "Unsupported trace class's environment entry value type: "
46bdd3e0
PP
1881 "type=%s",
1882 bt_common_value_type_string(
1883 bt_value_get_type(val)));
1884 goto end;
1885 }
1886 }
1887
cd03c43c
PP
1888 trace = fs_sink_ctf_trace_create(ir_trace);
1889 BT_ASSERT(trace);
46bdd3e0
PP
1890
1891end:
cd03c43c 1892 return trace;
46bdd3e0 1893}
This page took 0.137229 seconds and 4 git commands to generate.