sink.ctf.fs: write option field classes and fields
[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 "\"" BT_UUID_FMT "\"",
54 BT_UUID_FMT_VALUES(uuid));
55 }
56
57 static
58 void append_quoted_string_content(struct ctx *ctx, const char *str)
59 {
60 const char *ch;
61
62 for (ch = str; *ch != '\0'; ch++) {
63 unsigned char uch = (unsigned char) *ch;
64
65 if (uch < 32 || uch >= 127) {
66 switch (*ch) {
67 case '\a':
68 g_string_append(ctx->tsdl, "\\a");
69 break;
70 case '\b':
71 g_string_append(ctx->tsdl, "\\b");
72 break;
73 case '\f':
74 g_string_append(ctx->tsdl, "\\f");
75 break;
76 case '\n':
77 g_string_append(ctx->tsdl, "\\n");
78 break;
79 case '\r':
80 g_string_append(ctx->tsdl, "\\r");
81 break;
82 case '\t':
83 g_string_append(ctx->tsdl, "\\t");
84 break;
85 case '\v':
86 g_string_append(ctx->tsdl, "\\v");
87 break;
88 default:
89 g_string_append_printf(ctx->tsdl, "\\x%02x",
90 (unsigned int) uch);
91 break;
92 }
93 } else if (*ch == '"' || *ch == '\\') {
94 g_string_append_c(ctx->tsdl, '\\');
95 g_string_append_c(ctx->tsdl, *ch);
96 } else {
97 g_string_append_c(ctx->tsdl, *ch);
98 }
99 }
100 }
101
102 static
103 void append_quoted_string(struct ctx *ctx, const char *str)
104 {
105 g_string_append_c(ctx->tsdl, '"');
106 append_quoted_string_content(ctx, str);
107 g_string_append_c(ctx->tsdl, '"');
108 }
109
110 static
111 void append_integer_field_class_from_props(struct ctx *ctx, unsigned int size,
112 unsigned int alignment, bool is_signed,
113 bt_field_class_integer_preferred_display_base disp_base,
114 const char *mapped_clock_class_name, const char *field_name,
115 bool end)
116 {
117 g_string_append_printf(ctx->tsdl,
118 "integer { size = %u; align = %u;",
119 size, alignment);
120
121 if (is_signed) {
122 g_string_append(ctx->tsdl, " signed = true;");
123 }
124
125 if (disp_base != BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL) {
126 g_string_append(ctx->tsdl, " base = ");
127
128 switch (disp_base) {
129 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
130 g_string_append(ctx->tsdl, "b");
131 break;
132 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
133 g_string_append(ctx->tsdl, "o");
134 break;
135 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
136 g_string_append(ctx->tsdl, "x");
137 break;
138 default:
139 abort();
140 }
141
142 g_string_append_c(ctx->tsdl, ';');
143 }
144
145 if (mapped_clock_class_name) {
146 g_string_append_printf(ctx->tsdl, " map = clock.%s.value;",
147 mapped_clock_class_name);
148 }
149
150 g_string_append(ctx->tsdl, " }");
151
152 if (field_name) {
153 g_string_append_printf(ctx->tsdl, " %s", field_name);
154 }
155
156 if (end) {
157 g_string_append(ctx->tsdl, ";\n");
158 }
159 }
160
161 static
162 void append_end_block(struct ctx *ctx)
163 {
164 ctx->indent_level--;
165 append_indent(ctx);
166 g_string_append(ctx->tsdl, "}");
167 }
168
169 static
170 void append_end_block_semi_nl(struct ctx *ctx)
171 {
172 ctx->indent_level--;
173 append_indent(ctx);
174 g_string_append(ctx->tsdl, "};\n");
175 }
176
177 static
178 void append_end_block_semi_nl_nl(struct ctx *ctx)
179 {
180 append_end_block_semi_nl(ctx);
181 g_string_append_c(ctx->tsdl, '\n');
182 }
183
184 static
185 void append_bool_field_class(struct ctx *ctx,
186 __attribute__((unused)) struct fs_sink_ctf_field_class_bool *fc)
187 {
188 /*
189 * CTF 1.8 has no boolean field class type, so this component
190 * translates it to an 8-bit unsigned integer field class.
191 */
192 append_integer_field_class_from_props(ctx, fc->base.size,
193 fc->base.base.alignment, false,
194 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
195 NULL, NULL, false);
196 }
197
198 static
199 void append_integer_field_class(struct ctx *ctx,
200 struct fs_sink_ctf_field_class_int *fc)
201 {
202 const bt_field_class *ir_fc = fc->base.base.ir_fc;
203 bt_field_class_type type = bt_field_class_get_type(ir_fc);
204 bool is_signed = type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION ||
205 type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER;
206
207 if (type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION ||
208 type == BT_FIELD_CLASS_TYPE_SIGNED_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 (type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION ||
218 type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
219 uint64_t i;
220
221 g_string_append(ctx->tsdl, " {\n");
222 ctx->indent_level++;
223
224 for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_fc); i++) {
225 const char *label;
226 const bt_field_class_enumeration_mapping *mapping;
227 const bt_field_class_enumeration_unsigned_mapping *u_mapping;
228 const bt_field_class_enumeration_signed_mapping *s_mapping;
229 const bt_integer_range_set *ranges;
230 const bt_integer_range_set_unsigned *u_ranges;
231 const bt_integer_range_set_signed *s_ranges;
232 uint64_t range_count;
233 uint64_t range_i;
234
235 if (is_signed) {
236 s_mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
237 ir_fc, i);
238 mapping = bt_field_class_enumeration_signed_mapping_as_mapping_const(
239 s_mapping);
240 s_ranges = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
241 s_mapping);
242 ranges = bt_integer_range_set_signed_as_range_set_const(
243 s_ranges);
244 } else {
245 u_mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
246 ir_fc, i);
247 mapping = bt_field_class_enumeration_unsigned_mapping_as_mapping_const(
248 u_mapping);
249 u_ranges = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
250 u_mapping);
251 ranges = bt_integer_range_set_unsigned_as_range_set_const(
252 u_ranges);
253 }
254
255 label = bt_field_class_enumeration_mapping_get_label(
256 mapping);
257 range_count = bt_integer_range_set_get_range_count(
258 ranges);
259
260 for (range_i = 0; range_i < range_count; range_i++) {
261 append_indent(ctx);
262 g_string_append(ctx->tsdl, "\"");
263 append_quoted_string_content(ctx, label);
264 g_string_append(ctx->tsdl, "\" = ");
265
266 if (is_signed) {
267 const bt_integer_range_signed *range;
268 int64_t lower, upper;
269
270 range = bt_integer_range_set_signed_borrow_range_by_index_const(
271 s_ranges, range_i);
272 lower = bt_integer_range_signed_get_lower(
273 range);
274 upper = bt_integer_range_signed_get_upper(
275 range);
276
277 if (lower == upper) {
278 g_string_append_printf(
279 ctx->tsdl, "%" PRId64,
280 lower);
281 } else {
282 g_string_append_printf(
283 ctx->tsdl, "%" PRId64 " ... %" PRId64,
284 lower, upper);
285 }
286 } else {
287 const bt_integer_range_unsigned *range;
288 uint64_t lower, upper;
289
290 range = bt_integer_range_set_unsigned_borrow_range_by_index_const(
291 u_ranges, range_i);
292 lower = bt_integer_range_unsigned_get_lower(
293 range);
294 upper = bt_integer_range_unsigned_get_upper(
295 range);
296
297 if (lower == upper) {
298 g_string_append_printf(
299 ctx->tsdl, "%" PRIu64,
300 lower);
301 } else {
302 g_string_append_printf(
303 ctx->tsdl, "%" PRIu64 " ... %" PRIu64,
304 lower, upper);
305 }
306 }
307
308 g_string_append(ctx->tsdl, ",\n");
309 }
310 }
311
312 append_end_block(ctx);
313 }
314 }
315
316 static
317 void append_float_field_class(struct ctx *ctx,
318 struct fs_sink_ctf_field_class_float *fc)
319 {
320 unsigned int mant_dig, exp_dig;
321
322 if (bt_field_class_real_is_single_precision(fc->base.base.ir_fc)) {
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_float *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 (void *) 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 (void *) 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 (void *) 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 (void *) 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 (void *) 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 *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 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 }
489
490 append_indent(ctx);
491 append_member(ctx, named_fc->name->str, fc);
492 }
493 }
494
495 static
496 void append_struct_field_class(struct ctx *ctx,
497 struct fs_sink_ctf_field_class_struct *fc)
498 {
499 g_string_append(ctx->tsdl, "struct {\n");
500 ctx->indent_level++;
501 append_struct_field_class_members(ctx, fc);
502 append_end_block(ctx);
503 g_string_append_printf(ctx->tsdl, " align(%u)",
504 fc->base.alignment);
505 }
506
507 static
508 void append_option_field_class(struct ctx *ctx,
509 struct fs_sink_ctf_field_class_option *opt_fc)
510 {
511 g_string_append_printf(ctx->tsdl, "variant <%s> {\n",
512 opt_fc->tag_ref->str);
513 ctx->indent_level++;
514 append_indent(ctx);
515 g_string_append(ctx->tsdl, "struct { } none;\n");
516 append_indent(ctx);
517 append_member(ctx, "content", opt_fc->content_fc);
518 append_end_block(ctx);
519 }
520
521 static
522 void append_variant_field_class(struct ctx *ctx,
523 struct fs_sink_ctf_field_class_variant *var_fc)
524 {
525 uint64_t i;
526
527 g_string_append_printf(ctx->tsdl, "variant <%s> {\n",
528 var_fc->tag_ref->str);
529 ctx->indent_level++;
530
531 for (i = 0; i < var_fc->options->len; i++) {
532 struct fs_sink_ctf_named_field_class *named_fc =
533 fs_sink_ctf_field_class_variant_borrow_option_by_index(
534 var_fc, i);
535
536 append_indent(ctx);
537 append_member(ctx, named_fc->name->str, named_fc->fc);
538 }
539
540 append_end_block(ctx);
541 }
542
543 static
544 void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc)
545 {
546 switch (fc->type) {
547 case FS_SINK_CTF_FIELD_CLASS_TYPE_BOOL:
548 append_bool_field_class(ctx, (void *) fc);
549 break;
550 case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
551 append_integer_field_class(ctx, (void *) fc);
552 break;
553 case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
554 append_float_field_class(ctx, (void *) fc);
555 break;
556 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
557 append_string_field_class(ctx, (void *) fc);
558 break;
559 case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
560 append_struct_field_class(ctx, (void *) fc);
561 break;
562 case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
563 append_option_field_class(ctx, (void *) fc);
564 break;
565 case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
566 append_variant_field_class(ctx, (void *) fc);
567 break;
568 default:
569 abort();
570 }
571 }
572
573 static
574 void append_event_class(struct ctx *ctx, struct fs_sink_ctf_event_class *ec)
575 {
576 const char *str;
577 bt_event_class_log_level log_level;
578
579 /* Event class */
580 append_indent(ctx);
581 g_string_append(ctx->tsdl, "event {\n");
582 ctx->indent_level++;
583
584 /* Event class properties */
585 append_indent(ctx);
586 g_string_append(ctx->tsdl, "name = ");
587 str = bt_event_class_get_name(ec->ir_ec);
588 if (!str) {
589 str = "unknown";
590 }
591
592 append_quoted_string(ctx, str);
593 g_string_append(ctx->tsdl, ";\n");
594 append_indent(ctx);
595 g_string_append_printf(ctx->tsdl, "stream_id = %" PRIu64 ";\n",
596 bt_stream_class_get_id(ec->sc->ir_sc));
597 append_indent(ctx);
598 g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
599 bt_event_class_get_id(ec->ir_ec));
600
601 str = bt_event_class_get_emf_uri(ec->ir_ec);
602 if (str) {
603 append_indent(ctx);
604 g_string_append(ctx->tsdl, "model.emf.uri = ");
605 append_quoted_string(ctx, str);
606 g_string_append(ctx->tsdl, ";\n");
607 }
608
609 if (bt_event_class_get_log_level(ec->ir_ec, &log_level) ==
610 BT_PROPERTY_AVAILABILITY_AVAILABLE) {
611 unsigned int level;
612
613 append_indent(ctx);
614 g_string_append(ctx->tsdl, "loglevel = ");
615
616 switch (log_level) {
617 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
618 level = 0;
619 break;
620 case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
621 level = 1;
622 break;
623 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
624 level = 2;
625 break;
626 case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
627 level = 3;
628 break;
629 case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
630 level = 4;
631 break;
632 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
633 level = 5;
634 break;
635 case BT_EVENT_CLASS_LOG_LEVEL_INFO:
636 level = 6;
637 break;
638 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
639 level = 7;
640 break;
641 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
642 level = 8;
643 break;
644 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
645 level = 9;
646 break;
647 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
648 level = 10;
649 break;
650 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
651 level = 11;
652 break;
653 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
654 level = 12;
655 break;
656 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
657 level = 13;
658 break;
659 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
660 level = 14;
661 break;
662 default:
663 abort();
664 }
665
666 g_string_append_printf(ctx->tsdl, "%u;\n", level);
667 }
668
669 /* Event specific context field class */
670 if (ec->spec_context_fc) {
671 append_indent(ctx);
672 g_string_append(ctx->tsdl, "context := ");
673 append_field_class(ctx, ec->spec_context_fc);
674 g_string_append(ctx->tsdl, ";\n");
675 }
676
677 /* Event payload field class */
678 if (ec->payload_fc) {
679 append_indent(ctx);
680 g_string_append(ctx->tsdl, "fields := ");
681 append_field_class(ctx, ec->payload_fc);
682 g_string_append(ctx->tsdl, ";\n");
683 }
684
685 append_end_block_semi_nl_nl(ctx);
686 }
687
688 static
689 void append_stream_class(struct ctx *ctx,
690 struct fs_sink_ctf_stream_class *sc)
691 {
692 uint64_t i;
693
694 /* Default clock class */
695 if (sc->default_clock_class) {
696 const char *descr;
697 int64_t offset_seconds;
698 uint64_t offset_cycles;
699 bt_uuid uuid;
700
701 append_indent(ctx);
702 g_string_append(ctx->tsdl, "clock {\n");
703 ctx->indent_level++;
704 BT_ASSERT(sc->default_clock_class_name->len > 0);
705 append_indent(ctx);
706 g_string_append_printf(ctx->tsdl, "name = %s;\n",
707 sc->default_clock_class_name->str);
708 descr = bt_clock_class_get_description(sc->default_clock_class);
709 if (descr) {
710 append_indent(ctx);
711 g_string_append(ctx->tsdl, "description = ");
712 append_quoted_string(ctx, descr);
713 g_string_append(ctx->tsdl, ";\n");
714 }
715
716 append_indent(ctx);
717 g_string_append_printf(ctx->tsdl, "freq = %" PRIu64 ";\n",
718 bt_clock_class_get_frequency(sc->default_clock_class));
719 append_indent(ctx);
720 g_string_append_printf(ctx->tsdl, "precision = %" PRIu64 ";\n",
721 bt_clock_class_get_precision(sc->default_clock_class));
722 bt_clock_class_get_offset(sc->default_clock_class,
723 &offset_seconds, &offset_cycles);
724 append_indent(ctx);
725 g_string_append_printf(ctx->tsdl, "offset_s = %" PRId64 ";\n",
726 offset_seconds);
727 append_indent(ctx);
728 g_string_append_printf(ctx->tsdl, "offset = %" PRIu64 ";\n",
729 offset_cycles);
730 append_indent(ctx);
731 g_string_append(ctx->tsdl, "absolute = ");
732
733 if (bt_clock_class_origin_is_unix_epoch(
734 sc->default_clock_class)) {
735 g_string_append(ctx->tsdl, "true");
736 } else {
737 g_string_append(ctx->tsdl, "false");
738 }
739
740 g_string_append(ctx->tsdl, ";\n");
741 uuid = bt_clock_class_get_uuid(sc->default_clock_class);
742 if (uuid) {
743 append_indent(ctx);
744 g_string_append(ctx->tsdl, "uuid = ");
745 append_uuid(ctx, uuid);
746 g_string_append(ctx->tsdl, ";\n");
747 }
748
749 /* End clock class */
750 append_end_block_semi_nl_nl(ctx);
751 }
752
753 /* Stream class */
754 append_indent(ctx);
755 g_string_append(ctx->tsdl, "stream {\n");
756 ctx->indent_level++;
757
758 /* Stream class properties */
759 append_indent(ctx);
760 g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
761 bt_stream_class_get_id(sc->ir_sc));
762
763 /* Packet context field class */
764 append_indent(ctx);
765 g_string_append(ctx->tsdl, "packet.context := struct {\n");
766 ctx->indent_level++;
767 append_indent(ctx);
768 append_integer_field_class_from_props(ctx, 64, 8, false,
769 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
770 NULL, "packet_size", true);
771 append_indent(ctx);
772 append_integer_field_class_from_props(ctx, 64, 8, false,
773 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
774 NULL, "content_size", true);
775
776 if (sc->packets_have_ts_begin) {
777 append_indent(ctx);
778 append_integer_field_class_from_props(ctx, 64, 8, false,
779 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
780 sc->default_clock_class_name->str,
781 "timestamp_begin", true);
782 }
783
784 if (sc->packets_have_ts_end) {
785 append_indent(ctx);
786 append_integer_field_class_from_props(ctx, 64, 8, false,
787 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
788 sc->default_clock_class_name->str,
789 "timestamp_end", true);
790 }
791
792 if (sc->has_discarded_events) {
793 append_indent(ctx);
794 append_integer_field_class_from_props(ctx, 64, 8, false,
795 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
796 NULL, "events_discarded", true);
797 }
798
799 /*
800 * Unconditionnally write the packet sequence number as, even if
801 * there's no possible discarded packets message, it's still
802 * useful information to have.
803 */
804 append_indent(ctx);
805 append_integer_field_class_from_props(ctx, 64, 8, false,
806 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
807 NULL, "packet_seq_num", true);
808
809 if (sc->packet_context_fc) {
810 append_struct_field_class_members(ctx,
811 (void *) sc->packet_context_fc);
812 fs_sink_ctf_field_class_struct_align_at_least(
813 (void *) sc->packet_context_fc, 8);
814 }
815
816 /* End packet context field class */
817 append_end_block(ctx);
818 g_string_append_printf(ctx->tsdl, " align(%u);\n\n",
819 sc->packet_context_fc ? sc->packet_context_fc->alignment : 8);
820
821 /* Event header field class */
822 append_indent(ctx);
823 g_string_append(ctx->tsdl, "event.header := struct {\n");
824 ctx->indent_level++;
825 append_indent(ctx);
826 append_integer_field_class_from_props(ctx, 64, 8, false,
827 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
828 NULL, "id", true);
829
830 if (sc->default_clock_class) {
831 append_indent(ctx);
832 append_integer_field_class_from_props(ctx, 64, 8, false,
833 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
834 sc->default_clock_class_name->str,
835 "timestamp", true);
836 }
837
838 /* End event header field class */
839 append_end_block(ctx);
840 g_string_append(ctx->tsdl, " align(8);\n");
841
842 /* Event common context field class */
843 if (sc->event_common_context_fc) {
844 append_indent(ctx);
845 g_string_append(ctx->tsdl, "event.context := ");
846 append_field_class(ctx,
847 (void *) sc->event_common_context_fc);
848 g_string_append(ctx->tsdl, ";\n");
849 }
850
851 /* End stream class */
852 append_end_block_semi_nl_nl(ctx);
853
854 /* Event classes */
855 for (i = 0; i < sc->event_classes->len; i++) {
856 append_event_class(ctx, sc->event_classes->pdata[i]);
857 }
858 }
859
860 BT_HIDDEN
861 void translate_trace_ctf_ir_to_tsdl(struct fs_sink_ctf_trace *trace,
862 GString *tsdl)
863 {
864 struct ctx ctx = {
865 .indent_level = 0,
866 .tsdl = tsdl,
867 };
868 uint64_t i;
869 uint64_t count;
870
871 g_string_assign(tsdl, "/* CTF 1.8 */\n\n");
872 g_string_append(tsdl, "/* This was generated by a Babeltrace `sink.ctf.fs` component. */\n\n");
873
874 /* Trace class */
875 append_indent(&ctx);
876 g_string_append(tsdl, "trace {\n");
877 ctx.indent_level++;
878
879 /* Trace class properties */
880 append_indent(&ctx);
881 g_string_append(tsdl, "major = 1;\n");
882 append_indent(&ctx);
883 g_string_append(tsdl, "minor = 8;\n");
884 append_indent(&ctx);
885 g_string_append(tsdl, "uuid = ");
886 append_uuid(&ctx, trace->uuid);
887 g_string_append(tsdl, ";\n");
888 append_indent(&ctx);
889 g_string_append(tsdl, "byte_order = ");
890
891 if (BYTE_ORDER == LITTLE_ENDIAN) {
892 g_string_append(tsdl, "le");
893 } else {
894 g_string_append(tsdl, "be");
895 }
896
897 g_string_append(tsdl, ";\n");
898
899 /* Packet header field class */
900 append_indent(&ctx);
901 g_string_append(tsdl, "packet.header := struct {\n");
902 ctx.indent_level++;
903 append_indent(&ctx);
904 append_integer_field_class_from_props(&ctx, 32, 8, false,
905 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
906 NULL, "magic", true);
907 append_indent(&ctx);
908 append_integer_field_class_from_props(&ctx, 8, 8, false,
909 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
910 NULL, "uuid[16]", true);
911 append_indent(&ctx);
912 append_integer_field_class_from_props(&ctx, 64, 8, false,
913 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
914 NULL, "stream_id", true);
915 append_indent(&ctx);
916 append_integer_field_class_from_props(&ctx, 64, 8, false,
917 BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
918 NULL, "stream_instance_id", true);
919
920 /* End packet header field class */
921 append_end_block(&ctx);
922 g_string_append(ctx.tsdl, " align(8);\n");
923
924 /* End trace class */
925 append_end_block_semi_nl_nl(&ctx);
926
927 /* Trace environment */
928 count = bt_trace_get_environment_entry_count(trace->ir_trace);
929 if (count > 0) {
930 append_indent(&ctx);
931 g_string_append(tsdl, "env {\n");
932 ctx.indent_level++;
933
934 for (i = 0; i < count; i++) {
935 const char *name;
936 const bt_value *val;
937
938 bt_trace_borrow_environment_entry_by_index_const(
939 trace->ir_trace, i, &name, &val);
940 append_indent(&ctx);
941 g_string_append_printf(tsdl, "%s = ", name);
942
943 switch (bt_value_get_type(val)) {
944 case BT_VALUE_TYPE_SIGNED_INTEGER:
945 g_string_append_printf(tsdl, "%" PRId64,
946 bt_value_integer_signed_get(val));
947 break;
948 case BT_VALUE_TYPE_STRING:
949 append_quoted_string(&ctx, bt_value_string_get(val));
950 break;
951 default:
952 /*
953 * This is checked in
954 * translate_trace_trace_ir_to_ctf_ir().
955 */
956 abort();
957 }
958
959 g_string_append(tsdl, ";\n");
960 }
961
962 /* End trace class environment */
963 append_end_block_semi_nl_nl(&ctx);
964 }
965
966 /* Stream classes and their event classes */
967 for (i = 0; i < trace->stream_classes->len; i++) {
968 append_stream_class(&ctx, trace->stream_classes->pdata[i]);
969 }
970 }
This page took 0.100737 seconds and 5 git commands to generate.