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