sink.ctf.fs: Remove unused function
[babeltrace.git] / plugins / ctf / fs-sink / translate-trace-ir-to-ctf-ir.c
CommitLineData
46bdd3e0
PP
1/*
2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRANSLATE-TRACE-IR-TO-CTF-IR"
24#include "logging.h"
25
26#include <babeltrace/babeltrace.h>
27#include <babeltrace/babeltrace-internal.h>
28#include <babeltrace/common-internal.h>
29#include <babeltrace/assert-internal.h>
30#include <stdio.h>
31#include <stdbool.h>
32#include <string.h>
33#include <glib.h>
34
35#include "fs-sink-ctf-meta.h"
36
37struct field_path_elem {
38 uint64_t index_in_parent;
39 GString *name;
40
41 /* Weak */
42 const bt_field_class *ir_fc;
43
44 /* Weak */
45 struct fs_sink_ctf_field_class *parent_fc;
46};
47
48struct ctx {
49 /* Weak */
50 struct fs_sink_ctf_stream_class *cur_sc;
51
52 /* Weak */
53 struct fs_sink_ctf_event_class *cur_ec;
54
55 bt_scope cur_scope;
56
57 /*
58 * Array of `struct field_path_elem` */
59 GArray *cur_path;
60};
61
62static inline
63struct field_path_elem *cur_path_stack_at(struct ctx *ctx, uint64_t i)
64{
65 BT_ASSERT(i < ctx->cur_path->len);
66 return &g_array_index(ctx->cur_path, struct field_path_elem, i);
67}
68
69static inline
70struct field_path_elem *cur_path_stack_top(struct ctx *ctx)
71{
72 BT_ASSERT(ctx->cur_path->len > 0);
73 return cur_path_stack_at(ctx, ctx->cur_path->len - 1);
74}
75
76static inline
77bool is_reserved_member_name(const char *name, const char *reserved_name)
78{
79 bool is_reserved = false;
80
81 if (strcmp(name, reserved_name) == 0) {
82 is_reserved = true;
83 goto end;
84 }
85
86 if (name[0] == '_' && strcmp(&name[1], reserved_name) == 0) {
87 is_reserved = true;
88 goto end;
89 }
90
91end:
92 return is_reserved;
93}
94
95static inline
96int cur_path_stack_push(struct ctx *ctx,
97 uint64_t index_in_parent, const char *ir_name,
98 const bt_field_class *ir_fc,
99 struct fs_sink_ctf_field_class *parent_fc)
100{
101 int ret = 0;
102 struct field_path_elem *field_path_elem;
103
104 g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1);
105 field_path_elem = cur_path_stack_top(ctx);
106 field_path_elem->index_in_parent = index_in_parent;
107 field_path_elem->name = g_string_new(ir_name);
108
109 if (ir_name) {
110 if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) {
111 if (is_reserved_member_name(ir_name, "packet_size") ||
112 is_reserved_member_name(ir_name, "content_size") ||
113 is_reserved_member_name(ir_name, "timestamp_begin") ||
114 is_reserved_member_name(ir_name, "timestamp_end") ||
115 is_reserved_member_name(ir_name, "events_discarded") ||
116 is_reserved_member_name(ir_name, "packet_seq_num")) {
117 BT_LOGE("Unsupported reserved TSDL structure field class member "
118 "or variant field class option name: name=\"%s\"",
119 ir_name);
120 ret = -1;
121 goto end;
122 }
123 }
124
125 ret = fs_sink_ctf_protect_name(field_path_elem->name);
126 if (ret) {
127 BT_LOGE("Unsupported non-TSDL structure field class member "
128 "or variant field class option name: name=\"%s\"",
129 ir_name);
130 goto end;
131 }
132 }
133
134 field_path_elem->ir_fc = ir_fc;
135 field_path_elem->parent_fc = parent_fc;
136
137end:
138 return ret;
139}
140
141static inline
142void cur_path_stack_pop(struct ctx *ctx)
143{
144 struct field_path_elem *field_path_elem;
145
146 BT_ASSERT(ctx->cur_path->len > 0);
147 field_path_elem = cur_path_stack_top(ctx);
148
149 if (field_path_elem->name) {
150 g_string_free(field_path_elem->name, TRUE);
151 field_path_elem->name = NULL;
152 }
153
154 g_array_set_size(ctx->cur_path, ctx->cur_path->len - 1);
155}
156
46bdd3e0
PP
157/*
158 * Creates a relative field ref (a single name) from IR field path
159 * `tgt_ir_field_path`.
160 *
161 * This function tries to locate the target field class recursively from
162 * the top to the bottom of the context's current path using only the
163 * target field class's own name. This is because many CTF reading tools
164 * do not support a relative field ref with more than one element, for
165 * example `prev_struct.len`.
166 *
167 * Returns a negative value if this resolving operation failed.
168 */
169static
170int create_relative_field_ref(struct ctx *ctx,
171 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
172{
173 int ret = 0;
174 struct fs_sink_ctf_field_class *tgt_fc = NULL;
175 uint64_t i;
176 int64_t si;
177 const char *tgt_fc_name;
178 struct field_path_elem *field_path_elem;
179
180 /* Get target field class's name */
181 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
182 case BT_SCOPE_PACKET_CONTEXT:
183 BT_ASSERT(ctx->cur_sc);
184 tgt_fc = ctx->cur_sc->packet_context_fc;
185 break;
186 case BT_SCOPE_EVENT_COMMON_CONTEXT:
187 BT_ASSERT(ctx->cur_sc);
188 tgt_fc = ctx->cur_sc->event_common_context_fc;
189 break;
190 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
191 BT_ASSERT(ctx->cur_ec);
192 tgt_fc = ctx->cur_ec->spec_context_fc;
193 break;
194 case BT_SCOPE_EVENT_PAYLOAD:
195 BT_ASSERT(ctx->cur_ec);
196 tgt_fc = ctx->cur_ec->payload_fc;
197 break;
198 default:
199 abort();
200 }
201
202 i = 0;
203
204 while (i < bt_field_path_get_index_count(tgt_ir_field_path)) {
205 uint64_t index = bt_field_path_get_index_by_index(
206 tgt_ir_field_path, i);
207 struct fs_sink_ctf_named_field_class *named_fc = NULL;
208
209 BT_ASSERT(tgt_fc);
210
211 switch (tgt_fc->type) {
212 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
213 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
214 (void *) tgt_fc, index);
215 break;
216 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
217 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
218 (void *) tgt_fc, index);
219 break;
220 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
221 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
222 {
223 struct fs_sink_ctf_field_class_array_base *array_base_fc =
224 (void *) tgt_fc;
225
226 tgt_fc = array_base_fc->elem_fc;
227 break;
228 }
229 default:
230 abort();
231 }
232
233 if (named_fc) {
234 tgt_fc = named_fc->fc;
235 tgt_fc_name = named_fc->name->str;
236 i++;
237 }
238 }
239
240 BT_ASSERT(tgt_fc);
241 BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
242 BT_ASSERT(tgt_fc_name);
243
244 /* Find target field class having this name in current context */
245 for (si = ctx->cur_path->len - 1; si >= 0; si--) {
246 struct fs_sink_ctf_field_class *fc;
247 struct fs_sink_ctf_field_class_struct *struct_fc;
248 struct fs_sink_ctf_field_class_variant *var_fc;
249 struct fs_sink_ctf_named_field_class *named_fc;
250 uint64_t len;
251
252 field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
253 fc = field_path_elem->parent_fc;
254 if (!fc) {
255 /* Reached stack's bottom */
256 ret = -1;
257 goto end;
258 }
259
260 switch (fc->type) {
261 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
262 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
263 break;
264 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
265 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
266 continue;
267 default:
268 /* Not supported by TSDL 1.8 */
269 ret = -1;
270 goto end;
271 }
272
273 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
274 struct_fc = (void *) fc;
275 len = struct_fc->members->len;
276 } else {
277 var_fc = (void *) fc;
278 len = var_fc->options->len;
279 }
280
281 for (i = 0; i < len; i++) {
282 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
283 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
284 struct_fc, i);
285 } else {
286 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
287 var_fc, i);
288 }
289
290 if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
291 if (named_fc->fc == tgt_fc) {
292 g_string_assign(tgt_field_ref,
293 tgt_fc_name);
294 } else {
295 /*
296 * Using only the target field
297 * class's name, we're not
298 * reaching the target field
299 * class. This is not supported
300 * by TSDL 1.8.
301 */
302 ret = -1;
303 }
304
305 goto end;
306 }
307 }
308 }
309
310end:
311 return ret;
312}
313
314/*
315 * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
316 *
317 * Returns a negative value if this resolving operation failed.
318 */
319static
320int create_absolute_field_ref(struct ctx *ctx,
321 const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
322{
323 int ret = 0;
324 struct fs_sink_ctf_field_class *fc = NULL;
325 uint64_t i;
326
327 switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
328 case BT_SCOPE_PACKET_CONTEXT:
329 BT_ASSERT(ctx->cur_sc);
330 fc = ctx->cur_sc->packet_context_fc;
331 g_string_assign(tgt_field_ref, "stream.packet.context");
332 break;
333 case BT_SCOPE_EVENT_COMMON_CONTEXT:
334 BT_ASSERT(ctx->cur_sc);
335 fc = ctx->cur_sc->event_common_context_fc;
336 g_string_assign(tgt_field_ref, "stream.event.context");
337 break;
338 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
339 BT_ASSERT(ctx->cur_ec);
340 fc = ctx->cur_ec->spec_context_fc;
341 g_string_assign(tgt_field_ref, "event.context");
342 break;
343 case BT_SCOPE_EVENT_PAYLOAD:
344 BT_ASSERT(ctx->cur_ec);
345 fc = ctx->cur_ec->payload_fc;
346 g_string_assign(tgt_field_ref, "event.fields");
347 break;
348 default:
349 abort();
350 }
351
352 BT_ASSERT(fc);
353
354 for (i = 0; i < bt_field_path_get_index_count(tgt_ir_field_path); i++) {
355 uint64_t index = bt_field_path_get_index_by_index(
356 tgt_ir_field_path, i);
357 struct fs_sink_ctf_named_field_class *named_fc = NULL;
358
359 switch (fc->type) {
360 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
361 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
362 (void *) fc, index);
363 break;
364 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
365 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
366 (void *) fc, index);
367 break;
368 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
369 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
370 /* Not supported by TSDL 1.8 */
371 ret = -1;
372 goto end;
373 default:
374 abort();
375 }
376
377 BT_ASSERT(named_fc);
378 g_string_append_c(tgt_field_ref, '.');
379 g_string_append(tgt_field_ref, named_fc->name->str);
380 fc = named_fc->fc;
381 }
382
383end:
384 return ret;
385}
386
387/*
388 * Resolves a target field class located at `tgt_ir_field_path`, writing
389 * the resolved field ref to `tgt_field_ref` and setting
390 * `*create_before` according to whether or not the target field must be
391 * created immediately before (in which case `tgt_field_ref` is
392 * irrelevant).
393 */
394static
395void resolve_field_class(struct ctx *ctx,
396 const bt_field_path *tgt_ir_field_path,
397 GString *tgt_field_ref, bool *create_before)
398{
399 int ret;
400 bt_scope tgt_scope;
401
402 *create_before = false;
403
404 if (!tgt_ir_field_path) {
405 *create_before = true;
406 goto end;
407 }
408
409 tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
410
411 if (tgt_scope == ctx->cur_scope) {
412 /*
413 * Try, in this order:
414 *
415 * 1. Use a relative path, using only the target field
416 * class's name. This is what is the most commonly
417 * supported by popular CTF reading tools.
418 *
419 * 2. Use an absolute path. This could fail if there's
420 * an array field class from the current root's field
421 * class to the target field class.
422 *
423 * 3. Create the target field class before the
424 * requesting field class (fallback).
425 */
426 ret = create_relative_field_ref(ctx, tgt_ir_field_path,
427 tgt_field_ref);
428 if (ret) {
429 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
430 tgt_field_ref);
431 if (ret) {
432 *create_before = true;
433 ret = 0;
434 goto end;
435 }
436 }
437 } else {
438 ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
439 tgt_field_ref);
440
441 /* It must always work in previous scopes */
442 BT_ASSERT(ret == 0);
443 }
444
445end:
446 return;
447}
448
449static
450int translate_field_class(struct ctx *ctx);
451
452static inline
453void append_to_parent_field_class(struct ctx *ctx,
454 struct fs_sink_ctf_field_class *fc)
455{
456 struct fs_sink_ctf_field_class *parent_fc =
457 cur_path_stack_top(ctx)->parent_fc;
458
459 switch (parent_fc->type) {
460 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
461 fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
462 cur_path_stack_top(ctx)->name->str, fc);
463 break;
464 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
465 fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
466 cur_path_stack_top(ctx)->name->str, fc);
467 break;
468 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
469 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
470 {
471 struct fs_sink_ctf_field_class_array_base *array_base_fc =
472 (void *) parent_fc;
473
474 BT_ASSERT(!array_base_fc->elem_fc);
475 array_base_fc->elem_fc = fc;
476 array_base_fc->base.alignment = fc->alignment;
477 break;
478 }
479 default:
480 abort();
481 }
482}
483
484static inline
485void update_parent_field_class_alignment(struct ctx *ctx,
486 unsigned int alignment)
487{
488 struct fs_sink_ctf_field_class *parent_fc =
489 cur_path_stack_top(ctx)->parent_fc;
490
491 switch (parent_fc->type) {
492 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
493 fs_sink_ctf_field_class_struct_align_at_least(
494 (void *) parent_fc, alignment);
495 break;
496 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
497 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
498 {
499 struct fs_sink_ctf_field_class_array_base *array_base_fc =
500 (void *) parent_fc;
501
502 array_base_fc->base.alignment = alignment;
503 break;
504 }
505 default:
506 break;
507 }
508}
509
510static inline
511int translate_structure_field_class_members(struct ctx *ctx,
512 struct fs_sink_ctf_field_class_struct *struct_fc,
513 const bt_field_class *ir_fc)
514{
515 int ret = 0;
516 uint64_t i;
517
518 for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
519 const bt_field_class_structure_member *member;
520 const char *name;
521 const bt_field_class *memb_ir_fc;
522
523 member =
524 bt_field_class_structure_borrow_member_by_index_const(
525 ir_fc, i);
526 name = bt_field_class_structure_member_get_name(member);
527 memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
528 member);
529 ret = cur_path_stack_push(ctx, i, name, memb_ir_fc,
530 (void *) struct_fc);
531 if (ret) {
532 BT_LOGE("Cannot translate structure field class member: "
533 "name=\"%s\"", name);
534 goto end;
535 }
536
537 ret = translate_field_class(ctx);
538 if (ret) {
539 BT_LOGE("Cannot translate structure field class member: "
540 "name=\"%s\"", name);
541 goto end;
542 }
543
544 cur_path_stack_pop(ctx);
545 }
546
547end:
548 return ret;
549}
550
551static inline
552int translate_structure_field_class(struct ctx *ctx)
553{
554 int ret;
555 struct fs_sink_ctf_field_class_struct *fc =
556 fs_sink_ctf_field_class_struct_create_empty(
557 cur_path_stack_top(ctx)->ir_fc,
558 cur_path_stack_top(ctx)->index_in_parent);
559
560 BT_ASSERT(fc);
561 append_to_parent_field_class(ctx, (void *) fc);
562 ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
563 if (ret) {
564 goto end;
565 }
566
567 update_parent_field_class_alignment(ctx, fc->base.alignment);
568
569end:
570 return ret;
571}
572
573static inline
574int translate_variant_field_class(struct ctx *ctx)
575{
576 int ret = 0;
577 uint64_t i;
578 struct fs_sink_ctf_field_class_variant *fc =
579 fs_sink_ctf_field_class_variant_create_empty(
580 cur_path_stack_top(ctx)->ir_fc,
581 cur_path_stack_top(ctx)->index_in_parent);
582
583 BT_ASSERT(fc);
584
585 /* Resolve tag field class before appending to parent */
586 resolve_field_class(ctx,
587 bt_field_class_variant_borrow_selector_field_path_const(
588 fc->base.ir_fc), fc->tag_ref, &fc->tag_is_before);
589
590 append_to_parent_field_class(ctx, (void *) fc);
591
592 for (i = 0; i < bt_field_class_variant_get_option_count(fc->base.ir_fc);
593 i++) {
594 const bt_field_class_variant_option *opt;
595 const char *name;
596 const bt_field_class *opt_ir_fc;
597
598 opt = bt_field_class_variant_borrow_option_by_index_const(
599 fc->base.ir_fc, i);
600 name = bt_field_class_variant_option_get_name(opt);
601 opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
602 opt);
603 ret = cur_path_stack_push(ctx, i, name, opt_ir_fc, (void *) fc);
604 if (ret) {
605 BT_LOGE("Cannot translate variant field class option: "
606 "name=\"%s\"", name);
607 goto end;
608 }
609
610 ret = translate_field_class(ctx);
611 if (ret) {
612 BT_LOGE("Cannot translate variant field class option: "
613 "name=\"%s\"", name);
614 goto end;
615 }
616
617 cur_path_stack_pop(ctx);
618 }
619
620end:
621 return ret;
622}
623
624static inline
625int translate_static_array_field_class(struct ctx *ctx)
626{
627 struct fs_sink_ctf_field_class_array *fc =
628 fs_sink_ctf_field_class_array_create_empty(
629 cur_path_stack_top(ctx)->ir_fc,
630 cur_path_stack_top(ctx)->index_in_parent);
631 const bt_field_class *elem_ir_fc =
632 bt_field_class_array_borrow_element_field_class_const(
633 fc->base.base.ir_fc);
634 int ret;
635
636 BT_ASSERT(fc);
637 append_to_parent_field_class(ctx, (void *) fc);
638 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
639 (void *) fc);
640 if (ret) {
641 BT_LOGE_STR("Cannot translate static array field class element.");
642 goto end;
643 }
644
645 ret = translate_field_class(ctx);
646 if (ret) {
647 BT_LOGE_STR("Cannot translate static array field class element.");
648 goto end;
649 }
650
651 cur_path_stack_pop(ctx);
652 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
653
654end:
655 return ret;
656}
657
658static inline
659int translate_dynamic_array_field_class(struct ctx *ctx)
660{
661 struct fs_sink_ctf_field_class_sequence *fc =
662 fs_sink_ctf_field_class_sequence_create_empty(
663 cur_path_stack_top(ctx)->ir_fc,
664 cur_path_stack_top(ctx)->index_in_parent);
665 const bt_field_class *elem_ir_fc =
666 bt_field_class_array_borrow_element_field_class_const(
667 fc->base.base.ir_fc);
668 int ret;
669
670 BT_ASSERT(fc);
671
672 /* Resolve length field class before appending to parent */
673 resolve_field_class(ctx,
674 bt_field_class_dynamic_array_borrow_length_field_path_const(
675 fc->base.base.ir_fc),
676 fc->length_ref, &fc->length_is_before);
677
678 append_to_parent_field_class(ctx, (void *) fc);
679 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
680 (void *) fc);
681 if (ret) {
682 BT_LOGE_STR("Cannot translate dynamic array field class element.");
683 goto end;
684 }
685
686 ret = translate_field_class(ctx);
687 if (ret) {
688 BT_LOGE_STR("Cannot translate dynamic array field class element.");
689 goto end;
690 }
691
692 cur_path_stack_pop(ctx);
693 update_parent_field_class_alignment(ctx, fc->base.base.alignment);
694
695end:
696 return ret;
697}
698
699static inline
700int translate_integer_field_class(struct ctx *ctx)
701{
702 struct fs_sink_ctf_field_class_int *fc =
703 fs_sink_ctf_field_class_int_create(
704 cur_path_stack_top(ctx)->ir_fc,
705 cur_path_stack_top(ctx)->index_in_parent);
706
707 BT_ASSERT(fc);
708 append_to_parent_field_class(ctx, (void *) fc);
709 return 0;
710}
711
712static inline
713int translate_real_field_class(struct ctx *ctx)
714{
715 struct fs_sink_ctf_field_class_float *fc =
716 fs_sink_ctf_field_class_float_create(
717 cur_path_stack_top(ctx)->ir_fc,
718 cur_path_stack_top(ctx)->index_in_parent);
719
720 BT_ASSERT(fc);
721 append_to_parent_field_class(ctx, (void *) fc);
722 return 0;
723}
724
725static inline
726int translate_string_field_class(struct ctx *ctx)
727{
728 struct fs_sink_ctf_field_class_string *fc =
729 fs_sink_ctf_field_class_string_create(
730 cur_path_stack_top(ctx)->ir_fc,
731 cur_path_stack_top(ctx)->index_in_parent);
732
733 BT_ASSERT(fc);
734 append_to_parent_field_class(ctx, (void *) fc);
735 return 0;
736}
737
738/*
739 * Translates a field class, recursively.
740 *
741 * The field class's IR field class, parent field class, and index
742 * within its parent are in the context's current path's top element
743 * (cur_path_stack_top()).
744 */
745static
746int translate_field_class(struct ctx *ctx)
747{
748 int ret;
749
750 switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
751 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
752 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
753 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
754 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
755 ret = translate_integer_field_class(ctx);
756 break;
757 case BT_FIELD_CLASS_TYPE_REAL:
758 ret = translate_real_field_class(ctx);
759 break;
760 case BT_FIELD_CLASS_TYPE_STRING:
761 ret = translate_string_field_class(ctx);
762 break;
763 case BT_FIELD_CLASS_TYPE_STRUCTURE:
764 ret = translate_structure_field_class(ctx);
765 break;
766 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
767 ret = translate_static_array_field_class(ctx);
768 break;
769 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
770 ret = translate_dynamic_array_field_class(ctx);
771 break;
772 case BT_FIELD_CLASS_TYPE_VARIANT:
773 ret = translate_variant_field_class(ctx);
774 break;
775 default:
776 abort();
777 }
778
779 return ret;
780}
781
782static
783int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
784 struct fs_sink_ctf_field_class *parent_fc)
785{
786 int ret = 0;
787 GString *field_ref = NULL;
788 bool is_before;
789 const char *tgt_type;
790 struct fs_sink_ctf_field_class_struct *parent_struct_fc =
791 (void *) parent_fc;
792 uint64_t i;
793 unsigned int suffix = 0;
794
795 if (!fc_name || !parent_fc ||
796 parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
797 /* Not supported */
798 ret = -1;
799 goto end;
800 }
801
802 switch (fc->type) {
803 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
804 {
805 struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
806
807 field_ref = seq_fc->length_ref;
808 is_before = seq_fc->length_is_before;
809 tgt_type = "len";
810 break;
811 }
812 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
813 {
814 struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
815
816 field_ref = var_fc->tag_ref;
817 is_before = var_fc->tag_is_before;
818 tgt_type = "tag";
819 break;
820 }
821 default:
822 abort();
823 }
824
825 BT_ASSERT(field_ref);
826
827 if (!is_before) {
828 goto end;
829 }
830
831 /* Initial field ref */
832 g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
833
834 /*
835 * Make sure field ref does not clash with an existing field
836 * class name within the same parent structure field class.
837 */
838 while (true) {
839 bool name_ok = true;
840
841 for (i = 0; i < parent_struct_fc->members->len; i++) {
842 struct fs_sink_ctf_named_field_class *named_fc =
843 fs_sink_ctf_field_class_struct_borrow_member_by_index(
844 parent_struct_fc, i);
845
846 if (strcmp(field_ref->str, named_fc->name->str) == 0) {
847 /* Name clash */
848 name_ok = false;
849 break;
850 }
851 }
852
853 if (name_ok) {
854 /* No clash: we're done */
855 break;
856 }
857
858 /* Append suffix and try again */
859 g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
860 suffix);
861 suffix++;
862 }
863
864end:
865 return ret;
866}
867
868/*
869 * This function recursively sets field refs of sequence and variant
870 * field classes when they are immediately before, avoiding name clashes
871 * with existing field class names.
872 *
873 * It can fail at this point if, for example, a sequence field class of
874 * which to set the length's field ref has something else than a
875 * structure field class as its parent: in this case, there's no
876 * location to place the length field class immediately before the
877 * sequence field class.
878 */
879static
880int set_field_refs(struct fs_sink_ctf_field_class *fc, const char *fc_name,
881 struct fs_sink_ctf_field_class *parent_fc)
882{
883 int ret = 0;
884 BT_ASSERT(fc);
885
886 switch (fc->type) {
887 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
888 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
889 {
890 uint64_t i;
891 uint64_t len;
892 struct fs_sink_ctf_field_class_struct *struct_fc;
893 struct fs_sink_ctf_field_class_variant *var_fc;
894 struct fs_sink_ctf_named_field_class *named_fc;
895
896 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
897 struct_fc = (void *) fc;
898 len = struct_fc->members->len;
899 } else {
900 var_fc = (void *) fc;
901 len = var_fc->options->len;
902 ret = set_field_ref(fc, fc_name, parent_fc);
903 if (ret) {
904 goto end;
905 }
906 }
907
908 for (i = 0; i < len; i++) {
909 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
910 named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
911 struct_fc, i);
912 } else {
913 named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
914 var_fc, i);
915 }
916
917 ret = set_field_refs(named_fc->fc, named_fc->name->str,
918 fc);
919 if (ret) {
920 goto end;
921 }
922 }
923
924 break;
925 }
926 case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
927 case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
928 {
929 struct fs_sink_ctf_field_class_array_base *array_base_fc =
930 (void *) fc;
931
932 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
933 ret = set_field_ref(fc, fc_name, parent_fc);
934 if (ret) {
935 goto end;
936 }
937 }
938
939 ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
940 if (ret) {
941 goto end;
942 }
943
944 break;
945 }
946 default:
947 break;
948 }
949
950end:
951 return ret;
952}
953
954/*
955 * This function translates a root scope trace IR field class to
956 * a CTF IR field class.
957 *
958 * The resulting CTF IR field class is written to `*fc` so that it
959 * exists as the parent object's (stream class or event class) true root
960 * field class during the recursive translation for resolving purposes.
961 * This is also why this function creates the empty structure field
962 * class and then calls translate_structure_field_class_members() to
963 * fill it.
964 */
965static
966int translate_scope_field_class(struct ctx *ctx, bt_scope scope,
967 struct fs_sink_ctf_field_class **fc,
968 const bt_field_class *ir_fc)
969{
970 int ret = 0;
971
972 if (!ir_fc) {
973 goto end;
974 }
975
976 BT_ASSERT(bt_field_class_get_type(ir_fc) ==
977 BT_FIELD_CLASS_TYPE_STRUCTURE);
978 BT_ASSERT(fc);
979 *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
980 ir_fc, UINT64_C(-1));
981 BT_ASSERT(*fc);
982 ctx->cur_scope = scope;
983 BT_ASSERT(ctx->cur_path->len == 0);
984 ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, ir_fc, NULL);
985 if (ret) {
986 BT_LOGE("Cannot translate scope structure field class: "
987 "scope=%d", scope);
988 goto end;
989 }
990
991 ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
992 if (ret) {
993 BT_LOGE("Cannot translate scope structure field class: "
994 "scope=%d", scope);
995 goto end;
996 }
997
998 cur_path_stack_pop(ctx);
999
1000 /* Set field refs for preceding targets */
1001 ret = set_field_refs(*fc, NULL, NULL);
1002
1003end:
1004 return ret;
1005}
1006
1007static inline
1008void ctx_init(struct ctx *ctx)
1009{
1010 memset(ctx, 0, sizeof(struct ctx));
1011 ctx->cur_path = g_array_new(FALSE, TRUE,
1012 sizeof(struct field_path_elem));
1013 BT_ASSERT(ctx->cur_path);
1014}
1015
1016static inline
1017void ctx_fini(struct ctx *ctx)
1018{
1019 if (ctx->cur_path) {
1020 g_array_free(ctx->cur_path, TRUE);
1021 ctx->cur_path = NULL;
1022 }
1023}
1024
1025static
1026int translate_event_class(struct fs_sink_ctf_stream_class *sc,
1027 const bt_event_class *ir_ec,
1028 struct fs_sink_ctf_event_class **out_ec)
1029{
1030 int ret = 0;
1031 struct ctx ctx;
1032 struct fs_sink_ctf_event_class *ec;
1033
1034 BT_ASSERT(sc);
1035 BT_ASSERT(ir_ec);
1036
1037 ctx_init(&ctx);
1038 ec = fs_sink_ctf_event_class_create(sc, ir_ec);
1039 BT_ASSERT(ec);
1040 ctx.cur_sc = sc;
1041 ctx.cur_ec = ec;
1042 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
1043 &ec->spec_context_fc,
1044 bt_event_class_borrow_specific_context_field_class_const(
1045 ir_ec));
1046 if (ret) {
1047 goto end;
1048 }
1049
1050 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_PAYLOAD,
1051 &ec->payload_fc,
1052 bt_event_class_borrow_payload_field_class_const(ir_ec));
1053 if (ret) {
1054 goto end;
1055 }
1056
1057end:
1058 ctx_fini(&ctx);
1059 *out_ec = ec;
1060 return ret;
1061}
1062
1063BT_HIDDEN
1064int try_translate_event_class_trace_ir_to_ctf_ir(
1065 struct fs_sink_ctf_stream_class *sc,
1066 const bt_event_class *ir_ec,
1067 struct fs_sink_ctf_event_class **out_ec)
1068{
1069 int ret = 0;
1070
1071 BT_ASSERT(sc);
1072 BT_ASSERT(ir_ec);
1073
1074 /* Check in hash table first */
1075 *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
1076 if (likely(*out_ec)) {
1077 goto end;
1078 }
1079
1080 ret = translate_event_class(sc, ir_ec, out_ec);
1081
1082end:
1083 return ret;
1084}
1085
1086bool default_clock_class_name_exists(struct fs_sink_ctf_trace_class *tc,
1087 const char *name)
1088{
1089 bool exists = false;
1090 uint64_t i;
1091
1092 for (i = 0; i < tc->stream_classes->len; i++) {
1093 struct fs_sink_ctf_stream_class *sc =
1094 tc->stream_classes->pdata[i];
1095
1096 if (sc->default_clock_class_name->len == 0) {
1097 /* No default clock class */
1098 continue;
1099 }
1100
1101 if (strcmp(sc->default_clock_class_name->str, name) == 0) {
1102 exists = true;
1103 goto end;
1104 }
1105 }
1106
1107end:
1108 return exists;
1109}
1110
1111static
1112void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
1113{
1114 unsigned int suffix = 0;
1115 char buf[16];
1116
1117 g_string_assign(sc->default_clock_class_name, "");
1118 sprintf(buf, "default");
1119
1120 while (default_clock_class_name_exists(sc->tc, buf)) {
1121 sprintf(buf, "default%u", suffix);
1122 suffix++;
1123 }
1124
1125 g_string_assign(sc->default_clock_class_name, buf);
1126}
1127
1128static
1129int translate_stream_class(struct fs_sink_ctf_trace_class *tc,
1130 const bt_stream_class *ir_sc,
1131 struct fs_sink_ctf_stream_class **out_sc)
1132{
1133 int ret = 0;
1134 struct ctx ctx;
1135
1136 BT_ASSERT(tc);
1137 BT_ASSERT(ir_sc);
1138 ctx_init(&ctx);
1139 *out_sc = fs_sink_ctf_stream_class_create(tc, ir_sc);
1140 BT_ASSERT(*out_sc);
1141
1142 /* Set default clock class's protected name, if any */
1143 if ((*out_sc)->default_clock_class) {
1144 const char *name = bt_clock_class_get_name(
1145 (*out_sc)->default_clock_class);
1146
1147 if (!bt_stream_class_default_clock_is_always_known(ir_sc)) {
1148 BT_LOGE("Unsupported stream clock which can have an unknown value: "
1149 "sc-name=\"%s\"",
1150 bt_stream_class_get_name(ir_sc));
1151 goto error;
1152 }
1153
1154 if (name) {
1155 /* Try original name, protected */
1156 g_string_assign((*out_sc)->default_clock_class_name,
1157 name);
1158 ret = fs_sink_ctf_protect_name(
1159 (*out_sc)->default_clock_class_name);
1160 if (ret) {
1161 /* Invalid: create a new name */
1162 make_unique_default_clock_class_name(*out_sc);
1163 ret = 0;
1164 }
1165 } else {
1166 /* No name: create a name */
1167 make_unique_default_clock_class_name(*out_sc);
1168 }
1169 }
1170
1171 ctx.cur_sc = *out_sc;
1172 ret = translate_scope_field_class(&ctx, BT_SCOPE_PACKET_CONTEXT,
1173 &(*out_sc)->packet_context_fc,
1174 bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
1175 if (ret) {
1176 goto error;
1177 }
1178
1179 if ((*out_sc)->packet_context_fc) {
1180 /*
1181 * Make sure the structure field class's alignment is
1182 * enough: 8 is what we use for our own special members
1183 * in the packet context.
1184 */
1185 fs_sink_ctf_field_class_struct_align_at_least(
1186 (void *) (*out_sc)->packet_context_fc, 8);
1187 }
1188
1189 ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_COMMON_CONTEXT,
1190 &(*out_sc)->event_common_context_fc,
1191 bt_stream_class_borrow_event_common_context_field_class_const(
1192 ir_sc));
1193 if (ret) {
1194 goto error;
1195 }
1196
1197 goto end;
1198
1199error:
1200 fs_sink_ctf_stream_class_destroy(*out_sc);
1201 *out_sc = NULL;
1202
1203end:
1204 ctx_fini(&ctx);
1205 return ret;
1206}
1207
1208BT_HIDDEN
1209int try_translate_stream_class_trace_ir_to_ctf_ir(
1210 struct fs_sink_ctf_trace_class *tc,
1211 const bt_stream_class *ir_sc,
1212 struct fs_sink_ctf_stream_class **out_sc)
1213{
1214 int ret = 0;
1215 uint64_t i;
1216
1217 BT_ASSERT(tc);
1218 BT_ASSERT(ir_sc);
1219
1220 for (i = 0; i < tc->stream_classes->len; i++) {
1221 *out_sc = tc->stream_classes->pdata[i];
1222
1223 if ((*out_sc)->ir_sc == ir_sc) {
1224 goto end;
1225 }
1226 }
1227
1228 ret = translate_stream_class(tc, ir_sc, out_sc);
1229
1230end:
1231 return ret;
1232}
1233
1234BT_HIDDEN
1235struct fs_sink_ctf_trace_class *translate_trace_class_trace_ir_to_ctf_ir(
1236 const bt_trace_class *ir_tc)
1237{
1238 uint64_t count;
1239 uint64_t i;
1240 struct fs_sink_ctf_trace_class *tc = NULL;
1241
1242 /* Check that trace class's environment is TSDL-compatible */
1243 count = bt_trace_class_get_environment_entry_count(ir_tc);
1244 for (i = 0; i < count; i++) {
1245 const char *name;
1246 const bt_value *val;
1247
1248 bt_trace_class_borrow_environment_entry_by_index_const(
1249 ir_tc, i, &name, &val);
1250
1251 if (!fs_sink_ctf_ist_valid_identifier(name)) {
1252 BT_LOGE("Unsupported trace class's environment entry name: "
1253 "name=\"%s\"", name);
1254 goto end;
1255 }
1256
1257 switch (bt_value_get_type(val)) {
1258 case BT_VALUE_TYPE_INTEGER:
1259 case BT_VALUE_TYPE_STRING:
1260 break;
1261 default:
1262 BT_LOGE("Unsupported trace class's environment entry value type: "
1263 "type=%s",
1264 bt_common_value_type_string(
1265 bt_value_get_type(val)));
1266 goto end;
1267 }
1268 }
1269
1270 tc = fs_sink_ctf_trace_class_create(ir_tc);
1271 BT_ASSERT(tc);
1272
1273end:
1274 return tc;
1275}
This page took 0.067922 seconds and 4 git commands to generate.