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