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