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