sink.ctf.fs: remove unusued _is_variant_field_class_tag_valid()
[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"
d9c39b0a 26#include "logging/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
e7ceb9df 61 bt_field_path_scope cur_scope;
15fe47e0
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
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
e7ceb9df 218 if (ctx->cur_scope == BT_FIELD_PATH_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)) {
e7ceb9df 291 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
15fe47e0
PP
292 BT_ASSERT(ctx->cur_sc);
293 tgt_fc = ctx->cur_sc->packet_context_fc;
294 break;
e7ceb9df 295 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
15fe47e0
PP
296 BT_ASSERT(ctx->cur_sc);
297 tgt_fc = ctx->cur_sc->event_common_context_fc;
298 break;
e7ceb9df 299 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
15fe47e0
PP
300 BT_ASSERT(ctx->cur_ec);
301 tgt_fc = ctx->cur_ec->spec_context_fc;
302 break;
e7ceb9df 303 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
15fe47e0
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
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)) {
e7ceb9df 452 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
15fe47e0
PP
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;
e7ceb9df 457 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
15fe47e0
PP
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;
e7ceb9df 462 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
15fe47e0
PP
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;
e7ceb9df 467 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
15fe47e0
PP
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;
e7ceb9df 538 bt_field_path_scope tgt_scope;
15fe47e0
PP
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 indicates whether or not a given variant FC option name
713 * must be protected (with the `_` prefix).
714 *
715 * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
716 * close as possible to an original CTF trace as decoded by
717 * `src.ctf.fs`.
718 *
719 * This scenario is valid in CTF 1.8:
720 *
721 * enum {
722 * HELLO,
723 * MEOW
724 * } tag;
725 *
726 * variant <tag> {
727 * int HELLO;
728 * string MEOW;
729 * };
730 *
731 * Once in trace IR, the enumeration FC mapping names and variant FC
732 * option names are kept as is. For this reason, we don't want to
733 * protect the variant FC option names here (by prepending `_`): this
734 * would make the variant FC option name and the enumeration FC mapping
735 * name not match.
736 *
737 * This scenario is also valid in CTF 1.8:
738 *
739 * enum {
740 * _HELLO,
741 * MEOW
742 * } tag;
743 *
744 * variant <tag> {
745 * int _HELLO;
746 * string MEOW;
747 * };
748 *
749 * Once in trace IR, the enumeration FC mapping names are kept as is,
750 * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
751 * for presentation, as recommended by CTF 1.8). When going back to
752 * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
753 * the corresponding enumeration FC mapping name.
754 *
755 * This scenario is also valid in CTF 1.8:
756 *
757 * enum {
758 * __HELLO,
759 * MEOW
760 * } tag;
761 *
762 * variant <tag> {
763 * int __HELLO;
764 * string MEOW;
765 * };
766 *
767 * Once in trace IR, the enumeration FC mapping names are kept as is,
768 * but the `__HELLO` variant FC option name becomes `_HELLO`
769 * (unprotected). When going back to TSDL, we need to protect `_HELLO`
770 * so that it becomes `__HELLO` to match the corresponding enumeration
771 * FC mapping name.
772 *
773 * `src.ctf.fs` always uses the _same_ integer range sets for a selector
774 * FC mapping and a corresponding variant FC option. We can use that
775 * fact to find the original variant FC option names by matching variant
776 * FC options and enumeration FC mappings by range set.
777 */
778static
779int must_protect_variant_option_name(const bt_field_class *ir_var_fc,
780 const bt_field_class *ir_tag_fc, uint64_t opt_i,
781 GString *name_buf, bool *must_protect)
782{
783 int ret = 0;
784 uint64_t i;
785 bt_field_class_type ir_var_fc_type;
786 const void *opt_ranges = NULL;
787 const char *mapping_label = NULL;
788 const char *ir_opt_name;
789 const bt_field_class_variant_option *base_var_opt;
790 bool force_protect = false;
791
792 *must_protect = false;
793 ir_var_fc_type = bt_field_class_get_type(ir_var_fc);
794 base_var_opt = bt_field_class_variant_borrow_option_by_index_const(
795 ir_var_fc, opt_i);
796 BT_ASSERT(base_var_opt);
797 ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt);
798 BT_ASSERT(ir_opt_name);
799
800 /*
801 * Check if the variant FC option name is required to be
802 * protected (reserved TSDL keyword or starts with `_`). In that
803 * case, the name of the selector FC mapping we find must match
804 * exactly the protected name.
805 */
806 force_protect = must_protect_identifier(ir_opt_name);
807 if (force_protect) {
808 *must_protect = true;
809 g_string_assign(name_buf, "_");
810 g_string_append(name_buf, ir_opt_name);
811 } else {
812 g_string_assign(name_buf, ir_opt_name);
813 }
814
815 /* Borrow option's ranges */
816 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR) {
817 /* No ranges: we're done */
818 goto end;
819 } if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) {
9c08c816
PP
820 const bt_field_class_variant_with_selector_unsigned_option *var_opt =
821 bt_field_class_variant_with_selector_unsigned_borrow_option_by_index_const(
45c51519
PP
822 ir_var_fc, opt_i);
823 opt_ranges =
9c08c816 824 bt_field_class_variant_with_selector_unsigned_option_borrow_ranges_const(
45c51519
PP
825 var_opt);
826 } else {
9c08c816
PP
827 const bt_field_class_variant_with_selector_signed_option *var_opt =
828 bt_field_class_variant_with_selector_signed_borrow_option_by_index_const(
45c51519
PP
829 ir_var_fc, opt_i);
830 opt_ranges =
9c08c816 831 bt_field_class_variant_with_selector_signed_option_borrow_ranges_const(
45c51519
PP
832 var_opt);
833 }
834
835 /* Find corresponding mapping by range set in selector FC */
836 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_tag_fc);
837 i++) {
838 if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) {
839 const bt_field_class_enumeration_mapping *mapping_base;
9c08c816 840 const bt_field_class_enumeration_unsigned_mapping *mapping;
45c51519
PP
841 const bt_integer_range_set_unsigned *mapping_ranges;
842
9c08c816 843 mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
45c51519 844 ir_tag_fc, i);
9c08c816 845 mapping_ranges = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
45c51519
PP
846 mapping);
847
848 if (bt_integer_range_set_unsigned_compare(opt_ranges,
849 mapping_ranges)) {
850 /* We have a winner */
851 mapping_base =
9c08c816 852 bt_field_class_enumeration_unsigned_mapping_as_mapping_const(
45c51519
PP
853 mapping);
854 mapping_label =
855 bt_field_class_enumeration_mapping_get_label(
856 mapping_base);
857 break;
858 }
859 } else {
860 const bt_field_class_enumeration_mapping *mapping_base;
9c08c816 861 const bt_field_class_enumeration_signed_mapping *mapping;
45c51519
PP
862 const bt_integer_range_set_signed *mapping_ranges;
863
9c08c816 864 mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
45c51519 865 ir_tag_fc, i);
9c08c816 866 mapping_ranges = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
45c51519
PP
867 mapping);
868
869 if (bt_integer_range_set_signed_compare(opt_ranges,
870 mapping_ranges)) {
871 /* We have a winner */
872 mapping_base =
9c08c816 873 bt_field_class_enumeration_signed_mapping_as_mapping_const(
45c51519
PP
874 mapping);
875 mapping_label =
876 bt_field_class_enumeration_mapping_get_label(
877 mapping_base);
878 break;
879 }
880 }
881 }
882
883 if (!mapping_label) {
884 /* Range set not found: invalid selector for CTF 1.8 */
885 ret = -1;
886 goto end;
887 }
888
889 /*
890 * If the enumeration FC mapping name is not the same as the
891 * variant FC option name and we didn't protect already, try
892 * protecting the option name and check again.
893 */
894 if (strcmp(mapping_label, name_buf->str) != 0) {
895 if (force_protect) {
896 ret = -1;
897 goto end;
898 }
899
900 if (mapping_label[0] == '\0') {
901 ret = -1;
902 goto end;
903 }
904
905 g_string_assign(name_buf, "_");
906 g_string_append(name_buf, ir_opt_name);
907
908 if (strcmp(mapping_label, name_buf->str) != 0) {
909 ret = -1;
910 goto end;
911 }
912
913 /*
914 * If this comes from a `src.ctf.fs` source, it looks
915 * like the variant FC option name was initially
916 * protected: protect it again when going back to TSDL.
917 */
918 *must_protect = true;
919 }
920
921end:
922 return ret;
923}
924
15fe47e0
PP
925static inline
926int translate_variant_field_class(struct ctx *ctx)
927{
928 int ret = 0;
929 uint64_t i;
930 struct fs_sink_ctf_field_class_variant *fc =
931 fs_sink_ctf_field_class_variant_create_empty(
932 cur_path_stack_top(ctx)->ir_fc,
933 cur_path_stack_top(ctx)->index_in_parent);
45c51519
PP
934 bt_field_class_type ir_fc_type;
935 const bt_field_path *ir_selector_field_path = NULL;
936 struct fs_sink_ctf_field_class *tgt_fc = NULL;
937 GString *name_buf = g_string_new(NULL);
938 bt_value *prot_opt_names = bt_value_array_create();
939 uint64_t opt_count;
15fe47e0
PP
940
941 BT_ASSERT(fc);
45c51519
PP
942 BT_ASSERT(name_buf);
943 BT_ASSERT(prot_opt_names);
944 ir_fc_type = bt_field_class_get_type(fc->base.ir_fc);
945 opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc);
946
947 if (ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR ||
948 ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) {
949 ir_selector_field_path = bt_field_class_variant_with_selector_borrow_selector_field_path_const(
950 fc->base.ir_fc);
951 BT_ASSERT(ir_selector_field_path);
952 }
15fe47e0
PP
953
954 /* Resolve tag field class before appending to parent */
45c51519
PP
955 resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref,
956 &fc->tag_is_before, &tgt_fc);
957
958 if (ir_selector_field_path && tgt_fc) {
959 uint64_t mapping_count;
960 uint64_t option_count;
961
962 /* CTF 1.8: selector FC must be an enumeration FC */
963 bt_field_class_type type = bt_field_class_get_type(
964 tgt_fc->ir_fc);
965
966 if (type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION &&
967 type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
968 fc->tag_is_before = true;
969 goto validate_opts;
970 }
971
972 /*
973 * Call must_protect_variant_option_name() for each
974 * option below. In that case we also want selector FC
975 * to contain as many mappings as the variant FC has
976 * options.
977 */
978 mapping_count = bt_field_class_enumeration_get_mapping_count(
979 tgt_fc->ir_fc);
980 option_count = bt_field_class_variant_get_option_count(
981 fc->base.ir_fc);
982
983 if (mapping_count != option_count) {
984 fc->tag_is_before = true;
985 goto validate_opts;
986 }
987 } else {
988 /*
989 * No compatible selector field class for CTF 1.8:
990 * create the appropriate selector field class.
991 */
992 fc->tag_is_before = true;
993 }
994
995validate_opts:
996 /*
997 * First pass: detect any option name clash with option name
998 * protection. In that case, we don't fail: just create the
999 * selector field class before the variant field class.
1000 *
1001 * After this, `prot_opt_names` contains the final option names,
1002 * potentially protected if needed. They can still be invalid
1003 * TSDL identifiers however; this will be checked by
1004 * cur_path_stack_push().
1005 */
1006 for (i = 0; i < opt_count; i++) {
1007 bool must_protect = false;
1008
1009 ret = must_protect_variant_option_name(fc->base.ir_fc,
1010 tgt_fc->ir_fc, i, name_buf, &must_protect);
1011 if (ret) {
1012 fc->tag_is_before = true;
1013 }
1014
1015 ret = bt_value_array_append_string_element(prot_opt_names,
1016 name_buf->str);
1017 if (ret) {
1018 goto end;
1019 }
1020 }
1021
1022 for (i = 0; i < opt_count; i++) {
1023 uint64_t j;
1024 const bt_value *opt_name_a =
1025 bt_value_array_borrow_element_by_index_const(
1026 prot_opt_names, i);
1027
1028 for (j = 0; j < opt_count; j++) {
1029 const bt_value *opt_name_b;
1030
1031 if (i == j) {
1032 continue;
1033 }
15fe47e0 1034
45c51519
PP
1035 opt_name_b =
1036 bt_value_array_borrow_element_by_index_const(
1037 prot_opt_names, j);
1038 if (bt_value_compare(opt_name_a, opt_name_b)) {
1039 /*
1040 * Variant FC option names are not
1041 * unique when protected.
1042 */
1043 fc->tag_is_before = true;
1044 goto append_to_parent;
1045 }
1046 }
1047 }
1048
1049append_to_parent:
15fe47e0
PP
1050 append_to_parent_field_class(ctx, (void *) fc);
1051
45c51519 1052 for (i = 0; i < opt_count; i++) {
15fe47e0 1053 const bt_field_class_variant_option *opt;
15fe47e0 1054 const bt_field_class *opt_ir_fc;
45c51519
PP
1055 const bt_value *prot_opt_name_val =
1056 bt_value_array_borrow_element_by_index_const(
1057 prot_opt_names, i);
1058 const char *prot_opt_name = bt_value_string_get(
1059 prot_opt_name_val);
15fe47e0 1060
45c51519 1061 BT_ASSERT(prot_opt_name);
15fe47e0
PP
1062 opt = bt_field_class_variant_borrow_option_by_index_const(
1063 fc->base.ir_fc, i);
15fe47e0
PP
1064 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
1065 opt);
45c51519
PP
1066
1067 /*
1068 * We don't ask cur_path_stack_push() to protect the
1069 * option name because it's already protected at this
1070 * point.
1071 */
1072 ret = cur_path_stack_push(ctx, i, prot_opt_name, false,
1073 opt_ir_fc, (void *) fc);
15fe47e0 1074 if (ret) {
aa1a7452 1075 BT_COMP_LOGE("Cannot translate variant field class option: "
45c51519 1076 "name=\"%s\"", prot_opt_name);
15fe47e0
PP
1077 goto end;
1078 }
1079
1080 ret = translate_field_class(ctx);
1081 if (ret) {
aa1a7452 1082 BT_COMP_LOGE("Cannot translate variant field class option: "
45c51519 1083 "name=\"%s\"", prot_opt_name);
15fe47e0
PP
1084 goto end;
1085 }
1086
1087 cur_path_stack_pop(ctx);
1088 }
1089
1090end:
45c51519
PP
1091 if (name_buf) {
1092 g_string_free(name_buf, TRUE);
1093 }
1094
1095 bt_value_put_ref(prot_opt_names);
15fe47e0
PP
1096 return ret;
1097}
1098
1099static inline
1100int translate_static_array_field_class(struct ctx *ctx)
1101{
1102 struct fs_sink_ctf_field_class_array *fc =
1103 fs_sink_ctf_field_class_array_create_empty(
1104 cur_path_stack_top(ctx)->ir_fc,
1105 cur_path_stack_top(ctx)->index_in_parent);
1106 const bt_field_class *elem_ir_fc =
1107 bt_field_class_array_borrow_element_field_class_const(
1108 fc->base.base.ir_fc);
1109 int ret;
1110
1111 BT_ASSERT(fc);
1112 append_to_parent_field_class(ctx, (void *) fc);
45c51519 1113 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
15fe47e0
PP
1114 (void *) fc);
1115 if (ret) {
aa1a7452 1116 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
15fe47e0
PP
1117 goto end;
1118 }
1119
1120 ret = translate_field_class(ctx);
1121 if (ret) {
aa1a7452 1122 BT_COMP_LOGE_STR("Cannot translate static array field class element.");
15fe47e0
PP
1123 goto end;
1124 }
1125
1126 cur_path_stack_pop(ctx);
1127 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1128
1129end:
1130 return ret;
1131}
1132
1133static inline
1134int translate_dynamic_array_field_class(struct ctx *ctx)
1135{
1136 struct fs_sink_ctf_field_class_sequence *fc =
1137 fs_sink_ctf_field_class_sequence_create_empty(
1138 cur_path_stack_top(ctx)->ir_fc,
1139 cur_path_stack_top(ctx)->index_in_parent);
1140 const bt_field_class *elem_ir_fc =
1141 bt_field_class_array_borrow_element_field_class_const(
1142 fc->base.base.ir_fc);
1143 int ret;
1144
1145 BT_ASSERT(fc);
1146
1147 /* Resolve length field class before appending to parent */
1148 resolve_field_class(ctx,
9c08c816 1149 bt_field_class_array_dynamic_borrow_length_field_path_const(
15fe47e0 1150 fc->base.base.ir_fc),
45c51519 1151 fc->length_ref, &fc->length_is_before, NULL);
15fe47e0
PP
1152
1153 append_to_parent_field_class(ctx, (void *) fc);
45c51519 1154 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
15fe47e0
PP
1155 (void *) fc);
1156 if (ret) {
aa1a7452 1157 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
15fe47e0
PP
1158 goto end;
1159 }
1160
1161 ret = translate_field_class(ctx);
1162 if (ret) {
aa1a7452 1163 BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
15fe47e0
PP
1164 goto end;
1165 }
1166
1167 cur_path_stack_pop(ctx);
1168 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
1169
1170end:
1171 return ret;
1172}
1173
1174static inline
1175int translate_integer_field_class(struct ctx *ctx)
1176{
1177 struct fs_sink_ctf_field_class_int *fc =
1178 fs_sink_ctf_field_class_int_create(
1179 cur_path_stack_top(ctx)->ir_fc,
1180 cur_path_stack_top(ctx)->index_in_parent);
1181
1182 BT_ASSERT(fc);
1183 append_to_parent_field_class(ctx, (void *) fc);
1184 return 0;
1185}
1186
1187static inline
1188int translate_real_field_class(struct ctx *ctx)
1189{
1190 struct fs_sink_ctf_field_class_float *fc =
1191 fs_sink_ctf_field_class_float_create(
1192 cur_path_stack_top(ctx)->ir_fc,
1193 cur_path_stack_top(ctx)->index_in_parent);
1194
1195 BT_ASSERT(fc);
1196 append_to_parent_field_class(ctx, (void *) fc);
1197 return 0;
1198}
1199
1200static inline
1201int translate_string_field_class(struct ctx *ctx)
1202{
1203 struct fs_sink_ctf_field_class_string *fc =
1204 fs_sink_ctf_field_class_string_create(
1205 cur_path_stack_top(ctx)->ir_fc,
1206 cur_path_stack_top(ctx)->index_in_parent);
1207
1208 BT_ASSERT(fc);
1209 append_to_parent_field_class(ctx, (void *) fc);
1210 return 0;
1211}
1212
1213/*
1214 * Translates a field class, recursively.
1215 *
1216 * The field class's IR field class, parent field class, and index
1217 * within its parent are in the context's current path's top element
1218 * (cur_path_stack_top()).
1219 */
1220static
1221int translate_field_class(struct ctx *ctx)
1222{
1223 int ret;
1224
1225 switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
1226 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
1227 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
1228 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
1229 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
1230 ret = translate_integer_field_class(ctx);
1231 break;
1232 case BT_FIELD_CLASS_TYPE_REAL:
1233 ret = translate_real_field_class(ctx);
1234 break;
1235 case BT_FIELD_CLASS_TYPE_STRING:
1236 ret = translate_string_field_class(ctx);
1237 break;
1238 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1239 ret = translate_structure_field_class(ctx);
1240 break;
1241 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1242 ret = translate_static_array_field_class(ctx);
1243 break;
1244 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1245 ret = translate_dynamic_array_field_class(ctx);
1246 break;
45c51519
PP
1247 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
1248 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
1249 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
15fe47e0
PP
1250 ret = translate_variant_field_class(ctx);
1251 break;
1252 default:
1253 abort();
1254 }
1255
1256 return ret;
1257}
1258
1259static
1260int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
1261 struct fs_sink_ctf_field_class *parent_fc)
1262{
1263 int ret = 0;
1264 GString *field_ref = NULL;
1265 bool is_before;
1266 const char *tgt_type;
1267 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
1268 (void *) parent_fc;
1269 uint64_t i;
1270 unsigned int suffix = 0;
1271
1272 if (!fc_name || !parent_fc ||
1273 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
1274 /* Not supported */
1275 ret = -1;
1276 goto end;
1277 }
1278
1279 switch (fc->type) {
1280 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1281 {
1282 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
1283
1284 field_ref = seq_fc->length_ref;
1285 is_before = seq_fc->length_is_before;
1286 tgt_type = "len";
1287 break;
1288 }
1289 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1290 {
1291 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
1292
1293 field_ref = var_fc->tag_ref;
1294 is_before = var_fc->tag_is_before;
1295 tgt_type = "tag";
1296 break;
1297 }
1298 default:
1299 abort();
1300 }
1301
1302 BT_ASSERT(field_ref);
1303
1304 if (!is_before) {
1305 goto end;
1306 }
1307
1308 /* Initial field ref */
1309 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
1310
1311 /*
1312 * Make sure field ref does not clash with an existing field
1313 * class name within the same parent structure field class.
1314 */
1315 while (true) {
1316 bool name_ok = true;
1317
1318 for (i = 0; i < parent_struct_fc->members->len; i++) {
1319 struct fs_sink_ctf_named_field_class *named_fc =
1320 fs_sink_ctf_field_class_struct_borrow_member_by_index(
1321 parent_struct_fc, i);
1322
1323 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
1324 /* Name clash */
1325 name_ok = false;
1326 break;
1327 }
1328 }
1329
1330 if (name_ok) {
1331 /* No clash: we're done */
1332 break;
1333 }
1334
1335 /* Append suffix and try again */
1336 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
1337 suffix);
1338 suffix++;
1339 }
1340
1341end:
1342 return ret;
1343}
1344
1345/*
1346 * This function recursively sets field refs of sequence and variant
1347 * field classes when they are immediately before, avoiding name clashes
1348 * with existing field class names.
1349 *
1350 * It can fail at this point if, for example, a sequence field class of
1351 * which to set the length's field ref has something else than a
1352 * structure field class as its parent: in this case, there's no
1353 * location to place the length field class immediately before the
1354 * sequence field class.
1355 */
1356static
486a5fc8
PP
1357int set_field_refs(struct fs_sink_ctf_field_class * const fc,
1358 const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
15fe47e0
PP
1359{
1360 int ret = 0;
817326a9 1361 enum fs_sink_ctf_field_class_type fc_type;
15fe47e0
PP
1362 BT_ASSERT(fc);
1363
817326a9
FD
1364 fc_type = fc->type;
1365
1366 switch (fc_type) {
15fe47e0
PP
1367 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
1368 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
1369 {
1370 uint64_t i;
1371 uint64_t len;
1372 struct fs_sink_ctf_field_class_struct *struct_fc;
11476be3 1373 struct fs_sink_ctf_field_class_variant *var_fc = NULL;
15fe47e0
PP
1374 struct fs_sink_ctf_named_field_class *named_fc;
1375
817326a9 1376 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
15fe47e0
PP
1377 struct_fc = (void *) fc;
1378 len = struct_fc->members->len;
1379 } else {
1380 var_fc = (void *) fc;
1381 len = var_fc->options->len;
1382 ret = set_field_ref(fc, fc_name, parent_fc);
1383 if (ret) {
1384 goto end;
1385 }
1386 }
1387
1388 for (i = 0; i < len; i++) {
817326a9 1389 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
15fe47e0
PP
1390 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
1391 struct_fc, i);
1392 } else {
1393 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
1394 var_fc, i);
1395 }
1396
1397 ret = set_field_refs(named_fc->fc, named_fc->name->str,
1398 fc);
1399 if (ret) {
1400 goto end;
1401 }
1402 }
1403
1404 break;
1405 }
1406 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
1407 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
1408 {
1409 struct fs_sink_ctf_field_class_array_base *array_base_fc =
1410 (void *) fc;
1411
817326a9 1412 if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
15fe47e0
PP
1413 ret = set_field_ref(fc, fc_name, parent_fc);
1414 if (ret) {
1415 goto end;
1416 }
1417 }
1418
1419 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
1420 if (ret) {
1421 goto end;
1422 }
1423
1424 break;
1425 }
1426 default:
1427 break;
1428 }
1429
1430end:
1431 return ret;
1432}
1433
1434/*
1435 * This function translates a root scope trace IR field class to
1436 * a CTF IR field class.
1437 *
1438 * The resulting CTF IR field class is written to `*fc` so that it
1439 * exists as the parent object's (stream class or event class) true root
1440 * field class during the recursive translation for resolving purposes.
1441 * This is also why this function creates the empty structure field
1442 * class and then calls translate_structure_field_class_members() to
1443 * fill it.
1444 */
1445static
e7ceb9df 1446int translate_scope_field_class(struct ctx *ctx, bt_field_path_scope scope,
15fe47e0
PP
1447 struct fs_sink_ctf_field_class **fc,
1448 const bt_field_class *ir_fc)
1449{
1450 int ret = 0;
1451
1452 if (!ir_fc) {
1453 goto end;
1454 }
1455
1456 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
1457 BT_FIELD_CLASS_TYPE_STRUCTURE);
1458 BT_ASSERT(fc);
1459 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
1460 ir_fc, UINT64_C(-1));
1461 BT_ASSERT(*fc);
1462 ctx->cur_scope = scope;
1463 BT_ASSERT(ctx->cur_path->len == 0);
45c51519 1464 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
15fe47e0 1465 if (ret) {
aa1a7452 1466 BT_COMP_LOGE("Cannot translate scope structure field class: "
15fe47e0
PP
1467 "scope=%d", scope);
1468 goto end;
1469 }
1470
1471 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
1472 if (ret) {
aa1a7452 1473 BT_COMP_LOGE("Cannot translate scope structure field class: "
15fe47e0
PP
1474 "scope=%d", scope);
1475 goto end;
1476 }
1477
1478 cur_path_stack_pop(ctx);
1479
1480 /* Set field refs for preceding targets */
1481 ret = set_field_refs(*fc, NULL, NULL);
1482
1483end:
1484 return ret;
1485}
1486
1487static inline
aa1a7452 1488void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
15fe47e0
PP
1489{
1490 memset(ctx, 0, sizeof(struct ctx));
1491 ctx->cur_path = g_array_new(FALSE, TRUE,
1492 sizeof(struct field_path_elem));
1493 BT_ASSERT(ctx->cur_path);
aa1a7452
PP
1494 ctx->log_level = fs_sink->log_level;
1495 ctx->self_comp = fs_sink->self_comp;
15fe47e0
PP
1496}
1497
1498static inline
1499void ctx_fini(struct ctx *ctx)
1500{
1501 if (ctx->cur_path) {
1502 g_array_free(ctx->cur_path, TRUE);
1503 ctx->cur_path = NULL;
1504 }
1505}
1506
1507static
aa1a7452
PP
1508int translate_event_class(struct fs_sink_comp *fs_sink,
1509 struct fs_sink_ctf_stream_class *sc,
15fe47e0 1510 const bt_event_class *ir_ec,
aa1a7452 1511 struct fs_sink_ctf_event_class **out_ec)
15fe47e0
PP
1512{
1513 int ret = 0;
1514 struct ctx ctx;
1515 struct fs_sink_ctf_event_class *ec;
1516
1517 BT_ASSERT(sc);
1518 BT_ASSERT(ir_ec);
1519
aa1a7452 1520 ctx_init(&ctx, fs_sink);
15fe47e0
PP
1521 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1522 BT_ASSERT(ec);
1523 ctx.cur_sc = sc;
1524 ctx.cur_ec = ec;
e7ceb9df 1525 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT,
15fe47e0
PP
1526 &ec->spec_context_fc,
1527 bt_event_class_borrow_specific_context_field_class_const(
1528 ir_ec));
1529 if (ret) {
1530 goto end;
1531 }
1532
e7ceb9df 1533 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD,
15fe47e0
PP
1534 &ec->payload_fc,
1535 bt_event_class_borrow_payload_field_class_const(ir_ec));
1536 if (ret) {
1537 goto end;
1538 }
1539
1540end:
1541 ctx_fini(&ctx);
1542 *out_ec = ec;
1543 return ret;
1544}
1545
1546BT_HIDDEN
1547int try_translate_event_class_trace_ir_to_ctf_ir(
aa1a7452 1548 struct fs_sink_comp *fs_sink,
15fe47e0
PP
1549 struct fs_sink_ctf_stream_class *sc,
1550 const bt_event_class *ir_ec,
aa1a7452 1551 struct fs_sink_ctf_event_class **out_ec)
15fe47e0
PP
1552{
1553 int ret = 0;
1554
1555 BT_ASSERT(sc);
1556 BT_ASSERT(ir_ec);
1557
1558 /* Check in hash table first */
1559 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
91d81473 1560 if (G_LIKELY(*out_ec)) {
15fe47e0
PP
1561 goto end;
1562 }
1563
aa1a7452 1564 ret = translate_event_class(fs_sink, sc, ir_ec, out_ec);
15fe47e0
PP
1565
1566end:
1567 return ret;
1568}
1569
335a2da5 1570bool default_clock_class_name_exists(struct fs_sink_ctf_trace *trace,
15fe47e0
PP
1571 const char *name)
1572{
1573 bool exists = false;
1574 uint64_t i;
1575
335a2da5 1576 for (i = 0; i < trace->stream_classes->len; i++) {
15fe47e0 1577 struct fs_sink_ctf_stream_class *sc =
335a2da5 1578 trace->stream_classes->pdata[i];
15fe47e0
PP
1579
1580 if (sc->default_clock_class_name->len == 0) {
1581 /* No default clock class */
1582 continue;
1583 }
1584
1585 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1586 exists = true;
1587 goto end;
1588 }
1589 }
1590
1591end:
1592 return exists;
1593}
1594
1595static
1596void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1597{
1598 unsigned int suffix = 0;
1599 char buf[16];
1600
1601 g_string_assign(sc->default_clock_class_name, "");
1602 sprintf(buf, "default");
1603
335a2da5 1604 while (default_clock_class_name_exists(sc->trace, buf)) {
15fe47e0
PP
1605 sprintf(buf, "default%u", suffix);
1606 suffix++;
1607 }
1608
1609 g_string_assign(sc->default_clock_class_name, buf);
1610}
1611
1612static
aa1a7452 1613int translate_stream_class(struct fs_sink_comp *fs_sink,
335a2da5 1614 struct fs_sink_ctf_trace *trace,
15fe47e0 1615 const bt_stream_class *ir_sc,
aa1a7452 1616 struct fs_sink_ctf_stream_class **out_sc)
15fe47e0
PP
1617{
1618 int ret = 0;
1619 struct ctx ctx;
1620
335a2da5 1621 BT_ASSERT(trace);
15fe47e0 1622 BT_ASSERT(ir_sc);
aa1a7452 1623 ctx_init(&ctx, fs_sink);
335a2da5 1624 *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
15fe47e0
PP
1625 BT_ASSERT(*out_sc);
1626
1627 /* Set default clock class's protected name, if any */
1628 if ((*out_sc)->default_clock_class) {
1629 const char *name = bt_clock_class_get_name(
1630 (*out_sc)->default_clock_class);
1631
15fe47e0
PP
1632 if (name) {
1633 /* Try original name, protected */
45c51519
PP
1634 g_string_assign((*out_sc)->default_clock_class_name,
1635 "");
1636
1637 if (must_protect_identifier(name)) {
1638 g_string_assign(
1639 (*out_sc)->default_clock_class_name,
1640 "_");
1641 }
1642
15fe47e0
PP
1643 g_string_assign((*out_sc)->default_clock_class_name,
1644 name);
45c51519
PP
1645 if (!ist_valid_identifier(
1646 (*out_sc)->default_clock_class_name->str)) {
15fe47e0
PP
1647 /* Invalid: create a new name */
1648 make_unique_default_clock_class_name(*out_sc);
1649 ret = 0;
1650 }
1651 } else {
1652 /* No name: create a name */
1653 make_unique_default_clock_class_name(*out_sc);
1654 }
1655 }
1656
1657 ctx.cur_sc = *out_sc;
e7ceb9df 1658 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT,
15fe47e0
PP
1659 &(*out_sc)->packet_context_fc,
1660 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1661 if (ret) {
1662 goto error;
1663 }
1664
1665 if ((*out_sc)->packet_context_fc) {
1666 /*
1667 * Make sure the structure field class's alignment is
1668 * enough: 8 is what we use for our own special members
1669 * in the packet context.
1670 */
1671 fs_sink_ctf_field_class_struct_align_at_least(
1672 (void *) (*out_sc)->packet_context_fc, 8);
1673 }
1674
e7ceb9df 1675 ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT,
15fe47e0
PP
1676 &(*out_sc)->event_common_context_fc,
1677 bt_stream_class_borrow_event_common_context_field_class_const(
1678 ir_sc));
1679 if (ret) {
1680 goto error;
1681 }
1682
1683 goto end;
1684
1685error:
1686 fs_sink_ctf_stream_class_destroy(*out_sc);
1687 *out_sc = NULL;
1688
1689end:
1690 ctx_fini(&ctx);
1691 return ret;
1692}
1693
1694BT_HIDDEN
1695int try_translate_stream_class_trace_ir_to_ctf_ir(
aa1a7452 1696 struct fs_sink_comp *fs_sink,
335a2da5 1697 struct fs_sink_ctf_trace *trace,
15fe47e0 1698 const bt_stream_class *ir_sc,
aa1a7452 1699 struct fs_sink_ctf_stream_class **out_sc)
15fe47e0
PP
1700{
1701 int ret = 0;
1702 uint64_t i;
1703
335a2da5 1704 BT_ASSERT(trace);
15fe47e0
PP
1705 BT_ASSERT(ir_sc);
1706
335a2da5
PP
1707 for (i = 0; i < trace->stream_classes->len; i++) {
1708 *out_sc = trace->stream_classes->pdata[i];
15fe47e0
PP
1709
1710 if ((*out_sc)->ir_sc == ir_sc) {
1711 goto end;
1712 }
1713 }
1714
335a2da5 1715 ret = translate_stream_class(fs_sink, trace, ir_sc, out_sc);
15fe47e0
PP
1716
1717end:
1718 return ret;
1719}
1720
1721BT_HIDDEN
335a2da5
PP
1722struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(
1723 struct fs_sink_comp *fs_sink, const bt_trace *ir_trace)
15fe47e0
PP
1724{
1725 uint64_t count;
1726 uint64_t i;
335a2da5 1727 struct fs_sink_ctf_trace *trace = NULL;
15fe47e0 1728
335a2da5
PP
1729 /* Check that trace's environment is TSDL-compatible */
1730 count = bt_trace_get_environment_entry_count(ir_trace);
15fe47e0
PP
1731 for (i = 0; i < count; i++) {
1732 const char *name;
1733 const bt_value *val;
1734
335a2da5
PP
1735 bt_trace_borrow_environment_entry_by_index_const(
1736 ir_trace, i, &name, &val);
15fe47e0 1737
45c51519 1738 if (!ist_valid_identifier(name)) {
aa1a7452
PP
1739 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1740 fs_sink->self_comp,
ffa3b2b3 1741 "Unsupported trace class's environment entry name: "
15fe47e0
PP
1742 "name=\"%s\"", name);
1743 goto end;
1744 }
1745
1746 switch (bt_value_get_type(val)) {
fdd3a2da 1747 case BT_VALUE_TYPE_SIGNED_INTEGER:
15fe47e0
PP
1748 case BT_VALUE_TYPE_STRING:
1749 break;
1750 default:
aa1a7452
PP
1751 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
1752 fs_sink->self_comp,
ffa3b2b3 1753 "Unsupported trace class's environment entry value type: "
15fe47e0
PP
1754 "type=%s",
1755 bt_common_value_type_string(
1756 bt_value_get_type(val)));
1757 goto end;
1758 }
1759 }
1760
335a2da5
PP
1761 trace = fs_sink_ctf_trace_create(ir_trace);
1762 BT_ASSERT(trace);
15fe47e0
PP
1763
1764end:
335a2da5 1765 return trace;
15fe47e0 1766}
This page took 0.12066 seconds and 4 git commands to generate.