lib: decouple variant FC option names from selector FC mapping names
[babeltrace.git] / src / plugins / ctf / fs-sink / translate-trace-ir-to-ctf-ir.c
CommitLineData
15fe47e0
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
aa1a7452 23#define BT_COMP_LOG_SELF_COMP (ctx->self_comp)
ffa3b2b3 24#define BT_LOG_OUTPUT_LEVEL (ctx->log_level)
350ad6c1 25#define BT_LOG_TAG "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"
aa1a7452 26#include "plugins/comp-logging.h"
15fe47e0 27
3fadfbc0 28#include <babeltrace2/babeltrace.h>
91d81473 29#include "common/macros.h"
578e048b
MJ
30#include "common/common.h"
31#include "common/assert.h"
15fe47e0
PP
32#include <stdio.h>
33#include <stdbool.h>
34#include <string.h>
35#include <glib.h>
36
aa1a7452 37#include "fs-sink.h"
15fe47e0
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 {
ffa3b2b3 52 bt_logging_level log_level;
aa1a7452 53 bt_self_component *self_comp;
ffa3b2b3 54
15fe47e0
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
61 bt_scope cur_scope;
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
45c51519
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
15fe47e0
PP
197static inline
198int cur_path_stack_push(struct ctx *ctx,
45c51519
PP
199 uint64_t index_in_parent, const char *name,
200 bool force_protect_name, const bt_field_class *ir_fc,
15fe47e0
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;
45c51519
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);
15fe47e0 217
15fe47e0 218 if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) {
45c51519
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")) {
aa1a7452 225 BT_COMP_LOGE("Unsupported reserved TSDL structure field class member "
15fe47e0 226 "or variant field class option name: name=\"%s\"",
45c51519 227 name);
15fe47e0
PP
228 ret = -1;
229 goto end;
230 }
231 }
232
45c51519
PP
233 if (!ist_valid_identifier(field_path_elem->name->str)) {
234 ret = -1;
aa1a7452 235 BT_COMP_LOGE("Unsupported non-TSDL structure field class member "
15fe47e0 236 "or variant field class option name: name=\"%s\"",
45c51519 237 field_path_elem->name->str);
15fe47e0
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
15fe47e0
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,
45c51519
PP
279 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
280 struct fs_sink_ctf_field_class **user_tgt_fc)
15fe47e0
PP
281{
282 int ret = 0;
283 struct fs_sink_ctf_field_class *tgt_fc = NULL;
284 uint64_t i;
285 int64_t si;
e8806f78 286 const char *tgt_fc_name = NULL;
15fe47e0
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)) {
291 case BT_SCOPE_PACKET_CONTEXT:
292 BT_ASSERT(ctx->cur_sc);
293 tgt_fc = ctx->cur_sc->packet_context_fc;
294 break;
295 case BT_SCOPE_EVENT_COMMON_CONTEXT:
296 BT_ASSERT(ctx->cur_sc);
297 tgt_fc = ctx->cur_sc->event_common_context_fc;
298 break;
299 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
300 BT_ASSERT(ctx->cur_ec);
301 tgt_fc = ctx->cur_ec->spec_context_fc;
302 break;
303 case BT_SCOPE_EVENT_PAYLOAD:
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
66ddcddf
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);
15fe47e0
PP
317 struct fs_sink_ctf_named_field_class *named_fc = NULL;
318
319 BT_ASSERT(tgt_fc);
66ddcddf 320 BT_ASSERT(fp_item);
15fe47e0 321
00f1e7d3 322 switch (tgt_fc->type) {
15fe47e0 323 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
66ddcddf
PP
324 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
325 BT_FIELD_PATH_ITEM_TYPE_INDEX);
15fe47e0 326 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
66ddcddf
PP
327 (void *) tgt_fc,
328 bt_field_path_item_index_get_index(fp_item));
15fe47e0
PP
329 break;
330 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
66ddcddf
PP
331 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
332 BT_FIELD_PATH_ITEM_TYPE_INDEX);
15fe47e0 333 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
66ddcddf
PP
334 (void *) tgt_fc,
335 bt_field_path_item_index_get_index(fp_item));
15fe47e0
PP
336 break;
337 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
338 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
339 {
340 struct fs_sink_ctf_field_class_array_base *array_base_fc =
341 (void *) tgt_fc;
342
66ddcddf
PP
343 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
344 BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
15fe47e0
PP
345 tgt_fc = array_base_fc->elem_fc;
346 break;
347 }
348 default:
349 abort();
350 }
351
352 if (named_fc) {
353 tgt_fc = named_fc->fc;
354 tgt_fc_name = named_fc->name->str;
355 i++;
356 }
357 }
358
359 BT_ASSERT(tgt_fc);
00f1e7d3 360 BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
15fe47e0
PP
361 BT_ASSERT(tgt_fc_name);
362
363 /* Find target field class having this name in current context */
364 for (si = ctx->cur_path->len - 1; si >= 0; si--) {
365 struct fs_sink_ctf_field_class *fc;
366 struct fs_sink_ctf_field_class_struct *struct_fc;
367 struct fs_sink_ctf_field_class_variant *var_fc;
368 struct fs_sink_ctf_named_field_class *named_fc;
369 uint64_t len;
370
371 field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
372 fc = field_path_elem->parent_fc;
373 if (!fc) {
374 /* Reached stack's bottom */
375 ret = -1;
376 goto end;
377 }
378
379 switch (fc->type) {
380 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
381 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
382 break;
383 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
384 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
385 continue;
386 default:
387 /* Not supported by TSDL 1.8 */
388 ret = -1;
389 goto end;
390 }
391
392 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
393 struct_fc = (void *) fc;
394 len = struct_fc->members->len;
395 } else {
396 var_fc = (void *) fc;
397 len = var_fc->options->len;
398 }
399
400 for (i = 0; i < len; i++) {
401 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
402 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
403 struct_fc, i);
404 } else {
405 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
406 var_fc, i);
407 }
408
409 if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
410 if (named_fc->fc == tgt_fc) {
411 g_string_assign(tgt_field_ref,
412 tgt_fc_name);
45c51519
PP
413
414 if (user_tgt_fc) {
415 *user_tgt_fc = tgt_fc;
416 }
15fe47e0
PP
417 } else {
418 /*
419 * Using only the target field
420 * class's name, we're not
421 * reaching the target field
422 * class. This is not supported
423 * by TSDL 1.8.
424 */
425 ret = -1;
426 }
427
428 goto end;
429 }
430 }
431 }
432
433end:
434 return ret;
435}
436
437/*
438 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
439 *
440 * Returns a negative value if this resolving operation failed.
441 */
442static
443int create_absolute_field_ref(struct ctx *ctx,
45c51519
PP
444 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
445 struct fs_sink_ctf_field_class **user_tgt_fc)
15fe47e0
PP
446{
447 int ret = 0;
448 struct fs_sink_ctf_field_class *fc = NULL;
449 uint64_t i;
450
451 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
452 case BT_SCOPE_PACKET_CONTEXT:
453 BT_ASSERT(ctx->cur_sc);
454 fc = ctx->cur_sc->packet_context_fc;
455 g_string_assign(tgt_field_ref, "stream.packet.context");
456 break;
457 case BT_SCOPE_EVENT_COMMON_CONTEXT:
458 BT_ASSERT(ctx->cur_sc);
459 fc = ctx->cur_sc->event_common_context_fc;
460 g_string_assign(tgt_field_ref, "stream.event.context");
461 break;
462 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
463 BT_ASSERT(ctx->cur_ec);
464 fc = ctx->cur_ec->spec_context_fc;
465 g_string_assign(tgt_field_ref, "event.context");
466 break;
467 case BT_SCOPE_EVENT_PAYLOAD:
468 BT_ASSERT(ctx->cur_ec);
469 fc = ctx->cur_ec->payload_fc;
470 g_string_assign(tgt_field_ref, "event.fields");
471 break;
472 default:
473 abort();
474 }
475
476 BT_ASSERT(fc);
477
66ddcddf
PP
478 for (i = 0; i < bt_field_path_get_item_count(tgt_ir_field_path); i++) {
479 const bt_field_path_item *fp_item =
480 bt_field_path_borrow_item_by_index_const(
481 tgt_ir_field_path, i);
15fe47e0
PP
482 struct fs_sink_ctf_named_field_class *named_fc = NULL;
483
66ddcddf
PP
484 if (bt_field_path_item_get_type(fp_item) !=
485 BT_FIELD_PATH_ITEM_TYPE_INDEX) {
486 /* Not supported by TSDL 1.8 */
487 ret = -1;
488 goto end;
489 }
490
15fe47e0
PP
491 switch (fc->type) {
492 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
66ddcddf
PP
493 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
494 BT_FIELD_PATH_ITEM_TYPE_INDEX);
15fe47e0 495 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
66ddcddf
PP
496 (void *) fc,
497 bt_field_path_item_index_get_index(fp_item));
15fe47e0
PP
498 break;
499 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
66ddcddf
PP
500 BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
501 BT_FIELD_PATH_ITEM_TYPE_INDEX);
15fe47e0 502 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
66ddcddf
PP
503 (void *) fc,
504 bt_field_path_item_index_get_index(fp_item));
15fe47e0 505 break;
15fe47e0
PP
506 default:
507 abort();
508 }
509
510 BT_ASSERT(named_fc);
511 g_string_append_c(tgt_field_ref, '.');
512 g_string_append(tgt_field_ref, named_fc->name->str);
513 fc = named_fc->fc;
514 }
515
45c51519
PP
516 if (user_tgt_fc) {
517 *user_tgt_fc = fc;
518 }
519
15fe47e0
PP
520end:
521 return ret;
522}
523
524/*
525 * Resolves a target field class located at `tgt_ir_field_path`, writing
526 * the resolved field ref to `tgt_field_ref` and setting
527 * `*create_before` according to whether or not the target field must be
528 * created immediately before (in which case `tgt_field_ref` is
529 * irrelevant).
530 */
531static
532void resolve_field_class(struct ctx *ctx,
533 const bt_field_path *tgt_ir_field_path,
45c51519
PP
534 GString *tgt_field_ref, bool *create_before,
535 struct fs_sink_ctf_field_class **user_tgt_fc)
15fe47e0
PP
536{
537 int ret;
538 bt_scope tgt_scope;
539
540 *create_before = false;
541
542 if (!tgt_ir_field_path) {
543 *create_before = true;
544 goto end;
545 }
546
547 tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
548
549 if (tgt_scope == ctx->cur_scope) {
550 /*
551 * Try, in this order:
552 *
553 * 1. Use a relative path, using only the target field
554 * class's name. This is what is the most commonly
555 * supported by popular CTF reading tools.
556 *
557 * 2. Use an absolute path. This could fail if there's
558 * an array field class from the current root's field
559 * class to the target field class.
560 *
561 * 3. Create the target field class before the
562 * requesting field class (fallback).
563 */
564 ret = create_relative_field_ref(ctx, tgt_ir_field_path,
45c51519 565 tgt_field_ref, user_tgt_fc);
15fe47e0
PP
566 if (ret) {
567 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
45c51519 568 tgt_field_ref, user_tgt_fc);
15fe47e0
PP
569 if (ret) {
570 *create_before = true;
571 ret = 0;
572 goto end;
573 }
574 }
575 } else {
576 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
45c51519 577 tgt_field_ref, user_tgt_fc);
15fe47e0
PP
578
579 /* It must always work in previous scopes */
580 BT_ASSERT(ret == 0);
581 }
582
583end:
584 return;
585}
586
587static
588int translate_field_class(struct ctx *ctx);
589
590static inline
591void append_to_parent_field_class(struct ctx *ctx,
592 struct fs_sink_ctf_field_class *fc)
593{
594 struct fs_sink_ctf_field_class *parent_fc =
595 cur_path_stack_top(ctx)->parent_fc;
596
597 switch (parent_fc->type) {
598 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
599 fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
600 cur_path_stack_top(ctx)->name->str, fc);
601 break;
602 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
603 fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
604 cur_path_stack_top(ctx)->name->str, fc);
605 break;
606 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
607 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
608 {
609 struct fs_sink_ctf_field_class_array_base *array_base_fc =
610 (void *) parent_fc;
611
612 BT_ASSERT(!array_base_fc->elem_fc);
613 array_base_fc->elem_fc = fc;
614 array_base_fc->base.alignment = fc->alignment;
615 break;
616 }
617 default:
618 abort();
619 }
620}
621
622static inline
623void update_parent_field_class_alignment(struct ctx *ctx,
624 unsigned int alignment)
625{
626 struct fs_sink_ctf_field_class *parent_fc =
627 cur_path_stack_top(ctx)->parent_fc;
628
629 switch (parent_fc->type) {
630 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
631 fs_sink_ctf_field_class_struct_align_at_least(
632 (void *) parent_fc, alignment);
633 break;
634 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
635 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
636 {
637 struct fs_sink_ctf_field_class_array_base *array_base_fc =
638 (void *) parent_fc;
639
640 array_base_fc->base.alignment = alignment;
641 break;
642 }
643 default:
644 break;
645 }
646}
647
648static inline
649int translate_structure_field_class_members(struct ctx *ctx,
650 struct fs_sink_ctf_field_class_struct *struct_fc,
651 const bt_field_class *ir_fc)
652{
653 int ret = 0;
654 uint64_t i;
655
656 for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
657 const bt_field_class_structure_member *member;
658 const char *name;
659 const bt_field_class *memb_ir_fc;
660
661 member =
662 bt_field_class_structure_borrow_member_by_index_const(
663 ir_fc, i);
664 name = bt_field_class_structure_member_get_name(member);
665 memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
666 member);
45c51519 667 ret = cur_path_stack_push(ctx, i, name, true, memb_ir_fc,
15fe47e0
PP
668 (void *) struct_fc);
669 if (ret) {
aa1a7452 670 BT_COMP_LOGE("Cannot translate structure field class member: "
15fe47e0
PP
671 "name=\"%s\"", name);
672 goto end;
673 }
674
675 ret = translate_field_class(ctx);
676 if (ret) {
aa1a7452 677 BT_COMP_LOGE("Cannot translate structure field class member: "
15fe47e0
PP
678 "name=\"%s\"", name);
679 goto end;
680 }
681
682 cur_path_stack_pop(ctx);
683 }
684
685end:
686 return ret;
687}
688
689static inline
690int translate_structure_field_class(struct ctx *ctx)
691{
692 int ret;
693 struct fs_sink_ctf_field_class_struct *fc =
694 fs_sink_ctf_field_class_struct_create_empty(
695 cur_path_stack_top(ctx)->ir_fc,
696 cur_path_stack_top(ctx)->index_in_parent);
697
698 BT_ASSERT(fc);
699 append_to_parent_field_class(ctx, (void *) fc);
700 ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
701 if (ret) {
702 goto end;
703 }
704
705 update_parent_field_class_alignment(ctx, fc->base.alignment);
706
707end:
708 return ret;
709}
710
45c51519
PP
711/*
712 * This function returns whether or not a given field class `tag_fc`
713 * is valid as the tag field class of the variant field class `fc`.
714 *
715 * CTF 1.8 requires that the tag field class be an enumeration field
716 * class and that, for each variant field class option's range set, the
717 * tag field class contains a mapping which has the option's name and an
718 * equal range set.
719 */
720static inline
721bool _is_variant_field_class_tag_valid(
722 struct fs_sink_ctf_field_class_variant *fc,
723 struct fs_sink_ctf_field_class *tag_fc)
724{
725 bool is_valid = true;
726 bt_field_class_type ir_tag_fc_type = bt_field_class_get_type(
727 tag_fc->ir_fc);
728 uint64_t i;
729 GString *escaped_opt_name = g_string_new(NULL);
730
731 BT_ASSERT(escaped_opt_name);
732
733 if (ir_tag_fc_type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION &&
734 ir_tag_fc_type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
735 is_valid = false;
736 goto end;
737 }
738
739 for (i = 0; i < bt_field_class_variant_get_option_count(
740 fc->base.ir_fc); i++) {
741 const bt_field_class_variant_option *var_opt_base =
742 bt_field_class_variant_borrow_option_by_index_const(
743 fc->base.ir_fc, i);
744 const char *opt_name = bt_field_class_variant_option_get_name(
745 var_opt_base);
746
747 /*
748 * If the option is named `name` in trace IR, then it
749 * was _possibly_ named `_name` originally if it comes
750 * from `src.ctf.fs`. This means the corresponding
751 * enumeration field class mapping was also named
752 * `_name`, but this one didn't change, as enumeration
753 * FC mapping names are not escaped; they are literal
754 * strings.
755 *
756 * The `sink.ctf.fs` component escapes all the variant
757 * FC option names with `_`. Therefore the
758 * _escaped name_ must match the original enumeration
759 * FC mapping name.
760 */
761 g_string_assign(escaped_opt_name, "_");
762 g_string_append(escaped_opt_name, opt_name);
763
764 if (ir_tag_fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
765 const bt_field_class_variant_with_unsigned_selector_option *var_opt =
766 bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const(
767 fc->base.ir_fc, i);
768 const bt_field_class_unsigned_enumeration_mapping *mapping;
769 const bt_integer_range_set_unsigned *opt_ranges;
770 const bt_integer_range_set_unsigned *mapping_ranges;
771
772 mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_label_const(
773 tag_fc->ir_fc, escaped_opt_name->str);
774 if (!mapping) {
775 is_valid = false;
776 goto end;
777 }
778
779 opt_ranges = bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const(
780 var_opt);
781 mapping_ranges = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const(
782 mapping);
783 if (!bt_integer_range_set_unsigned_compare(opt_ranges,
784 mapping_ranges)) {
785 is_valid = false;
786 goto end;
787 }
788 } else {
789 const bt_field_class_variant_with_signed_selector_option *var_opt =
790 bt_field_class_variant_with_signed_selector_borrow_option_by_index_const(
791 fc->base.ir_fc, i);
792 const bt_field_class_signed_enumeration_mapping *mapping;
793 const bt_integer_range_set_signed *opt_ranges;
794 const bt_integer_range_set_signed *mapping_ranges;
795
796 mapping = bt_field_class_signed_enumeration_borrow_mapping_by_label_const(
797 tag_fc->ir_fc, escaped_opt_name->str);
798 if (!mapping) {
799 is_valid = false;
800 goto end;
801 }
802
803 opt_ranges = bt_field_class_variant_with_signed_selector_option_borrow_ranges_const(
804 var_opt);
805 mapping_ranges = bt_field_class_signed_enumeration_mapping_borrow_ranges_const(
806 mapping);
807 if (!bt_integer_range_set_signed_compare(opt_ranges,
808 mapping_ranges)) {
809 is_valid = false;
810 goto end;
811 }
812 }
813 }
814
815end:
816 return is_valid;
817}
818
819/*
820 * This function indicates whether or not a given variant FC option name
821 * must be protected (with the `_` prefix).
822 *
823 * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
824 * close as possible to an original CTF trace as decoded by
825 * `src.ctf.fs`.
826 *
827 * This scenario is valid in CTF 1.8:
828 *
829 * enum {
830 * HELLO,
831 * MEOW
832 * } tag;
833 *
834 * variant <tag> {
835 * int HELLO;
836 * string MEOW;
837 * };
838 *
839 * Once in trace IR, the enumeration FC mapping names and variant FC
840 * option names are kept as is. For this reason, we don't want to
841 * protect the variant FC option names here (by prepending `_`): this
842 * would make the variant FC option name and the enumeration FC mapping
843 * name not match.
844 *
845 * This scenario is also valid in CTF 1.8:
846 *
847 * enum {
848 * _HELLO,
849 * MEOW
850 * } tag;
851 *
852 * variant <tag> {
853 * int _HELLO;
854 * string MEOW;
855 * };
856 *
857 * Once in trace IR, the enumeration FC mapping names are kept as is,
858 * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
859 * for presentation, as recommended by CTF 1.8). When going back to
860 * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
861 * the corresponding enumeration FC mapping name.
862 *
863 * This scenario is also valid in CTF 1.8:
864 *
865 * enum {
866 * __HELLO,
867 * MEOW
868 * } tag;
869 *
870 * variant <tag> {
871 * int __HELLO;
872 * string MEOW;
873 * };
874 *
875 * Once in trace IR, the enumeration FC mapping names are kept as is,
876 * but the `__HELLO` variant FC option name becomes `_HELLO`
877 * (unprotected). When going back to TSDL, we need to protect `_HELLO`
878 * so that it becomes `__HELLO` to match the corresponding enumeration
879 * FC mapping name.
880 *
881 * `src.ctf.fs` always uses the _same_ integer range sets for a selector
882 * FC mapping and a corresponding variant FC option. We can use that
883 * fact to find the original variant FC option names by matching variant
884 * FC options and enumeration FC mappings by range set.
885 */
886static
887int must_protect_variant_option_name(const bt_field_class *ir_var_fc,
888 const bt_field_class *ir_tag_fc, uint64_t opt_i,
889 GString *name_buf, bool *must_protect)
890{
891 int ret = 0;
892 uint64_t i;
893 bt_field_class_type ir_var_fc_type;
894 const void *opt_ranges = NULL;
895 const char *mapping_label = NULL;
896 const char *ir_opt_name;
897 const bt_field_class_variant_option *base_var_opt;
898 bool force_protect = false;
899
900 *must_protect = false;
901 ir_var_fc_type = bt_field_class_get_type(ir_var_fc);
902 base_var_opt = bt_field_class_variant_borrow_option_by_index_const(
903 ir_var_fc, opt_i);
904 BT_ASSERT(base_var_opt);
905 ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt);
906 BT_ASSERT(ir_opt_name);
907
908 /*
909 * Check if the variant FC option name is required to be
910 * protected (reserved TSDL keyword or starts with `_`). In that
911 * case, the name of the selector FC mapping we find must match
912 * exactly the protected name.
913 */
914 force_protect = must_protect_identifier(ir_opt_name);
915 if (force_protect) {
916 *must_protect = true;
917 g_string_assign(name_buf, "_");
918 g_string_append(name_buf, ir_opt_name);
919 } else {
920 g_string_assign(name_buf, ir_opt_name);
921 }
922
923 /* Borrow option's ranges */
924 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR) {
925 /* No ranges: we're done */
926 goto end;
927 } if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) {
928 const bt_field_class_variant_with_unsigned_selector_option *var_opt =
929 bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const(
930 ir_var_fc, opt_i);
931 opt_ranges =
932 bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const(
933 var_opt);
934 } else {
935 const bt_field_class_variant_with_signed_selector_option *var_opt =
936 bt_field_class_variant_with_signed_selector_borrow_option_by_index_const(
937 ir_var_fc, opt_i);
938 opt_ranges =
939 bt_field_class_variant_with_signed_selector_option_borrow_ranges_const(
940 var_opt);
941 }
942
943 /* Find corresponding mapping by range set in selector FC */
944 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_tag_fc);
945 i++) {
946 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) {
947 const bt_field_class_enumeration_mapping *mapping_base;
948 const bt_field_class_unsigned_enumeration_mapping *mapping;
949 const bt_integer_range_set_unsigned *mapping_ranges;
950
951 mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
952 ir_tag_fc, i);
953 mapping_ranges = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const(
954 mapping);
955
956 if (bt_integer_range_set_unsigned_compare(opt_ranges,
957 mapping_ranges)) {
958 /* We have a winner */
959 mapping_base =
960 bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
961 mapping);
962 mapping_label =
963 bt_field_class_enumeration_mapping_get_label(
964 mapping_base);
965 break;
966 }
967 } else {
968 const bt_field_class_enumeration_mapping *mapping_base;
969 const bt_field_class_signed_enumeration_mapping *mapping;
970 const bt_integer_range_set_signed *mapping_ranges;
971
972 mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
973 ir_tag_fc, i);
974 mapping_ranges = bt_field_class_signed_enumeration_mapping_borrow_ranges_const(
975 mapping);
976
977 if (bt_integer_range_set_signed_compare(opt_ranges,
978 mapping_ranges)) {
979 /* We have a winner */
980 mapping_base =
981 bt_field_class_signed_enumeration_mapping_as_mapping_const(
982 mapping);
983 mapping_label =
984 bt_field_class_enumeration_mapping_get_label(
985 mapping_base);
986 break;
987 }
988 }
989 }
990
991 if (!mapping_label) {
992 /* Range set not found: invalid selector for CTF 1.8 */
993 ret = -1;
994 goto end;
995 }
996
997 /*
998 * If the enumeration FC mapping name is not the same as the
999 * variant FC option name and we didn't protect already, try
1000 * protecting the option name and check again.
1001 */
1002 if (strcmp(mapping_label, name_buf->str) != 0) {
1003 if (force_protect) {
1004 ret = -1;
1005 goto end;
1006 }
1007
1008 if (mapping_label[0] == '\0') {
1009 ret = -1;
1010 goto end;
1011 }
1012
1013 g_string_assign(name_buf, "_");
1014 g_string_append(name_buf, ir_opt_name);
1015
1016 if (strcmp(mapping_label, name_buf->str) != 0) {
1017 ret = -1;
1018 goto end;
1019 }
1020
1021 /*
1022 * If this comes from a `src.ctf.fs` source, it looks
1023 * like the variant FC option name was initially
1024 * protected: protect it again when going back to TSDL.
1025 */
1026 *must_protect = true;
1027 }
1028
1029end:
1030 return ret;
1031}
1032
15fe47e0
PP
1033static inline
1034int translate_variant_field_class(struct ctx *ctx)
1035{
1036 int ret = 0;
1037 uint64_t i;
1038 struct fs_sink_ctf_field_class_variant *fc =
1039 fs_sink_ctf_field_class_variant_create_empty(
1040 cur_path_stack_top(ctx)->ir_fc,
1041 cur_path_stack_top(ctx)->index_in_parent);
45c51519
PP
1042 bt_field_class_type ir_fc_type;
1043 const bt_field_path *ir_selector_field_path = NULL;
1044 struct fs_sink_ctf_field_class *tgt_fc = NULL;
1045 GString *name_buf = g_string_new(NULL);
1046 bt_value *prot_opt_names = bt_value_array_create();
1047 uint64_t opt_count;
15fe47e0
PP
1048
1049 BT_ASSERT(fc);
45c51519
PP
1050 BT_ASSERT(name_buf);
1051 BT_ASSERT(prot_opt_names);
1052 ir_fc_type = bt_field_class_get_type(fc->base.ir_fc);
1053 opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc);
1054
1055 if (ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR ||
1056 ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) {
1057 ir_selector_field_path = bt_field_class_variant_with_selector_borrow_selector_field_path_const(
1058 fc->base.ir_fc);
1059 BT_ASSERT(ir_selector_field_path);
1060 }
15fe47e0
PP
1061
1062 /* Resolve tag field class before appending to parent */
45c51519
PP
1063 resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref,
1064 &fc->tag_is_before, &tgt_fc);
1065
1066 if (ir_selector_field_path && tgt_fc) {
1067 uint64_t mapping_count;
1068 uint64_t option_count;
1069
1070 /* CTF 1.8: selector FC must be an enumeration FC */
1071 bt_field_class_type type = bt_field_class_get_type(
1072 tgt_fc->ir_fc);
1073
1074 if (type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION &&
1075 type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
1076 fc->tag_is_before = true;
1077 goto validate_opts;
1078 }
1079
1080 /*
1081 * Call must_protect_variant_option_name() for each
1082 * option below. In that case we also want selector FC
1083 * to contain as many mappings as the variant FC has
1084 * options.
1085 */
1086 mapping_count = bt_field_class_enumeration_get_mapping_count(
1087 tgt_fc->ir_fc);
1088 option_count = bt_field_class_variant_get_option_count(
1089 fc->base.ir_fc);
1090
1091 if (mapping_count != option_count) {
1092 fc->tag_is_before = true;
1093 goto validate_opts;
1094 }
1095 } else {
1096 /*
1097 * No compatible selector field class for CTF 1.8:
1098 * create the appropriate selector field class.
1099 */
1100 fc->tag_is_before = true;
1101 }
1102
1103validate_opts:
1104 /*
1105 * First pass: detect any option name clash with option name
1106 * protection. In that case, we don't fail: just create the
1107 * selector field class before the variant field class.
1108 *
1109 * After this, `prot_opt_names` contains the final option names,
1110 * potentially protected if needed. They can still be invalid
1111 * TSDL identifiers however; this will be checked by
1112 * cur_path_stack_push().
1113 */
1114 for (i = 0; i < opt_count; i++) {
1115 bool must_protect = false;
1116
1117 ret = must_protect_variant_option_name(fc->base.ir_fc,
1118 tgt_fc->ir_fc, i, name_buf, &must_protect);
1119 if (ret) {
1120 fc->tag_is_before = true;
1121 }
1122
1123 ret = bt_value_array_append_string_element(prot_opt_names,
1124 name_buf->str);
1125 if (ret) {
1126 goto end;
1127 }
1128 }
1129
1130 for (i = 0; i < opt_count; i++) {
1131 uint64_t j;
1132 const bt_value *opt_name_a =
1133 bt_value_array_borrow_element_by_index_const(
1134 prot_opt_names, i);
1135
1136 for (j = 0; j < opt_count; j++) {
1137 const bt_value *opt_name_b;
1138
1139 if (i == j) {
1140 continue;
1141 }
15fe47e0 1142
45c51519
PP
1143 opt_name_b =
1144 bt_value_array_borrow_element_by_index_const(
1145 prot_opt_names, j);
1146 if (bt_value_compare(opt_name_a, opt_name_b)) {
1147 /*
1148 * Variant FC option names are not
1149 * unique when protected.
1150 */
1151 fc->tag_is_before = true;
1152 goto append_to_parent;
1153 }
1154 }
1155 }
1156
1157append_to_parent:
15fe47e0
PP
1158 append_to_parent_field_class(ctx, (void *) fc);
1159
45c51519 1160 for (i = 0; i < opt_count; i++) {
15fe47e0 1161 const bt_field_class_variant_option *opt;
15fe47e0 1162 const bt_field_class *opt_ir_fc;
45c51519
PP
1163 const bt_value *prot_opt_name_val =
1164 bt_value_array_borrow_element_by_index_const(
1165 prot_opt_names, i);
1166 const char *prot_opt_name = bt_value_string_get(
1167 prot_opt_name_val);
15fe47e0 1168
45c51519 1169 BT_ASSERT(prot_opt_name);
15fe47e0
PP
1170 opt = bt_field_class_variant_borrow_option_by_index_const(
1171 fc->base.ir_fc, i);
15fe47e0
PP
1172 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
1173 opt);
45c51519
PP
1174
1175 /*
1176 * We don't ask cur_path_stack_push() to protect the
1177 * option name because it's already protected at this
1178 * point.
1179 */
1180 ret = cur_path_stack_push(ctx, i, prot_opt_name, false,
1181 opt_ir_fc, (void *) fc);
15fe47e0 1182 if (ret) {
aa1a7452 1183 BT_COMP_LOGE("Cannot translate variant field class option: "
45c51519 1184 "name=\"%s\"", prot_opt_name);
15fe47e0
PP
1185 goto end;
1186 }
1187
1188 ret = translate_field_class(ctx);
1189 if (ret) {
aa1a7452 1190 BT_COMP_LOGE("Cannot translate variant field class option: "
45c51519 1191 "name=\"%s\"", prot_opt_name);
15fe47e0
PP
1192 goto end;
1193 }
1194
1195 cur_path_stack_pop(ctx);
1196 }
1197
1198end:
45c51519
PP
1199 if (name_buf) {
1200 g_string_free(name_buf, TRUE);
1201 }
1202
1203 bt_value_put_ref(prot_opt_names);
15fe47e0
PP
1204 return ret;
1205}
1206
1207static inline
1208int translate_static_array_field_class(struct ctx *ctx)
1209{
1210 struct fs_sink_ctf_field_class_array *fc =
1211 fs_sink_ctf_field_class_array_create_empty(
1212 cur_path_stack_top(ctx)->ir_fc,
1213 cur_path_stack_top(ctx)->index_in_parent);
1214 const bt_field_class *elem_ir_fc =
1215 bt_field_class_array_borrow_element_field_class_const(
1216 fc->base.base.ir_fc);
1217 int ret;
1218
1219 BT_ASSERT(fc);
1220 append_to_parent_field_class(ctx, (void *) fc);
45c51519 1221 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
15fe47e0
PP
1222 (void *) fc);
1223 if (ret) {
aa1a7452 1224 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
15fe47e0
PP
1225 goto end;
1226 }
1227
1228 ret = translate_field_class(ctx);
1229 if (ret) {
aa1a7452 1230 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
15fe47e0
PP
1231 goto end;
1232 }
1233
1234 cur_path_stack_pop(ctx);
1235 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1236
1237end:
1238 return ret;
1239}
1240
1241static inline
1242int translate_dynamic_array_field_class(struct ctx *ctx)
1243{
1244 struct fs_sink_ctf_field_class_sequence *fc =
1245 fs_sink_ctf_field_class_sequence_create_empty(
1246 cur_path_stack_top(ctx)->ir_fc,
1247 cur_path_stack_top(ctx)->index_in_parent);
1248 const bt_field_class *elem_ir_fc =
1249 bt_field_class_array_borrow_element_field_class_const(
1250 fc->base.base.ir_fc);
1251 int ret;
1252
1253 BT_ASSERT(fc);
1254
1255 /* Resolve length field class before appending to parent */
1256 resolve_field_class(ctx,
1257 bt_field_class_dynamic_array_borrow_length_field_path_const(
1258 fc->base.base.ir_fc),
45c51519 1259 fc->length_ref, &fc->length_is_before, NULL);
15fe47e0
PP
1260
1261 append_to_parent_field_class(ctx, (void *) fc);
45c51519 1262 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
15fe47e0
PP
1263 (void *) fc);
1264 if (ret) {
aa1a7452 1265 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
15fe47e0
PP
1266 goto end;
1267 }
1268
1269 ret = translate_field_class(ctx);
1270 if (ret) {
aa1a7452 1271 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
15fe47e0
PP
1272 goto end;
1273 }
1274
1275 cur_path_stack_pop(ctx);
1276 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1277
1278end:
1279 return ret;
1280}
1281
1282static inline
1283int translate_integer_field_class(struct ctx *ctx)
1284{
1285 struct fs_sink_ctf_field_class_int *fc =
1286 fs_sink_ctf_field_class_int_create(
1287 cur_path_stack_top(ctx)->ir_fc,
1288 cur_path_stack_top(ctx)->index_in_parent);
1289
1290 BT_ASSERT(fc);
1291 append_to_parent_field_class(ctx, (void *) fc);
1292 return 0;
1293}
1294
1295static inline
1296int translate_real_field_class(struct ctx *ctx)
1297{
1298 struct fs_sink_ctf_field_class_float *fc =
1299 fs_sink_ctf_field_class_float_create(
1300 cur_path_stack_top(ctx)->ir_fc,
1301 cur_path_stack_top(ctx)->index_in_parent);
1302
1303 BT_ASSERT(fc);
1304 append_to_parent_field_class(ctx, (void *) fc);
1305 return 0;
1306}
1307
1308static inline
1309int translate_string_field_class(struct ctx *ctx)
1310{
1311 struct fs_sink_ctf_field_class_string *fc =
1312 fs_sink_ctf_field_class_string_create(
1313 cur_path_stack_top(ctx)->ir_fc,
1314 cur_path_stack_top(ctx)->index_in_parent);
1315
1316 BT_ASSERT(fc);
1317 append_to_parent_field_class(ctx, (void *) fc);
1318 return 0;
1319}
1320
1321/*
1322 * Translates a field class, recursively.
1323 *
1324 * The field class's IR field class, parent field class, and index
1325 * within its parent are in the context's current path's top element
1326 * (cur_path_stack_top()).
1327 */
1328static
1329int translate_field_class(struct ctx *ctx)
1330{
1331 int ret;
1332
1333 switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
1334 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
1335 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
1336 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1337 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1338 ret = translate_integer_field_class(ctx);
1339 break;
1340 case BT_FIELD_CLASS_TYPE_REAL:
1341 ret = translate_real_field_class(ctx);
1342 break;
1343 case BT_FIELD_CLASS_TYPE_STRING:
1344 ret = translate_string_field_class(ctx);
1345 break;
1346 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1347 ret = translate_structure_field_class(ctx);
1348 break;
1349 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1350 ret = translate_static_array_field_class(ctx);
1351 break;
1352 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1353 ret = translate_dynamic_array_field_class(ctx);
1354 break;
45c51519
PP
1355 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
1356 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
1357 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
15fe47e0
PP
1358 ret = translate_variant_field_class(ctx);
1359 break;
1360 default:
1361 abort();
1362 }
1363
1364 return ret;
1365}
1366
1367static
1368int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
1369 struct fs_sink_ctf_field_class *parent_fc)
1370{
1371 int ret = 0;
1372 GString *field_ref = NULL;
1373 bool is_before;
1374 const char *tgt_type;
1375 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
1376 (void *) parent_fc;
1377 uint64_t i;
1378 unsigned int suffix = 0;
1379
1380 if (!fc_name || !parent_fc ||
1381 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1382 /* Not supported */
1383 ret = -1;
1384 goto end;
1385 }
1386
1387 switch (fc->type) {
1388 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1389 {
1390 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
1391
1392 field_ref = seq_fc->length_ref;
1393 is_before = seq_fc->length_is_before;
1394 tgt_type = "len";
1395 break;
1396 }
1397 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1398 {
1399 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
1400
1401 field_ref = var_fc->tag_ref;
1402 is_before = var_fc->tag_is_before;
1403 tgt_type = "tag";
1404 break;
1405 }
1406 default:
1407 abort();
1408 }
1409
1410 BT_ASSERT(field_ref);
1411
1412 if (!is_before) {
1413 goto end;
1414 }
1415
1416 /* Initial field ref */
1417 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
1418
1419 /*
1420 * Make sure field ref does not clash with an existing field
1421 * class name within the same parent structure field class.
1422 */
1423 while (true) {
1424 bool name_ok = true;
1425
1426 for (i = 0; i < parent_struct_fc->members->len; i++) {
1427 struct fs_sink_ctf_named_field_class *named_fc =
1428 fs_sink_ctf_field_class_struct_borrow_member_by_index(
1429 parent_struct_fc, i);
1430
1431 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
1432 /* Name clash */
1433 name_ok = false;
1434 break;
1435 }
1436 }
1437
1438 if (name_ok) {
1439 /* No clash: we're done */
1440 break;
1441 }
1442
1443 /* Append suffix and try again */
1444 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
1445 suffix);
1446 suffix++;
1447 }
1448
1449end:
1450 return ret;
1451}
1452
1453/*
1454 * This function recursively sets field refs of sequence and variant
1455 * field classes when they are immediately before, avoiding name clashes
1456 * with existing field class names.
1457 *
1458 * It can fail at this point if, for example, a sequence field class of
1459 * which to set the length's field ref has something else than a
1460 * structure field class as its parent: in this case, there's no
1461 * location to place the length field class immediately before the
1462 * sequence field class.
1463 */
1464static
486a5fc8
PP
1465int set_field_refs(struct fs_sink_ctf_field_class * const fc,
1466 const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
15fe47e0
PP
1467{
1468 int ret = 0;
817326a9 1469 enum fs_sink_ctf_field_class_type fc_type;
15fe47e0
PP
1470 BT_ASSERT(fc);
1471
817326a9
FD
1472 fc_type = fc->type;
1473
1474 switch (fc_type) {
15fe47e0
PP
1475 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1476 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1477 {
1478 uint64_t i;
1479 uint64_t len;
1480 struct fs_sink_ctf_field_class_struct *struct_fc;
11476be3 1481 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
15fe47e0
PP
1482 struct fs_sink_ctf_named_field_class *named_fc;
1483
817326a9 1484 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
15fe47e0
PP
1485 struct_fc = (void *) fc;
1486 len = struct_fc->members->len;
1487 } else {
1488 var_fc = (void *) fc;
1489 len = var_fc->options->len;
1490 ret = set_field_ref(fc, fc_name, parent_fc);
1491 if (ret) {
1492 goto end;
1493 }
1494 }
1495
1496 for (i = 0; i < len; i++) {
817326a9 1497 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
15fe47e0
PP
1498 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1499 struct_fc, i);
1500 } else {
1501 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1502 var_fc, i);
1503 }
1504
1505 ret = set_field_refs(named_fc->fc, named_fc->name->str,
1506 fc);
1507 if (ret) {
1508 goto end;
1509 }
1510 }
1511
1512 break;
1513 }
1514 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
1515 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1516 {
1517 struct fs_sink_ctf_field_class_array_base *array_base_fc =
1518 (void *) fc;
1519
817326a9 1520 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
15fe47e0
PP
1521 ret = set_field_ref(fc, fc_name, parent_fc);
1522 if (ret) {
1523 goto end;
1524 }
1525 }
1526
1527 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
1528 if (ret) {
1529 goto end;
1530 }
1531
1532 break;
1533 }
1534 default:
1535 break;
1536 }
1537
1538end:
1539 return ret;
1540}
1541
1542/*
1543 * This function translates a root scope trace IR field class to
1544 * a CTF IR field class.
1545 *
1546 * The resulting CTF IR field class is written to `*fc` so that it
1547 * exists as the parent object's (stream class or event class) true root
1548 * field class during the recursive translation for resolving purposes.
1549 * This is also why this function creates the empty structure field
1550 * class and then calls translate_structure_field_class_members() to
1551 * fill it.
1552 */
1553static
1554int translate_scope_field_class(struct ctx *ctx, bt_scope scope,
1555 struct fs_sink_ctf_field_class **fc,
1556 const bt_field_class *ir_fc)
1557{
1558 int ret = 0;
1559
1560 if (!ir_fc) {
1561 goto end;
1562 }
1563
1564 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
1565 BT_FIELD_CLASS_TYPE_STRUCTURE);
1566 BT_ASSERT(fc);
1567 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
1568 ir_fc, UINT64_C(-1));
1569 BT_ASSERT(*fc);
1570 ctx->cur_scope = scope;
1571 BT_ASSERT(ctx->cur_path->len == 0);
45c51519 1572 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
15fe47e0 1573 if (ret) {
aa1a7452 1574 BT_COMP_LOGE("Cannot translate scope structure field class: "
15fe47e0
PP
1575 "scope=%d", scope);
1576 goto end;
1577 }
1578
1579 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
1580 if (ret) {
aa1a7452 1581 BT_COMP_LOGE("Cannot translate scope structure field class: "
15fe47e0
PP
1582 "scope=%d", scope);
1583 goto end;
1584 }
1585
1586 cur_path_stack_pop(ctx);
1587
1588 /* Set field refs for preceding targets */
1589 ret = set_field_refs(*fc, NULL, NULL);
1590
1591end:
1592 return ret;
1593}
1594
1595static inline
aa1a7452 1596void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
15fe47e0
PP
1597{
1598 memset(ctx, 0, sizeof(struct ctx));
1599 ctx->cur_path = g_array_new(FALSE, TRUE,
1600 sizeof(struct field_path_elem));
1601 BT_ASSERT(ctx->cur_path);
aa1a7452
PP
1602 ctx->log_level = fs_sink->log_level;
1603 ctx->self_comp = fs_sink->self_comp;
15fe47e0
PP
1604}
1605
1606static inline
1607void ctx_fini(struct ctx *ctx)
1608{
1609 if (ctx->cur_path) {
1610 g_array_free(ctx->cur_path, TRUE);
1611 ctx->cur_path = NULL;
1612 }
1613}
1614
1615static
aa1a7452
PP
1616int translate_event_class(struct fs_sink_comp *fs_sink,
1617 struct fs_sink_ctf_stream_class *sc,
15fe47e0 1618 const bt_event_class *ir_ec,
aa1a7452 1619 struct fs_sink_ctf_event_class **out_ec)
15fe47e0
PP
1620{
1621 int ret = 0;
1622 struct ctx ctx;
1623 struct fs_sink_ctf_event_class *ec;
1624
1625 BT_ASSERT(sc);
1626 BT_ASSERT(ir_ec);
1627
aa1a7452 1628 ctx_init(&ctx, fs_sink);
15fe47e0
PP
1629 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1630 BT_ASSERT(ec);
1631 ctx.cur_sc = sc;
1632 ctx.cur_ec = ec;
1633 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
1634 &ec->spec_context_fc,
1635 bt_event_class_borrow_specific_context_field_class_const(
1636 ir_ec));
1637 if (ret) {
1638 goto end;
1639 }
1640
1641 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_PAYLOAD,
1642 &ec->payload_fc,
1643 bt_event_class_borrow_payload_field_class_const(ir_ec));
1644 if (ret) {
1645 goto end;
1646 }
1647
1648end:
1649 ctx_fini(&ctx);
1650 *out_ec = ec;
1651 return ret;
1652}
1653
1654BT_HIDDEN
1655int try_translate_event_class_trace_ir_to_ctf_ir(
aa1a7452 1656 struct fs_sink_comp *fs_sink,
15fe47e0
PP
1657 struct fs_sink_ctf_stream_class *sc,
1658 const bt_event_class *ir_ec,
aa1a7452 1659 struct fs_sink_ctf_event_class **out_ec)
15fe47e0
PP
1660{
1661 int ret = 0;
1662
1663 BT_ASSERT(sc);
1664 BT_ASSERT(ir_ec);
1665
1666 /* Check in hash table first */
1667 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
91d81473 1668 if (G_LIKELY(*out_ec)) {
15fe47e0
PP
1669 goto end;
1670 }
1671
aa1a7452 1672 ret = translate_event_class(fs_sink, sc, ir_ec, out_ec);
15fe47e0
PP
1673
1674end:
1675 return ret;
1676}
1677
335a2da5 1678bool default_clock_class_name_exists(struct fs_sink_ctf_trace *trace,
15fe47e0
PP
1679 const char *name)
1680{
1681 bool exists = false;
1682 uint64_t i;
1683
335a2da5 1684 for (i = 0; i < trace->stream_classes->len; i++) {
15fe47e0 1685 struct fs_sink_ctf_stream_class *sc =
335a2da5 1686 trace->stream_classes->pdata[i];
15fe47e0
PP
1687
1688 if (sc->default_clock_class_name->len == 0) {
1689 /* No default clock class */
1690 continue;
1691 }
1692
1693 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1694 exists = true;
1695 goto end;
1696 }
1697 }
1698
1699end:
1700 return exists;
1701}
1702
1703static
1704void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1705{
1706 unsigned int suffix = 0;
1707 char buf[16];
1708
1709 g_string_assign(sc->default_clock_class_name, "");
1710 sprintf(buf, "default");
1711
335a2da5 1712 while (default_clock_class_name_exists(sc->trace, buf)) {
15fe47e0
PP
1713 sprintf(buf, "default%u", suffix);
1714 suffix++;
1715 }
1716
1717 g_string_assign(sc->default_clock_class_name, buf);
1718}
1719
1720static
aa1a7452 1721int translate_stream_class(struct fs_sink_comp *fs_sink,
335a2da5 1722 struct fs_sink_ctf_trace *trace,
15fe47e0 1723 const bt_stream_class *ir_sc,
aa1a7452 1724 struct fs_sink_ctf_stream_class **out_sc)
15fe47e0
PP
1725{
1726 int ret = 0;
1727 struct ctx ctx;
1728
335a2da5 1729 BT_ASSERT(trace);
15fe47e0 1730 BT_ASSERT(ir_sc);
aa1a7452 1731 ctx_init(&ctx, fs_sink);
335a2da5 1732 *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
15fe47e0
PP
1733 BT_ASSERT(*out_sc);
1734
1735 /* Set default clock class's protected name, if any */
1736 if ((*out_sc)->default_clock_class) {
1737 const char *name = bt_clock_class_get_name(
1738 (*out_sc)->default_clock_class);
1739
15fe47e0
PP
1740 if (name) {
1741 /* Try original name, protected */
45c51519
PP
1742 g_string_assign((*out_sc)->default_clock_class_name,
1743 "");
1744
1745 if (must_protect_identifier(name)) {
1746 g_string_assign(
1747 (*out_sc)->default_clock_class_name,
1748 "_");
1749 }
1750
15fe47e0
PP
1751 g_string_assign((*out_sc)->default_clock_class_name,
1752 name);
45c51519
PP
1753 if (!ist_valid_identifier(
1754 (*out_sc)->default_clock_class_name->str)) {
15fe47e0
PP
1755 /* Invalid: create a new name */
1756 make_unique_default_clock_class_name(*out_sc);
1757 ret = 0;
1758 }
1759 } else {
1760 /* No name: create a name */
1761 make_unique_default_clock_class_name(*out_sc);
1762 }
1763 }
1764
1765 ctx.cur_sc = *out_sc;
1766 ret = translate_scope_field_class(&ctx, BT_SCOPE_PACKET_CONTEXT,
1767 &(*out_sc)->packet_context_fc,
1768 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1769 if (ret) {
1770 goto error;
1771 }
1772
1773 if ((*out_sc)->packet_context_fc) {
1774 /*
1775 * Make sure the structure field class's alignment is
1776 * enough: 8 is what we use for our own special members
1777 * in the packet context.
1778 */
1779 fs_sink_ctf_field_class_struct_align_at_least(
1780 (void *) (*out_sc)->packet_context_fc, 8);
1781 }
1782
1783 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_COMMON_CONTEXT,
1784 &(*out_sc)->event_common_context_fc,
1785 bt_stream_class_borrow_event_common_context_field_class_const(
1786 ir_sc));
1787 if (ret) {
1788 goto error;
1789 }
1790
1791 goto end;
1792
1793error:
1794 fs_sink_ctf_stream_class_destroy(*out_sc);
1795 *out_sc = NULL;
1796
1797end:
1798 ctx_fini(&ctx);
1799 return ret;
1800}
1801
1802BT_HIDDEN
1803int try_translate_stream_class_trace_ir_to_ctf_ir(
aa1a7452 1804 struct fs_sink_comp *fs_sink,
335a2da5 1805 struct fs_sink_ctf_trace *trace,
15fe47e0 1806 const bt_stream_class *ir_sc,
aa1a7452 1807 struct fs_sink_ctf_stream_class **out_sc)
15fe47e0
PP
1808{
1809 int ret = 0;
1810 uint64_t i;
1811
335a2da5 1812 BT_ASSERT(trace);
15fe47e0
PP
1813 BT_ASSERT(ir_sc);
1814
335a2da5
PP
1815 for (i = 0; i < trace->stream_classes->len; i++) {
1816 *out_sc = trace->stream_classes->pdata[i];
15fe47e0
PP
1817
1818 if ((*out_sc)->ir_sc == ir_sc) {
1819 goto end;
1820 }
1821 }
1822
335a2da5 1823 ret = translate_stream_class(fs_sink, trace, ir_sc, out_sc);
15fe47e0
PP
1824
1825end:
1826 return ret;
1827}
1828
1829BT_HIDDEN
335a2da5
PP
1830struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(
1831 struct fs_sink_comp *fs_sink, const bt_trace *ir_trace)
15fe47e0
PP
1832{
1833 uint64_t count;
1834 uint64_t i;
335a2da5 1835 struct fs_sink_ctf_trace *trace = NULL;
15fe47e0 1836
335a2da5
PP
1837 /* Check that trace's environment is TSDL-compatible */
1838 count = bt_trace_get_environment_entry_count(ir_trace);
15fe47e0
PP
1839 for (i = 0; i < count; i++) {
1840 const char *name;
1841 const bt_value *val;
1842
335a2da5
PP
1843 bt_trace_borrow_environment_entry_by_index_const(
1844 ir_trace, i, &name, &val);
15fe47e0 1845
45c51519 1846 if (!ist_valid_identifier(name)) {
aa1a7452
PP
1847 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1848 fs_sink->self_comp,
ffa3b2b3 1849 "Unsupported trace class's environment entry name: "
15fe47e0
PP
1850 "name=\"%s\"", name);
1851 goto end;
1852 }
1853
1854 switch (bt_value_get_type(val)) {
fdd3a2da 1855 case BT_VALUE_TYPE_SIGNED_INTEGER:
15fe47e0
PP
1856 case BT_VALUE_TYPE_STRING:
1857 break;
1858 default:
aa1a7452
PP
1859 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1860 fs_sink->self_comp,
ffa3b2b3 1861 "Unsupported trace class's environment entry value type: "
15fe47e0
PP
1862 "type=%s",
1863 bt_common_value_type_string(
1864 bt_value_get_type(val)));
1865 goto end;
1866 }
1867 }
1868
335a2da5
PP
1869 trace = fs_sink_ctf_trace_create(ir_trace);
1870 BT_ASSERT(trace);
15fe47e0
PP
1871
1872end:
335a2da5 1873 return trace;
15fe47e0 1874}
This page took 0.110409 seconds and 4 git commands to generate.