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