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