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