c93db6a6e2682134419db9f1f28d5ad97de49872
[babeltrace.git] / src / plugins / ctf / fs-sink / translate-ctf-ir-to-tsdl.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
5 */
6
7 #include "translate-ctf-ir-to-tsdl.hpp"
8
9 #include <babeltrace2/babeltrace.h>
10 #include "common/macros.h"
11 #include <stdio.h>
12 #include <stdbool.h>
13 #include <string.h>
14 #include <glib.h>
15 #include "common/assert.h"
16 #include "compat/endian.h"
17
18 #include "fs-sink-ctf-meta.hpp"
19
20 struct ctx {
21 unsigned int indent_level;
22 GString *tsdl;
23 };
24
25 static inline
26 void append_indent(struct ctx *ctx)
27 {
28 unsigned int i;
29
30 for (i = 0; i < ctx->indent_level; i++) {
31 g_string_append_c(ctx->tsdl, '\t');
32 }
33 }
34
35 static
36 void append_uuid(struct ctx *ctx, bt_uuid uuid)
37 {
38 g_string_append_printf(ctx->tsdl,
39 "\"" BT_UUID_FMT "\"",
40 BT_UUID_FMT_VALUES(uuid));
41 }
42
43 static
44 void append_quoted_string_content(struct ctx *ctx, const char *str)
45 {
46 const char *ch;
47
48 for (ch = str; *ch != '\0'; ch++) {
49 unsigned char uch = (unsigned char) *ch;
50
51 if (uch < 32 || uch >= 127) {
52 switch (*ch) {
53 case '\a':
54 g_string_append(ctx->tsdl, "\\a");
55 break;
56 case '\b':
57 g_string_append(ctx->tsdl, "\\b");
58 break;
59 case '\f':
60 g_string_append(ctx->tsdl, "\\f");
61 break;
62 case '\n':
63 g_string_append(ctx->tsdl, "\\n");
64 break;
65 case '\r':
66 g_string_append(ctx->tsdl, "\\r");
67 break;
68 case '\t':
69 g_string_append(ctx->tsdl, "\\t");
70 break;
71 case '\v':
72 g_string_append(ctx->tsdl, "\\v");
73 break;
74 default:
75 g_string_append_printf(ctx->tsdl, "\\x%02x",
76 (unsigned int) uch);
77 break;
78 }
79 } else if (*ch == '"' || *ch == '\\') {
80 g_string_append_c(ctx->tsdl, '\\');
81 g_string_append_c(ctx->tsdl, *ch);
82 } else {
83 g_string_append_c(ctx->tsdl, *ch);
84 }
85 }
86 }
87
88 static
89 void append_quoted_string(struct ctx *ctx, const char *str)
90 {
91 g_string_append_c(ctx->tsdl, '"');
92 append_quoted_string_content(ctx, str);
93 g_string_append_c(ctx->tsdl, '"');
94 }
95
96 static
97 void append_integer_field_class_from_props(struct ctx *ctx, unsigned int size,
98 unsigned int alignment, bool is_signed,
99 bt_field_class_integer_preferred_display_base disp_base,
100 const char *mapped_clock_class_name, const char *field_name,
101 bool end)
102 {
103 g_string_append_printf(ctx->tsdl,
104 "integer { size = %u; align = %u;",
105 size, alignment);
106
107 if (is_signed) {
108 g_string_append(ctx->tsdl, " signed = true;");
109 }
110
111 if (disp_base != BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL) {
112 g_string_append(ctx->tsdl, " base = ");
113
114 switch (disp_base) {
115 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
116 g_string_append(ctx->tsdl, "b");
117 break;
118 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
119 g_string_append(ctx->tsdl, "o");
120 break;
121 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
122 g_string_append(ctx->tsdl, "x");
123 break;
124 default:
125 bt_common_abort();
126 }
127
128 g_string_append_c(ctx->tsdl, ';');
129 }
130
131 if (mapped_clock_class_name) {
132 g_string_append_printf(ctx->tsdl, " map = clock.%s.value;",
133 mapped_clock_class_name);
134 }
135
136 g_string_append(ctx->tsdl, " }");
137
138 if (field_name) {
139 g_string_append_printf(ctx->tsdl, " %s", field_name);
140 }
141
142 if (end) {
143 g_string_append(ctx->tsdl, ";\n");
144 }
145 }
146
147 static
148 void append_end_block(struct ctx *ctx)
149 {
150 ctx->indent_level--;
151 append_indent(ctx);
152 g_string_append(ctx->tsdl, "}");
153 }
154
155 static
156 void append_end_block_semi_nl(struct ctx *ctx)
157 {
158 ctx->indent_level--;
159 append_indent(ctx);
160 g_string_append(ctx->tsdl, "};\n");
161 }
162
163 static
164 void append_end_block_semi_nl_nl(struct ctx *ctx)
165 {
166 append_end_block_semi_nl(ctx);
167 g_string_append_c(ctx->tsdl, '\n');
168 }
169
170 static
171 void append_bool_field_class(struct ctx *ctx,
172 __attribute__((unused)) struct fs_sink_ctf_field_class_bool *fc)
173 {
174 /*
175 * CTF 1.8 has no boolean field class type, so this component
176 * translates it to an 8-bit unsigned integer field class.
177 */
178 append_integer_field_class_from_props(ctx, fc->base.size,
179 fc->base.base.alignment, false,
180 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
181 NULL, NULL, false);
182 }
183
184 static
185 void append_bit_array_field_class(struct ctx *ctx,
186 struct fs_sink_ctf_field_class_bit_array *fc)
187 {
188 /*
189 * CTF 1.8 has no bit array field class type, so this component
190 * translates it to an unsigned integer field class with an
191 * hexadecimal base.
192 */
193 append_integer_field_class_from_props(ctx, fc->size,
194 fc->base.alignment, false,
195 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
196 NULL, NULL, false);
197 }
198
199 static
200 void append_integer_field_class(struct ctx *ctx,
201 struct fs_sink_ctf_field_class_int *fc)
202 {
203 const bt_field_class *ir_fc = fc->base.base.ir_fc;
204 bt_field_class_type type = bt_field_class_get_type(ir_fc);
205 bool is_signed = bt_field_class_type_is(type,
206 BT_FIELD_CLASS_TYPE_SIGNED_INTEGER);
207
208 if (bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_ENUMERATION)) {
209 g_string_append(ctx->tsdl, "enum : ");
210 }
211
212 append_integer_field_class_from_props(ctx, fc->base.size,
213 fc->base.base.alignment, is_signed,
214 bt_field_class_integer_get_preferred_display_base(ir_fc),
215 NULL, NULL, false);
216
217 if (bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_ENUMERATION)) {
218 uint64_t i;
219
220 g_string_append(ctx->tsdl, " {\n");
221 ctx->indent_level++;
222
223 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_fc); i++) {
224 const char *label;
225 const bt_field_class_enumeration_mapping *mapping;
226 const bt_field_class_enumeration_unsigned_mapping *u_mapping;
227 const bt_field_class_enumeration_signed_mapping *s_mapping;
228 const bt_integer_range_set *ranges;
229 const bt_integer_range_set_unsigned *u_ranges;
230 const bt_integer_range_set_signed *s_ranges;
231 uint64_t range_count;
232 uint64_t range_i;
233
234 if (is_signed) {
235 s_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
236 ir_fc, i);
237 mapping = bt_field_class_enumeration_signed_mapping_as_mapping_const(
238 s_mapping);
239 s_ranges = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
240 s_mapping);
241 ranges = bt_integer_range_set_signed_as_range_set_const(
242 s_ranges);
243 } else {
244 u_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
245 ir_fc, i);
246 mapping = bt_field_class_enumeration_unsigned_mapping_as_mapping_const(
247 u_mapping);
248 u_ranges = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
249 u_mapping);
250 ranges = bt_integer_range_set_unsigned_as_range_set_const(
251 u_ranges);
252 }
253
254 label = bt_field_class_enumeration_mapping_get_label(
255 mapping);
256 range_count = bt_integer_range_set_get_range_count(
257 ranges);
258
259 for (range_i = 0; range_i < range_count; range_i++) {
260 append_indent(ctx);
261 g_string_append(ctx->tsdl, "\"");
262 append_quoted_string_content(ctx, label);
263 g_string_append(ctx->tsdl, "\" = ");
264
265 if (is_signed) {
266 const bt_integer_range_signed *range;
267 int64_t lower, upper;
268
269 range = bt_integer_range_set_signed_borrow_range_by_index_const(
270 s_ranges, range_i);
271 lower = bt_integer_range_signed_get_lower(
272 range);
273 upper = bt_integer_range_signed_get_upper(
274 range);
275
276 if (lower == upper) {
277 g_string_append_printf(
278 ctx->tsdl, "%" PRId64,
279 lower);
280 } else {
281 g_string_append_printf(
282 ctx->tsdl, "%" PRId64 " ... %" PRId64,
283 lower, upper);
284 }
285 } else {
286 const bt_integer_range_unsigned *range;
287 uint64_t lower, upper;
288
289 range = bt_integer_range_set_unsigned_borrow_range_by_index_const(
290 u_ranges, range_i);
291 lower = bt_integer_range_unsigned_get_lower(
292 range);
293 upper = bt_integer_range_unsigned_get_upper(
294 range);
295
296 if (lower == upper) {
297 g_string_append_printf(
298 ctx->tsdl, "%" PRIu64,
299 lower);
300 } else {
301 g_string_append_printf(
302 ctx->tsdl, "%" PRIu64 " ... %" PRIu64,
303 lower, upper);
304 }
305 }
306
307 g_string_append(ctx->tsdl, ",\n");
308 }
309 }
310
311 append_end_block(ctx);
312 }
313 }
314
315 static
316 void append_float_field_class(struct ctx *ctx,
317 struct fs_sink_ctf_field_class_float *fc)
318 {
319 unsigned int mant_dig, exp_dig;
320
321 if (bt_field_class_get_type(fc->base.base.ir_fc) ==
322 BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) {
323 mant_dig = 24;
324 exp_dig = 8;
325 } else {
326 mant_dig = 53;
327 exp_dig = 11;
328 }
329
330 g_string_append_printf(ctx->tsdl,
331 "floating_point { mant_dig = %u; exp_dig = %u; align = %u; }",
332 mant_dig, exp_dig, fc->base.base.alignment);
333 }
334
335 static
336 void append_string_field_class(struct ctx *ctx,
337 struct fs_sink_ctf_field_class_string *fc)
338 {
339 g_string_append(ctx->tsdl, "string { encoding = UTF8; }");
340 }
341
342 static
343 void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc);
344
345 static
346 void append_member(struct ctx *ctx, const char *name,
347 struct fs_sink_ctf_field_class *fc)
348 {
349 GString *lengths = NULL;
350 const char *lengths_str = "";
351
352 BT_ASSERT(fc);
353
354 while (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY ||
355 fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
356 if (!lengths) {
357 lengths = g_string_new(NULL);
358 BT_ASSERT(lengths);
359 }
360
361 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY) {
362 struct fs_sink_ctf_field_class_array *array_fc =
363 fs_sink_ctf_field_class_as_array(fc);
364
365 g_string_append_printf(lengths, "[%" PRIu64 "]",
366 array_fc->length);
367 fc = array_fc->base.elem_fc;
368 } else {
369 struct fs_sink_ctf_field_class_sequence *seq_fc =
370 fs_sink_ctf_field_class_as_sequence(fc);
371
372 g_string_append_printf(lengths, "[%s]",
373 seq_fc->length_ref->str);
374 fc = seq_fc->base.elem_fc;
375 }
376 }
377
378 append_field_class(ctx, fc);
379
380 if (lengths) {
381 lengths_str = lengths->str;
382 }
383
384 g_string_append_printf(ctx->tsdl, " %s%s;\n", name, lengths_str);
385
386 if (lengths) {
387 g_string_free(lengths, TRUE);
388 }
389 }
390
391 static
392 void append_struct_field_class_members(struct ctx *ctx,
393 struct fs_sink_ctf_field_class_struct *struct_fc)
394 {
395 uint64_t i;
396
397 for (i = 0; i < struct_fc->members->len; i++) {
398 struct fs_sink_ctf_named_field_class *named_fc =
399 fs_sink_ctf_field_class_struct_borrow_member_by_index(
400 struct_fc, i);
401 struct fs_sink_ctf_field_class *fc = named_fc->fc;
402
403 /*
404 * For sequence, option, and variant field classes, if
405 * the length/tag field class is generated before, write
406 * it now before the dependent field class.
407 */
408 if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
409 struct fs_sink_ctf_field_class_sequence *seq_fc =
410 fs_sink_ctf_field_class_as_sequence(fc);
411
412 if (seq_fc->length_is_before) {
413 append_indent(ctx);
414 append_integer_field_class_from_props(ctx,
415 32, 8, false,
416 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
417 NULL, seq_fc->length_ref->str, true);
418 }
419 } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION) {
420 struct fs_sink_ctf_field_class_option *opt_fc =
421 fs_sink_ctf_field_class_as_option(fc);
422
423 /*
424 * CTF 1.8 does not support the option field
425 * class type. To write something anyway, this
426 * component translates this type to a variant
427 * field class where the options are:
428 *
429 * * An empty structure field class.
430 * * The optional field class itself.
431 *
432 * The "tag" is always generated/before in that
433 * case (an 8-bit unsigned enumeration field
434 * class).
435 */
436 append_indent(ctx);
437 g_string_append(ctx->tsdl,
438 "/* The enumeration and variant field classes "
439 "below were a trace IR option field class. */\n");
440 append_indent(ctx);
441 g_string_append(ctx->tsdl, "enum : ");
442 append_integer_field_class_from_props(ctx,
443 8, 8, false,
444 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
445 NULL, NULL, false);
446 g_string_append(ctx->tsdl, " {\n");
447 ctx->indent_level++;
448 append_indent(ctx);
449 g_string_append(ctx->tsdl, "none = 0,\n");
450 append_indent(ctx);
451 g_string_append(ctx->tsdl, "content = 1,\n");
452 append_end_block(ctx);
453 g_string_append_printf(ctx->tsdl, " %s;\n",
454 opt_fc->tag_ref->str);
455 } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT) {
456 struct fs_sink_ctf_field_class_variant *var_fc =
457 fs_sink_ctf_field_class_as_variant(fc);
458
459 if (var_fc->tag_is_before) {
460 append_indent(ctx);
461 g_string_append(ctx->tsdl, "enum : ");
462 append_integer_field_class_from_props(ctx,
463 16, 8, false,
464 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
465 NULL, NULL, false);
466 g_string_append(ctx->tsdl, " {\n");
467 ctx->indent_level++;
468
469 for (i = 0; i < var_fc->options->len; i++) {
470 struct fs_sink_ctf_named_field_class *option_named_fc =
471 fs_sink_ctf_field_class_variant_borrow_option_by_index(
472 var_fc, i);
473
474 append_indent(ctx);
475 g_string_append_printf(ctx->tsdl,
476 "\"%s\" = %" PRIu64 ",\n",
477 option_named_fc->name->str, i);
478 }
479
480 append_end_block(ctx);
481 g_string_append_printf(ctx->tsdl, " %s;\n",
482 var_fc->tag_ref->str);
483 }
484 } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_BOOL) {
485 append_indent(ctx);
486 g_string_append(ctx->tsdl,
487 "/* The integer field class below was a trace IR boolean field class. */\n");
488 } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_BIT_ARRAY) {
489 append_indent(ctx);
490 g_string_append(ctx->tsdl,
491 "/* The integer field class below was a trace IR bit array field class. */\n");
492 }
493
494 append_indent(ctx);
495 append_member(ctx, named_fc->name->str, fc);
496 }
497 }
498
499 static
500 void append_struct_field_class(struct ctx *ctx,
501 struct fs_sink_ctf_field_class_struct *fc)
502 {
503 g_string_append(ctx->tsdl, "struct {\n");
504 ctx->indent_level++;
505 append_struct_field_class_members(ctx, fc);
506 append_end_block(ctx);
507 g_string_append_printf(ctx->tsdl, " align(%u)",
508 fc->base.alignment);
509 }
510
511 static
512 void append_option_field_class(struct ctx *ctx,
513 struct fs_sink_ctf_field_class_option *opt_fc)
514 {
515 g_string_append_printf(ctx->tsdl, "variant <%s> {\n",
516 opt_fc->tag_ref->str);
517 ctx->indent_level++;
518 append_indent(ctx);
519 g_string_append(ctx->tsdl, "struct { } none;\n");
520 append_indent(ctx);
521 append_member(ctx, "content", opt_fc->content_fc);
522 append_end_block(ctx);
523 }
524
525 static
526 void append_variant_field_class(struct ctx *ctx,
527 struct fs_sink_ctf_field_class_variant *var_fc)
528 {
529 uint64_t i;
530
531 g_string_append_printf(ctx->tsdl, "variant <%s> {\n",
532 var_fc->tag_ref->str);
533 ctx->indent_level++;
534
535 for (i = 0; i < var_fc->options->len; i++) {
536 struct fs_sink_ctf_named_field_class *named_fc =
537 fs_sink_ctf_field_class_variant_borrow_option_by_index(
538 var_fc, i);
539
540 append_indent(ctx);
541 append_member(ctx, named_fc->name->str, named_fc->fc);
542 }
543
544 append_end_block(ctx);
545 }
546
547 static
548 void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc)
549 {
550 switch (fc->type) {
551 case FS_SINK_CTF_FIELD_CLASS_TYPE_BOOL:
552 append_bool_field_class(ctx, fs_sink_ctf_field_class_as_bool(fc));
553 break;
554 case FS_SINK_CTF_FIELD_CLASS_TYPE_BIT_ARRAY:
555 append_bit_array_field_class(ctx, fs_sink_ctf_field_class_as_bit_array(fc));
556 break;
557 case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
558 append_integer_field_class(ctx, fs_sink_ctf_field_class_as_int(fc));
559 break;
560 case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
561 append_float_field_class(ctx, fs_sink_ctf_field_class_as_float(fc));
562 break;
563 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
564 append_string_field_class(ctx, fs_sink_ctf_field_class_as_string(fc));
565 break;
566 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
567 append_struct_field_class(ctx, fs_sink_ctf_field_class_as_struct(fc));
568 break;
569 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
570 append_option_field_class(ctx, fs_sink_ctf_field_class_as_option(fc));
571 break;
572 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
573 append_variant_field_class(ctx, fs_sink_ctf_field_class_as_variant(fc));
574 break;
575 default:
576 bt_common_abort();
577 }
578 }
579
580 static
581 void append_event_class(struct ctx *ctx, struct fs_sink_ctf_event_class *ec)
582 {
583 const char *str;
584 bt_event_class_log_level log_level;
585
586 /* Event class */
587 append_indent(ctx);
588 g_string_append(ctx->tsdl, "event {\n");
589 ctx->indent_level++;
590
591 /* Event class properties */
592 append_indent(ctx);
593 g_string_append(ctx->tsdl, "name = ");
594 str = bt_event_class_get_name(ec->ir_ec);
595 if (!str) {
596 str = "unknown";
597 }
598
599 append_quoted_string(ctx, str);
600 g_string_append(ctx->tsdl, ";\n");
601 append_indent(ctx);
602 g_string_append_printf(ctx->tsdl, "stream_id = %" PRIu64 ";\n",
603 bt_stream_class_get_id(ec->sc->ir_sc));
604 append_indent(ctx);
605 g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
606 bt_event_class_get_id(ec->ir_ec));
607
608 str = bt_event_class_get_emf_uri(ec->ir_ec);
609 if (str) {
610 append_indent(ctx);
611 g_string_append(ctx->tsdl, "model.emf.uri = ");
612 append_quoted_string(ctx, str);
613 g_string_append(ctx->tsdl, ";\n");
614 }
615
616 if (bt_event_class_get_log_level(ec->ir_ec, &log_level) ==
617 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
618 unsigned int level;
619
620 append_indent(ctx);
621 g_string_append(ctx->tsdl, "loglevel = ");
622
623 switch (log_level) {
624 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
625 level = 0;
626 break;
627 case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
628 level = 1;
629 break;
630 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
631 level = 2;
632 break;
633 case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
634 level = 3;
635 break;
636 case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
637 level = 4;
638 break;
639 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
640 level = 5;
641 break;
642 case BT_EVENT_CLASS_LOG_LEVEL_INFO:
643 level = 6;
644 break;
645 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
646 level = 7;
647 break;
648 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
649 level = 8;
650 break;
651 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
652 level = 9;
653 break;
654 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
655 level = 10;
656 break;
657 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
658 level = 11;
659 break;
660 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
661 level = 12;
662 break;
663 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
664 level = 13;
665 break;
666 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
667 level = 14;
668 break;
669 default:
670 bt_common_abort();
671 }
672
673 g_string_append_printf(ctx->tsdl, "%u;\n", level);
674 }
675
676 /* Event specific context field class */
677 if (ec->spec_context_fc) {
678 append_indent(ctx);
679 g_string_append(ctx->tsdl, "context := ");
680 append_field_class(ctx, ec->spec_context_fc);
681 g_string_append(ctx->tsdl, ";\n");
682 }
683
684 /* Event payload field class */
685 if (ec->payload_fc) {
686 append_indent(ctx);
687 g_string_append(ctx->tsdl, "fields := ");
688 append_field_class(ctx, ec->payload_fc);
689 g_string_append(ctx->tsdl, ";\n");
690 }
691
692 append_end_block_semi_nl_nl(ctx);
693 }
694
695 static
696 void append_stream_class(struct ctx *ctx,
697 struct fs_sink_ctf_stream_class *sc)
698 {
699 uint64_t i;
700
701 /* Default clock class */
702 if (sc->default_clock_class) {
703 const char *descr;
704 int64_t offset_seconds;
705 uint64_t offset_cycles;
706 bt_uuid uuid;
707
708 append_indent(ctx);
709 g_string_append(ctx->tsdl, "clock {\n");
710 ctx->indent_level++;
711 BT_ASSERT(sc->default_clock_class_name->len > 0);
712 append_indent(ctx);
713 g_string_append_printf(ctx->tsdl, "name = %s;\n",
714 sc->default_clock_class_name->str);
715 descr = bt_clock_class_get_description(sc->default_clock_class);
716 if (descr) {
717 append_indent(ctx);
718 g_string_append(ctx->tsdl, "description = ");
719 append_quoted_string(ctx, descr);
720 g_string_append(ctx->tsdl, ";\n");
721 }
722
723 append_indent(ctx);
724 g_string_append_printf(ctx->tsdl, "freq = %" PRIu64 ";\n",
725 bt_clock_class_get_frequency(sc->default_clock_class));
726 append_indent(ctx);
727 g_string_append_printf(ctx->tsdl, "precision = %" PRIu64 ";\n",
728 bt_clock_class_get_precision(sc->default_clock_class));
729 bt_clock_class_get_offset(sc->default_clock_class,
730 &offset_seconds, &offset_cycles);
731 append_indent(ctx);
732 g_string_append_printf(ctx->tsdl, "offset_s = %" PRId64 ";\n",
733 offset_seconds);
734 append_indent(ctx);
735 g_string_append_printf(ctx->tsdl, "offset = %" PRIu64 ";\n",
736 offset_cycles);
737 append_indent(ctx);
738 g_string_append(ctx->tsdl, "absolute = ");
739
740 if (bt_clock_class_origin_is_unix_epoch(
741 sc->default_clock_class)) {
742 g_string_append(ctx->tsdl, "true");
743 } else {
744 g_string_append(ctx->tsdl, "false");
745 }
746
747 g_string_append(ctx->tsdl, ";\n");
748 uuid = bt_clock_class_get_uuid(sc->default_clock_class);
749 if (uuid) {
750 append_indent(ctx);
751 g_string_append(ctx->tsdl, "uuid = ");
752 append_uuid(ctx, uuid);
753 g_string_append(ctx->tsdl, ";\n");
754 }
755
756 /* End clock class */
757 append_end_block_semi_nl_nl(ctx);
758 }
759
760 /* Stream class */
761 append_indent(ctx);
762 g_string_append(ctx->tsdl, "stream {\n");
763 ctx->indent_level++;
764
765 /* Stream class properties */
766 append_indent(ctx);
767 g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
768 bt_stream_class_get_id(sc->ir_sc));
769
770 /* Packet context field class */
771 append_indent(ctx);
772 g_string_append(ctx->tsdl, "packet.context := struct {\n");
773 ctx->indent_level++;
774 append_indent(ctx);
775 append_integer_field_class_from_props(ctx, 64, 8, false,
776 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
777 NULL, "packet_size", true);
778 append_indent(ctx);
779 append_integer_field_class_from_props(ctx, 64, 8, false,
780 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
781 NULL, "content_size", true);
782
783 if (sc->packets_have_ts_begin) {
784 append_indent(ctx);
785 append_integer_field_class_from_props(ctx, 64, 8, false,
786 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
787 sc->default_clock_class_name->str,
788 "timestamp_begin", true);
789 }
790
791 if (sc->packets_have_ts_end) {
792 append_indent(ctx);
793 append_integer_field_class_from_props(ctx, 64, 8, false,
794 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
795 sc->default_clock_class_name->str,
796 "timestamp_end", true);
797 }
798
799 if (sc->has_discarded_events) {
800 append_indent(ctx);
801 append_integer_field_class_from_props(ctx, 64, 8, false,
802 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
803 NULL, "events_discarded", true);
804 }
805
806 /*
807 * Unconditionnally write the packet sequence number as, even if
808 * there's no possible discarded packets message, it's still
809 * useful information to have.
810 */
811 append_indent(ctx);
812 append_integer_field_class_from_props(ctx, 64, 8, false,
813 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
814 NULL, "packet_seq_num", true);
815
816 if (sc->packet_context_fc) {
817 append_struct_field_class_members(ctx,
818 fs_sink_ctf_field_class_as_struct(sc->packet_context_fc));
819 fs_sink_ctf_field_class_struct_align_at_least(
820 fs_sink_ctf_field_class_as_struct(sc->packet_context_fc), 8);
821 }
822
823 /* End packet context field class */
824 append_end_block(ctx);
825 g_string_append_printf(ctx->tsdl, " align(%u);\n\n",
826 sc->packet_context_fc ? sc->packet_context_fc->alignment : 8);
827
828 /* Event header field class */
829 append_indent(ctx);
830 g_string_append(ctx->tsdl, "event.header := struct {\n");
831 ctx->indent_level++;
832 append_indent(ctx);
833 append_integer_field_class_from_props(ctx, 64, 8, false,
834 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
835 NULL, "id", true);
836
837 if (sc->default_clock_class) {
838 append_indent(ctx);
839 append_integer_field_class_from_props(ctx, 64, 8, false,
840 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
841 sc->default_clock_class_name->str,
842 "timestamp", true);
843 }
844
845 /* End event header field class */
846 append_end_block(ctx);
847 g_string_append(ctx->tsdl, " align(8);\n");
848
849 /* Event common context field class */
850 if (sc->event_common_context_fc) {
851 append_indent(ctx);
852 g_string_append(ctx->tsdl, "event.context := ");
853 append_field_class(ctx, sc->event_common_context_fc);
854 g_string_append(ctx->tsdl, ";\n");
855 }
856
857 /* End stream class */
858 append_end_block_semi_nl_nl(ctx);
859
860 /* Event classes */
861 for (i = 0; i < sc->event_classes->len; i++) {
862 append_event_class(ctx,
863 (fs_sink_ctf_event_class *) sc->event_classes->pdata[i]);
864 }
865 }
866
867 BT_HIDDEN
868 void translate_trace_ctf_ir_to_tsdl(struct fs_sink_ctf_trace *trace,
869 GString *tsdl)
870 {
871 struct ctx ctx = {
872 .indent_level = 0,
873 .tsdl = tsdl,
874 };
875 uint64_t i;
876 uint64_t count;
877
878 g_string_assign(tsdl, "/* CTF 1.8 */\n\n");
879 g_string_append(tsdl, "/* This was generated by a Babeltrace `sink.ctf.fs` component. */\n\n");
880
881 /* Trace class */
882 append_indent(&ctx);
883 g_string_append(tsdl, "trace {\n");
884 ctx.indent_level++;
885
886 /* Trace class properties */
887 append_indent(&ctx);
888 g_string_append(tsdl, "major = 1;\n");
889 append_indent(&ctx);
890 g_string_append(tsdl, "minor = 8;\n");
891 append_indent(&ctx);
892 g_string_append(tsdl, "uuid = ");
893 append_uuid(&ctx, trace->uuid);
894 g_string_append(tsdl, ";\n");
895 append_indent(&ctx);
896 g_string_append(tsdl, "byte_order = ");
897
898 if (BYTE_ORDER == LITTLE_ENDIAN) {
899 g_string_append(tsdl, "le");
900 } else {
901 g_string_append(tsdl, "be");
902 }
903
904 g_string_append(tsdl, ";\n");
905
906 /* Packet header field class */
907 append_indent(&ctx);
908 g_string_append(tsdl, "packet.header := struct {\n");
909 ctx.indent_level++;
910 append_indent(&ctx);
911 append_integer_field_class_from_props(&ctx, 32, 8, false,
912 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
913 NULL, "magic", true);
914 append_indent(&ctx);
915 append_integer_field_class_from_props(&ctx, 8, 8, false,
916 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
917 NULL, "uuid[16]", true);
918 append_indent(&ctx);
919 append_integer_field_class_from_props(&ctx, 64, 8, false,
920 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
921 NULL, "stream_id", true);
922 append_indent(&ctx);
923 append_integer_field_class_from_props(&ctx, 64, 8, false,
924 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
925 NULL, "stream_instance_id", true);
926
927 /* End packet header field class */
928 append_end_block(&ctx);
929 g_string_append(ctx.tsdl, " align(8);\n");
930
931 /* End trace class */
932 append_end_block_semi_nl_nl(&ctx);
933
934 /* Trace environment */
935 count = bt_trace_get_environment_entry_count(trace->ir_trace);
936 if (count > 0) {
937 append_indent(&ctx);
938 g_string_append(tsdl, "env {\n");
939 ctx.indent_level++;
940
941 for (i = 0; i < count; i++) {
942 const char *name;
943 const bt_value *val;
944
945 bt_trace_borrow_environment_entry_by_index_const(
946 trace->ir_trace, i, &name, &val);
947 append_indent(&ctx);
948 g_string_append_printf(tsdl, "%s = ", name);
949
950 switch (bt_value_get_type(val)) {
951 case BT_VALUE_TYPE_SIGNED_INTEGER:
952 g_string_append_printf(tsdl, "%" PRId64,
953 bt_value_integer_signed_get(val));
954 break;
955 case BT_VALUE_TYPE_STRING:
956 append_quoted_string(&ctx, bt_value_string_get(val));
957 break;
958 default:
959 /*
960 * This is checked in
961 * translate_trace_trace_ir_to_ctf_ir().
962 */
963 bt_common_abort();
964 }
965
966 g_string_append(tsdl, ";\n");
967 }
968
969 /* End trace class environment */
970 append_end_block_semi_nl_nl(&ctx);
971 }
972
973 /* Stream classes and their event classes */
974 for (i = 0; i < trace->stream_classes->len; i++) {
975 append_stream_class(&ctx,
976 (fs_sink_ctf_stream_class *) trace->stream_classes->pdata[i]);
977 }
978 }
This page took 0.054153 seconds and 3 git commands to generate.