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