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