958b94d8dd580cb26d5f159364a003d61ee7946f
[babeltrace.git] / plugins / text / print.c
1 /*
2 * print.c
3 *
4 * Babeltrace CTF Text Output Plugin Event Printing
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 *
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30 #include <babeltrace/ctf-ir/event.h>
31 #include <babeltrace/ctf-ir/event-class.h>
32 #include <babeltrace/ctf-ir/packet.h>
33 #include <babeltrace/ctf-ir/stream.h>
34 #include <babeltrace/ctf-ir/stream-class.h>
35 #include <babeltrace/ctf-ir/clock-class.h>
36 #include <babeltrace/ctf-ir/field-types.h>
37 #include <babeltrace/ctf-ir/fields.h>
38 #include <babeltrace/ctf-ir/trace.h>
39 #include <babeltrace/bitfield.h>
40 #include <babeltrace/common-internal.h>
41 #include <inttypes.h>
42 #include "text.h"
43
44 #define NSEC_PER_SEC 1000000000LL
45
46 #define COLOR_NAME BT_COMMON_COLOR_BOLD
47 #define COLOR_FIELD_NAME BT_COMMON_COLOR_FG_CYAN
48 #define COLOR_RST BT_COMMON_COLOR_RESET
49 #define COLOR_STRING_VALUE BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_GREEN
50 #define COLOR_NUMBER_VALUE BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_RED
51 #define COLOR_ENUM_MAPPING_NAME BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_CYAN
52 #define COLOR_UNKNOWN BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_RED
53 #define COLOR_EVENT_NAME BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_MAGENTA
54 #define COLOR_TIMESTAMP BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_YELLOW
55
56 static inline
57 const char *rem_(const char *str)
58 {
59 if (str[0] == '_')
60 return &str[1];
61 else
62 return str;
63 }
64
65 struct timestamp {
66 int64_t real_timestamp; /* Relative to UNIX epoch. */
67 uint64_t clock_value; /* In cycles. */
68 };
69
70 static
71 enum bt_component_status print_field(struct text_component *text,
72 struct bt_ctf_field *field, bool print_names);
73
74 static
75 void print_name_equal(struct text_component *text, const char *name)
76 {
77 if (text->use_colors) {
78 fprintf(text->out, "%s%s%s = ", COLOR_NAME, name, COLOR_RST);
79 } else {
80 fputs(name, text->out);
81 }
82 }
83
84 static
85 void print_field_name_equal(struct text_component *text, const char *name)
86 {
87 if (text->use_colors) {
88 fprintf(text->out, "%s%s%s = ", COLOR_FIELD_NAME, name,
89 COLOR_RST);
90 } else {
91 fputs(name, text->out);
92 }
93 }
94
95 static
96 void print_timestamp_cycles(struct text_component *text,
97 struct bt_ctf_clock_class *clock_class,
98 struct bt_ctf_event *event)
99 {
100 int ret;
101 struct bt_ctf_clock_value *clock_value;
102 uint64_t cycles;
103
104 clock_value = bt_ctf_event_get_clock_value(event, clock_class);
105 if (!clock_value) {
106 fputs("????????????????????", text->out);
107 return;
108 }
109
110 ret = bt_ctf_clock_value_get_value(clock_value, &cycles);
111 bt_put(clock_value);
112 if (ret) {
113 fprintf(text->out, "Error");
114 return;
115 }
116 fprintf(text->out, "%020" PRIu64, cycles);
117
118 if (text->last_cycles_timestamp != -1ULL) {
119 text->delta_cycles = cycles - text->last_cycles_timestamp;
120 }
121 text->last_cycles_timestamp = cycles;
122 }
123
124 static
125 void print_timestamp_wall(struct text_component *text,
126 struct bt_ctf_clock_class *clock_class,
127 struct bt_ctf_event *event)
128 {
129 int ret;
130 struct bt_ctf_clock_value *clock_value;
131 int64_t ts_nsec = 0; /* add configurable offset */
132 int64_t ts_sec = 0; /* add configurable offset */
133 uint64_t ts_sec_abs, ts_nsec_abs;
134 bool is_negative;
135
136 clock_value = bt_ctf_event_get_clock_value(event, clock_class);
137 if (!clock_value) {
138 fputs("??:??:??.?????????", text->out);
139 return;
140 }
141
142 ret = bt_ctf_clock_value_get_value_ns_from_epoch(clock_value, &ts_nsec);
143 bt_put(clock_value);
144 if (ret) {
145 fprintf(text->out, "Error");
146 return;
147 }
148
149 if (text->last_real_timestamp != -1ULL) {
150 text->delta_real_timestamp = ts_nsec - text->last_real_timestamp;
151 }
152 text->last_real_timestamp = ts_nsec;
153
154 ts_sec += ts_nsec / NSEC_PER_SEC;
155 ts_nsec = ts_nsec % NSEC_PER_SEC;
156 if (ts_sec >= 0 && ts_nsec >= 0) {
157 is_negative = false;
158 ts_sec_abs = ts_sec;
159 ts_nsec_abs = ts_nsec;
160 } else if (ts_sec > 0 && ts_nsec < 0) {
161 is_negative = false;
162 ts_sec_abs = ts_sec - 1;
163 ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
164 } else if (ts_sec == 0 && ts_nsec < 0) {
165 is_negative = true;
166 ts_sec_abs = ts_sec;
167 ts_nsec_abs = -ts_nsec;
168 } else if (ts_sec < 0 && ts_nsec > 0) {
169 is_negative = true;
170 ts_sec_abs = -(ts_sec + 1);
171 ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
172 } else if (ts_sec < 0 && ts_nsec == 0) {
173 is_negative = true;
174 ts_sec_abs = -ts_sec;
175 ts_nsec_abs = ts_nsec;
176 } else { /* (ts_sec < 0 && ts_nsec < 0) */
177 is_negative = true;
178 ts_sec_abs = -ts_sec;
179 ts_nsec_abs = -ts_nsec;
180 }
181
182 if (!text->options.clock_seconds) {
183 struct tm tm;
184 time_t time_s = (time_t) ts_sec_abs;
185
186 if (is_negative) {
187 fprintf(stderr, "[warning] Fallback to [sec.ns] to print negative time value. Use --clock-seconds.\n");
188 goto seconds;
189 }
190
191 if (!text->options.clock_gmt) {
192 struct tm *res;
193
194 res = localtime_r(&time_s, &tm);
195 if (!res) {
196 fprintf(stderr, "[warning] Unable to get localtime.\n");
197 goto seconds;
198 }
199 } else {
200 struct tm *res;
201
202 res = gmtime_r(&time_s, &tm);
203 if (!res) {
204 fprintf(stderr, "[warning] Unable to get gmtime.\n");
205 goto seconds;
206 }
207 }
208 if (text->options.clock_date) {
209 char timestr[26];
210 size_t res;
211
212 /* Print date and time */
213 res = strftime(timestr, sizeof(timestr),
214 "%F ", &tm);
215 if (!res) {
216 fprintf(stderr, "[warning] Unable to print ascii time.\n");
217 goto seconds;
218 }
219 fprintf(text->out, "%s", timestr);
220 }
221 /* Print time in HH:MM:SS.ns */
222 fprintf(text->out, "%02d:%02d:%02d.%09" PRIu64,
223 tm.tm_hour, tm.tm_min, tm.tm_sec, ts_nsec_abs);
224 goto end;
225 }
226 seconds:
227 fprintf(text->out, "%s%" PRId64 ".%09" PRIu64,
228 is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
229 end:
230 return;
231 }
232
233 static
234 enum bt_component_status print_event_timestamp(struct text_component *text,
235 struct bt_ctf_event *event, bool *start_line)
236 {
237 bool print_names = text->options.print_header_field_names;
238 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
239 struct bt_ctf_stream *stream = NULL;
240 struct bt_ctf_stream_class *stream_class = NULL;
241 struct bt_ctf_trace *trace = NULL;
242 struct bt_ctf_clock_class *clock_class = NULL;
243 FILE *out = text->out;
244
245 stream = bt_ctf_event_get_stream(event);
246 if (!stream) {
247 ret = BT_COMPONENT_STATUS_ERROR;
248 goto end;
249 }
250
251 stream_class = bt_ctf_stream_get_class(stream);
252 if (!stream_class) {
253 ret = BT_COMPONENT_STATUS_ERROR;
254 goto end;
255 }
256 trace = bt_ctf_stream_class_get_trace(stream_class);
257 if (!trace) {
258 ret = BT_COMPONENT_STATUS_ERROR;
259 goto end;
260 }
261 clock_class = bt_ctf_trace_get_clock_class(trace, 0);
262 if (!clock_class) {
263 ret = BT_COMPONENT_STATUS_ERROR;
264 goto end;
265 }
266
267 if (print_names) {
268 print_name_equal(text, "timestamp");
269 } else {
270 fputs("[", out);
271 }
272 if (text->use_colors) {
273 fputs(COLOR_TIMESTAMP, text->out);
274 }
275 if (text->options.print_timestamp_cycles) {
276 print_timestamp_cycles(text, clock_class, event);
277 } else {
278 print_timestamp_wall(text, clock_class, event);
279 }
280 if (text->use_colors) {
281 fputs(COLOR_RST, text->out);
282 }
283
284 if (!print_names)
285 fputs("] ", out);
286
287 if (text->options.print_delta_field) {
288 if (print_names) {
289 fputs(", ", text->out);
290 print_name_equal(text, "delta");
291 } else {
292 fputs("(", text->out);
293 }
294 if (text->options.print_timestamp_cycles) {
295 if (text->delta_cycles == -1ULL) {
296 fputs("+??????????\?\?) ", text->out); /* Not a trigraph. */
297 } else {
298 fprintf(text->out, "+%012" PRIu64, text->delta_cycles);
299 }
300 } else {
301 if (text->delta_real_timestamp != -1ULL) {
302 uint64_t delta_sec, delta_nsec, delta;
303
304 delta = text->delta_real_timestamp;
305 delta_sec = delta / NSEC_PER_SEC;
306 delta_nsec = delta % NSEC_PER_SEC;
307 fprintf(text->out, "+%" PRIu64 ".%09" PRIu64,
308 delta_sec, delta_nsec);
309 } else {
310 fputs("+?.?????????", text->out);
311 }
312 }
313 if (!print_names) {
314 fputs(") ", text->out);
315 }
316 }
317 *start_line = !print_names;
318
319 end:
320 bt_put(stream);
321 bt_put(clock_class);
322 bt_put(stream_class);
323 bt_put(trace);
324 return ret;
325 }
326
327 static
328 enum bt_component_status print_event_header(struct text_component *text,
329 struct bt_ctf_event *event)
330 {
331 bool print_names = text->options.print_header_field_names;
332 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
333 struct bt_ctf_event_class *event_class = NULL;
334 struct bt_ctf_stream_class *stream_class = NULL;
335 struct bt_ctf_trace *trace_class = NULL;
336
337 event_class = bt_ctf_event_get_class(event);
338 if (!event_class) {
339 ret = BT_COMPONENT_STATUS_ERROR;
340 goto end;
341 }
342 stream_class = bt_ctf_event_class_get_stream_class(event_class);
343 if (!stream_class) {
344 ret = BT_COMPONENT_STATUS_ERROR;
345 goto end;
346 }
347 trace_class = bt_ctf_stream_class_get_trace(stream_class);
348 if (!trace_class) {
349 ret = BT_COMPONENT_STATUS_ERROR;
350 goto end;
351 }
352 if (!text->start_line) {
353 fputs(", ", text->out);
354 }
355 text->start_line = false;
356 ret = print_event_timestamp(text, event, &text->start_line);
357 if (ret != BT_COMPONENT_STATUS_OK) {
358 goto end;
359 }
360 if (text->options.print_trace_field) {
361 const char *name;
362
363 name = bt_ctf_trace_get_name(trace_class);
364 if (name) {
365 if (!text->start_line) {
366 fputs(", ", text->out);
367 }
368 text->start_line = false;
369 if (print_names) {
370 print_name_equal(text, "trace");
371 }
372 fprintf(text->out, "%s", name);
373 }
374 }
375 if (text->options.print_trace_hostname_field) {
376 struct bt_value *hostname_str;
377
378 hostname_str = bt_ctf_trace_get_environment_field_value_by_name(trace_class,
379 "hostname");
380 if (hostname_str) {
381 const char *str;
382
383 if (!text->start_line) {
384 fputs(", ", text->out);
385 }
386 text->start_line = false;
387 if (print_names) {
388 print_name_equal(text, "trace:hostname");
389 }
390 if (bt_value_string_get(hostname_str, &str)
391 == BT_VALUE_STATUS_OK) {
392 fprintf(text->out, "%s", str);
393 }
394 bt_put(hostname_str);
395 }
396 }
397 if (text->options.print_trace_domain_field) {
398 struct bt_value *domain_str;
399
400 domain_str = bt_ctf_trace_get_environment_field_value_by_name(trace_class,
401 "domain");
402 if (domain_str) {
403 const char *str;
404
405 if (!text->start_line) {
406 fputs(", ", text->out);
407 }
408 text->start_line = false;
409 if (print_names) {
410 print_name_equal(text, "trace:domain");
411 }
412 if (bt_value_string_get(domain_str, &str)
413 == BT_VALUE_STATUS_OK) {
414 fprintf(text->out, "%s", str);
415 }
416 bt_put(domain_str);
417 }
418 }
419 if (text->options.print_trace_procname_field) {
420 struct bt_value *procname_str;
421
422 procname_str = bt_ctf_trace_get_environment_field_value_by_name(trace_class,
423 "procname");
424 if (procname_str) {
425 const char *str;
426
427 if (!text->start_line) {
428 fputs(", ", text->out);
429 }
430 text->start_line = false;
431 if (print_names) {
432 print_name_equal(text, "trace:procname");
433 }
434 if (bt_value_string_get(procname_str, &str)
435 == BT_VALUE_STATUS_OK) {
436 fprintf(text->out, "%s", str);
437 }
438 bt_put(procname_str);
439 }
440 }
441 if (text->options.print_trace_vpid_field) {
442 struct bt_value *vpid_value;
443
444 vpid_value = bt_ctf_trace_get_environment_field_value_by_name(trace_class,
445 "vpid");
446 if (vpid_value) {
447 int64_t value;
448
449 if (!text->start_line) {
450 fputs(", ", text->out);
451 }
452 text->start_line = false;
453 if (print_names) {
454 print_name_equal(text, "trace:vpid");
455 }
456 if (bt_value_integer_get(vpid_value, &value)
457 == BT_VALUE_STATUS_OK) {
458 fprintf(text->out, "(%" PRId64 ")", value);
459 }
460 bt_put(vpid_value);
461 }
462 }
463 if (text->options.print_loglevel_field) {
464 struct bt_value *loglevel_str, *loglevel_value;
465
466 loglevel_str = bt_ctf_event_class_get_attribute_value_by_name(event_class,
467 "loglevel_string");
468 loglevel_value = bt_ctf_event_class_get_attribute_value_by_name(event_class,
469 "loglevel");
470 if (loglevel_str || loglevel_value) {
471 bool has_str = false;
472
473 if (!text->start_line) {
474 fputs(", ", text->out);
475 }
476 text->start_line = false;
477 if (print_names) {
478 print_name_equal(text, "loglevel");
479 }
480 if (loglevel_str) {
481 const char *str;
482
483 if (bt_value_string_get(loglevel_str, &str)
484 == BT_VALUE_STATUS_OK) {
485 fprintf(text->out, "%s", str);
486 has_str = true;
487 }
488 }
489 if (loglevel_value) {
490 int64_t value;
491
492 if (bt_value_integer_get(loglevel_value, &value)
493 == BT_VALUE_STATUS_OK) {
494 fprintf(text->out, "%s(%" PRId64 ")",
495 has_str ? " " : "", value);
496 }
497 }
498 bt_put(loglevel_str);
499 bt_put(loglevel_value);
500 }
501 }
502 if (text->options.print_emf_field) {
503 struct bt_value *uri_str;
504
505 uri_str = bt_ctf_event_class_get_attribute_value_by_name(event_class,
506 "model.emf.uri");
507 if (uri_str) {
508 if (!text->start_line) {
509 fputs(", ", text->out);
510 }
511 text->start_line = false;
512 if (print_names) {
513 print_name_equal(text, "model.emf.uri");
514 }
515 if (uri_str) {
516 const char *str;
517
518 if (bt_value_string_get(uri_str, &str)
519 == BT_VALUE_STATUS_OK) {
520 fprintf(text->out, "%s", str);
521 }
522 }
523 bt_put(uri_str);
524 }
525 }
526 if (!text->start_line) {
527 fputs(", ", text->out);
528 }
529 text->start_line = false;
530 if (print_names) {
531 print_name_equal(text, "name");
532 }
533 if (text->use_colors) {
534 fputs(COLOR_EVENT_NAME, text->out);
535 }
536 fputs(bt_ctf_event_class_get_name(event_class), text->out);
537 if (text->use_colors) {
538 fputs(COLOR_RST, text->out);
539 }
540 end:
541 bt_put(trace_class);
542 bt_put(stream_class);
543 bt_put(event_class);
544 return ret;
545 }
546
547 static
548 enum bt_component_status print_integer(struct text_component *text,
549 struct bt_ctf_field *field)
550 {
551 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
552 struct bt_ctf_field_type *field_type = NULL;
553 enum bt_ctf_integer_base base;
554 enum bt_ctf_string_encoding encoding;
555 int signedness;
556 union {
557 uint64_t u;
558 int64_t s;
559 } v;
560 bool rst_color = false;
561
562 field_type = bt_ctf_field_get_type(field);
563 if (!field_type) {
564 ret = BT_COMPONENT_STATUS_ERROR;
565 goto end;
566 }
567 signedness = bt_ctf_field_type_integer_get_signed(field_type);
568 if (signedness < 0) {
569 ret = BT_COMPONENT_STATUS_ERROR;
570 goto end;
571 }
572 if (!signedness) {
573 if (bt_ctf_field_unsigned_integer_get_value(field, &v.u) < 0) {
574 ret = BT_COMPONENT_STATUS_ERROR;
575 goto end;
576 }
577 } else {
578 if (bt_ctf_field_signed_integer_get_value(field, &v.s) < 0) {
579 ret = BT_COMPONENT_STATUS_ERROR;
580 goto end;
581 }
582 }
583
584 encoding = bt_ctf_field_type_integer_get_encoding(field_type);
585 switch (encoding) {
586 case BT_CTF_STRING_ENCODING_UTF8:
587 case BT_CTF_STRING_ENCODING_ASCII:
588 g_string_append_c(text->string, (int) v.u);
589 goto end;
590 case BT_CTF_STRING_ENCODING_NONE:
591 case BT_CTF_STRING_ENCODING_UNKNOWN:
592 break;
593 default:
594 ret = BT_COMPONENT_STATUS_ERROR;
595 goto end;
596 }
597
598 if (text->use_colors) {
599 fputs(COLOR_NUMBER_VALUE, text->out);
600 rst_color = true;
601 }
602
603 base = bt_ctf_field_type_integer_get_base(field_type);
604 switch (base) {
605 case BT_CTF_INTEGER_BASE_BINARY:
606 {
607 int bitnr, len;
608
609 len = bt_ctf_field_type_integer_get_size(field_type);
610 if (len < 0) {
611 ret = BT_COMPONENT_STATUS_ERROR;
612 goto end;
613 }
614 fprintf(text->out, "0b");
615 v.u = _bt_piecewise_lshift(v.u, 64 - len);
616 for (bitnr = 0; bitnr < len; bitnr++) {
617 fprintf(text->out, "%u", (v.u & (1ULL << 63)) ? 1 : 0);
618 v.u = _bt_piecewise_lshift(v.u, 1);
619 }
620 break;
621 }
622 case BT_CTF_INTEGER_BASE_OCTAL:
623 {
624 if (signedness) {
625 int len;
626
627 len = bt_ctf_field_type_integer_get_size(field_type);
628 if (len < 0) {
629 ret = BT_COMPONENT_STATUS_ERROR;
630 goto end;
631 }
632 if (len < 64) {
633 size_t rounded_len;
634
635 assert(len != 0);
636 /* Round length to the nearest 3-bit */
637 rounded_len = (((len - 1) / 3) + 1) * 3;
638 v.u &= ((uint64_t) 1 << rounded_len) - 1;
639 }
640 }
641
642 fprintf(text->out, "0%" PRIo64, v.u);
643 break;
644 }
645 case BT_CTF_INTEGER_BASE_DECIMAL:
646 if (!signedness) {
647 fprintf(text->out, "%" PRIu64, v.u);
648 } else {
649 fprintf(text->out, "%" PRId64, v.s);
650 }
651 break;
652 case BT_CTF_INTEGER_BASE_HEXADECIMAL:
653 {
654 int len;
655
656 len = bt_ctf_field_type_integer_get_size(field_type);
657 if (len < 0) {
658 ret = BT_COMPONENT_STATUS_ERROR;
659 goto end;
660 }
661 if (len < 64) {
662 /* Round length to the nearest nibble */
663 uint8_t rounded_len = ((len + 3) & ~0x3);
664
665 v.u &= ((uint64_t) 1 << rounded_len) - 1;
666 }
667
668 fprintf(text->out, "0x%" PRIX64, v.u);
669 break;
670 }
671 default:
672 ret = BT_COMPONENT_STATUS_ERROR;
673 goto end;
674 }
675 end:
676 if (rst_color) {
677 fputs(COLOR_RST, text->out);
678 }
679 bt_put(field_type);
680 return ret;
681 }
682
683 static
684 enum bt_component_status print_enum(struct text_component *text,
685 struct bt_ctf_field *field)
686 {
687 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
688 struct bt_ctf_field *container_field = NULL;
689 struct bt_ctf_field_type *enumeration_field_type = NULL;
690 struct bt_ctf_field_type *container_field_type = NULL;
691 struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL;
692 int nr_mappings = 0;
693 int is_signed;
694
695 enumeration_field_type = bt_ctf_field_get_type(field);
696 if (!enumeration_field_type) {
697 ret = BT_COMPONENT_STATUS_ERROR;
698 goto end;
699 }
700 container_field = bt_ctf_field_enumeration_get_container(field);
701 if (!container_field) {
702 ret = BT_COMPONENT_STATUS_ERROR;
703 goto end;
704 }
705 container_field_type = bt_ctf_field_get_type(container_field);
706 if (!container_field_type) {
707 ret = BT_COMPONENT_STATUS_ERROR;
708 goto end;
709 }
710 is_signed = bt_ctf_field_type_integer_get_signed(container_field_type);
711 if (is_signed < 0) {
712 ret = BT_COMPONENT_STATUS_ERROR;
713 goto end;
714 }
715 if (is_signed) {
716 int64_t value;
717
718 if (bt_ctf_field_signed_integer_get_value(container_field,
719 &value)) {
720 ret = BT_COMPONENT_STATUS_ERROR;
721 goto end;
722 }
723 iter = bt_ctf_field_type_enumeration_find_mappings_by_signed_value(
724 enumeration_field_type, value);
725 } else {
726 uint64_t value;
727
728 if (bt_ctf_field_unsigned_integer_get_value(container_field,
729 &value)) {
730 ret = BT_COMPONENT_STATUS_ERROR;
731 goto end;
732 }
733 iter = bt_ctf_field_type_enumeration_find_mappings_by_unsigned_value(
734 enumeration_field_type, value);
735 }
736 if (!iter) {
737 ret = BT_COMPONENT_STATUS_ERROR;
738 goto end;
739 }
740 fprintf(text->out, "( ");
741 for (;;) {
742 const char *mapping_name;
743
744 if (bt_ctf_field_type_enumeration_mapping_iterator_get_signed(
745 iter, &mapping_name, NULL, NULL) < 0) {
746 ret = BT_COMPONENT_STATUS_ERROR;
747 goto end;
748 }
749 if (nr_mappings++)
750 fprintf(text->out, ", ");
751 if (text->use_colors) {
752 fputs(COLOR_ENUM_MAPPING_NAME, text->out);
753 }
754 // TODO: escape string
755 fprintf(text->out, "\"%s\"", mapping_name);
756 if (text->use_colors) {
757 fputs(COLOR_RST, text->out);
758 }
759 if (bt_ctf_field_type_enumeration_mapping_iterator_next(iter) < 0) {
760 break;
761 }
762 }
763 if (!nr_mappings) {
764 if (text->use_colors) {
765 fputs(COLOR_UNKNOWN, text->out);
766 }
767 fprintf(text->out, "<unknown>");
768 if (text->use_colors) {
769 fputs(COLOR_RST, text->out);
770 }
771 }
772 fprintf(text->out, " : container = ");
773 ret = print_integer(text, container_field);
774 if (ret != BT_COMPONENT_STATUS_OK) {
775 goto end;
776 }
777 fprintf(text->out, " )");
778 end:
779 bt_put(iter);
780 bt_put(container_field_type);
781 bt_put(container_field);
782 bt_put(enumeration_field_type);
783 return ret;
784 }
785
786 static
787 enum bt_component_status print_struct_field(struct text_component *text,
788 struct bt_ctf_field *_struct,
789 struct bt_ctf_field_type *struct_type,
790 int i, bool print_names)
791 {
792 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
793 const char *field_name;
794 struct bt_ctf_field *field = NULL;
795 struct bt_ctf_field_type *field_type = NULL;;
796
797 field = bt_ctf_field_structure_get_field_by_index(_struct, i);
798 if (!field) {
799 ret = BT_COMPONENT_STATUS_ERROR;
800 goto end;
801 }
802 if (bt_ctf_field_type_structure_get_field(struct_type,
803 &field_name, &field_type, i) < 0) {
804 ret = BT_COMPONENT_STATUS_ERROR;
805 goto end;
806 }
807
808 if (i != 0) {
809 fprintf(text->out, ", ");
810 } else {
811 fprintf(text->out, " ");
812 }
813 if (print_names) {
814 print_field_name_equal(text, rem_(field_name));
815 }
816 ret = print_field(text, field, print_names);
817 end:
818 bt_put(field_type);
819 bt_put(field);
820 return ret;
821 }
822
823 static
824 enum bt_component_status print_struct(struct text_component *text,
825 struct bt_ctf_field *_struct, bool print_names)
826 {
827 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
828 struct bt_ctf_field_type *struct_type = NULL;
829 int nr_fields, i;
830
831 struct_type = bt_ctf_field_get_type(_struct);
832 if (!struct_type) {
833 ret = BT_COMPONENT_STATUS_ERROR;
834 goto end;
835 }
836 nr_fields = bt_ctf_field_type_structure_get_field_count(struct_type);
837 if (nr_fields < 0) {
838 ret = BT_COMPONENT_STATUS_ERROR;
839 goto end;
840 }
841 fprintf(text->out, "{");
842 text->depth++;
843 for (i = 0; i < nr_fields; i++) {
844 ret = print_struct_field(text, _struct, struct_type, i,
845 print_names);
846 if (ret != BT_COMPONENT_STATUS_OK) {
847 goto end;
848 }
849 }
850 text->depth--;
851 fprintf(text->out, " }");
852 end:
853 bt_put(struct_type);
854 return ret;
855 }
856
857 static
858 enum bt_component_status print_array_field(struct text_component *text,
859 struct bt_ctf_field *array, uint64_t i,
860 bool is_string, bool print_names)
861 {
862 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
863 struct bt_ctf_field *field = NULL;
864
865 if (!is_string) {
866 if (i != 0) {
867 fprintf(text->out, ", ");
868 } else {
869 fprintf(text->out, " ");
870 }
871 }
872 field = bt_ctf_field_array_get_field(array, i);
873 if (!field) {
874 ret = BT_COMPONENT_STATUS_ERROR;
875 goto end;
876 }
877 ret = print_field(text, field, print_names);
878 end:
879 bt_put(field);
880 return ret;
881 }
882
883 static
884 enum bt_component_status print_array(struct text_component *text,
885 struct bt_ctf_field *array, bool print_names)
886 {
887 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
888 struct bt_ctf_field_type *array_type = NULL, *field_type = NULL;
889 enum bt_ctf_type_id type_id;
890 int64_t len;
891 uint64_t i;
892 bool is_string = false;
893
894 array_type = bt_ctf_field_get_type(array);
895 if (!array_type) {
896 ret = BT_COMPONENT_STATUS_ERROR;
897 goto end;
898 }
899 field_type = bt_ctf_field_type_array_get_element_type(array_type);
900 if (!field_type) {
901 ret = BT_COMPONENT_STATUS_ERROR;
902 goto end;
903 }
904 len = bt_ctf_field_type_array_get_length(array_type);
905 if (len < 0) {
906 ret = BT_COMPONENT_STATUS_ERROR;
907 goto end;
908 }
909 type_id = bt_ctf_field_type_get_type_id(field_type);
910 if (type_id == BT_CTF_TYPE_ID_INTEGER) {
911 enum bt_ctf_string_encoding encoding;
912
913 encoding = bt_ctf_field_type_integer_get_encoding(field_type);
914 if (encoding == BT_CTF_STRING_ENCODING_UTF8
915 || encoding == BT_CTF_STRING_ENCODING_ASCII) {
916 int integer_len, integer_alignment;
917
918 integer_len = bt_ctf_field_type_integer_get_size(field_type);
919 if (integer_len < 0) {
920 return BT_COMPONENT_STATUS_ERROR;
921 }
922 integer_alignment = bt_ctf_field_type_get_alignment(field_type);
923 if (integer_alignment < 0) {
924 return BT_COMPONENT_STATUS_ERROR;
925 }
926 if (integer_len == CHAR_BIT
927 && integer_alignment == CHAR_BIT) {
928 is_string = true;
929 }
930 }
931 }
932
933 if (is_string) {
934 g_string_assign(text->string, "");
935 } else {
936 fprintf(text->out, "[");
937 }
938
939 text->depth++;
940 for (i = 0; i < len; i++) {
941 ret = print_array_field(text, array, i, is_string, print_names);
942 if (ret != BT_COMPONENT_STATUS_OK) {
943 goto end;
944 }
945 }
946 text->depth--;
947
948 if (is_string) {
949 if (text->use_colors) {
950 fputs(COLOR_STRING_VALUE, text->out);
951 }
952 // TODO: escape string
953 fprintf(text->out, "\"%s\"", text->string->str);
954 if (text->use_colors) {
955 fputs(COLOR_RST, text->out);
956 }
957 } else {
958 fprintf(text->out, " ]");
959 }
960 end:
961 bt_put(field_type);
962 bt_put(array_type);
963 return ret;
964 }
965
966 static
967 enum bt_component_status print_sequence_field(struct text_component *text,
968 struct bt_ctf_field *seq, uint64_t i,
969 bool is_string, bool print_names)
970 {
971 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
972 struct bt_ctf_field *field = NULL;
973
974 if (!is_string) {
975 if (i != 0) {
976 fprintf(text->out, ", ");
977 } else {
978 fprintf(text->out, " ");
979 }
980 }
981 field = bt_ctf_field_sequence_get_field(seq, i);
982 if (!field) {
983 ret = BT_COMPONENT_STATUS_ERROR;
984 goto end;
985 }
986 ret = print_field(text, field, print_names);
987 end:
988 bt_put(field);
989 return ret;
990 }
991
992 static
993 enum bt_component_status print_sequence(struct text_component *text,
994 struct bt_ctf_field *seq, bool print_names)
995 {
996 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
997 struct bt_ctf_field_type *seq_type = NULL, *field_type = NULL;
998 struct bt_ctf_field *length_field = NULL;
999 enum bt_ctf_type_id type_id;
1000 uint64_t len;
1001 uint64_t i;
1002 bool is_string = false;
1003
1004 seq_type = bt_ctf_field_get_type(seq);
1005 if (!seq_type) {
1006 ret = BT_COMPONENT_STATUS_ERROR;
1007 goto end;
1008 }
1009 length_field = bt_ctf_field_sequence_get_length(seq);
1010 if (!length_field) {
1011 ret = BT_COMPONENT_STATUS_ERROR;
1012 goto end;
1013 }
1014 if (bt_ctf_field_unsigned_integer_get_value(length_field, &len) < 0) {
1015 ret = BT_COMPONENT_STATUS_ERROR;
1016 goto end;
1017 }
1018 field_type = bt_ctf_field_type_sequence_get_element_type(seq_type);
1019 if (!field_type) {
1020 ret = BT_COMPONENT_STATUS_ERROR;
1021 goto end;
1022 }
1023 type_id = bt_ctf_field_type_get_type_id(field_type);
1024 if (type_id == BT_CTF_TYPE_ID_INTEGER) {
1025 enum bt_ctf_string_encoding encoding;
1026
1027 encoding = bt_ctf_field_type_integer_get_encoding(field_type);
1028 if (encoding == BT_CTF_STRING_ENCODING_UTF8
1029 || encoding == BT_CTF_STRING_ENCODING_ASCII) {
1030 int integer_len, integer_alignment;
1031
1032 integer_len = bt_ctf_field_type_integer_get_size(field_type);
1033 if (integer_len < 0) {
1034 ret = BT_COMPONENT_STATUS_ERROR;
1035 goto end;
1036 }
1037 integer_alignment = bt_ctf_field_type_get_alignment(field_type);
1038 if (integer_alignment < 0) {
1039 ret = BT_COMPONENT_STATUS_ERROR;
1040 goto end;
1041 }
1042 if (integer_len == CHAR_BIT
1043 && integer_alignment == CHAR_BIT) {
1044 is_string = true;
1045 }
1046 }
1047 }
1048
1049 if (is_string) {
1050 g_string_assign(text->string, "");
1051 } else {
1052 fprintf(text->out, "[");
1053 }
1054
1055 text->depth++;
1056 for (i = 0; i < len; i++) {
1057 ret = print_sequence_field(text, seq, i,
1058 is_string, print_names);
1059 if (ret != BT_COMPONENT_STATUS_OK) {
1060 goto end;
1061 }
1062 }
1063 text->depth--;
1064
1065 if (is_string) {
1066 if (text->use_colors) {
1067 fputs(COLOR_STRING_VALUE, text->out);
1068 }
1069 // TODO: escape string
1070 fprintf(text->out, "\"%s\"", text->string->str);
1071 if (text->use_colors) {
1072 fputs(COLOR_RST, text->out);
1073 }
1074 } else {
1075 fprintf(text->out, " ]");
1076 }
1077 end:
1078 bt_put(length_field);
1079 bt_put(field_type);
1080 bt_put(seq_type);
1081 return ret;
1082 }
1083
1084 static
1085 enum bt_component_status print_variant(struct text_component *text,
1086 struct bt_ctf_field *variant, bool print_names)
1087 {
1088 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
1089 struct bt_ctf_field *field = NULL;
1090
1091 field = bt_ctf_field_variant_get_current_field(variant);
1092 if (!field) {
1093 ret = BT_COMPONENT_STATUS_ERROR;
1094 goto end;
1095 }
1096 fprintf(text->out, "{ ");
1097 text->depth++;
1098 if (print_names) {
1099 int iter_ret;
1100 struct bt_ctf_field *tag_field = NULL;
1101 const char *tag_choice;
1102 struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
1103
1104 tag_field = bt_ctf_field_variant_get_tag(variant);
1105 if (!tag_field) {
1106 ret = BT_COMPONENT_STATUS_ERROR;
1107 goto end;
1108 }
1109
1110 iter = bt_ctf_field_enumeration_get_mappings(tag_field);
1111 if (!iter) {
1112 bt_put(tag_field);
1113 ret = BT_COMPONENT_STATUS_ERROR;
1114 goto end;
1115 }
1116
1117 iter_ret =
1118 bt_ctf_field_type_enumeration_mapping_iterator_get_signed(
1119 iter, &tag_choice, NULL, NULL);
1120 if (iter_ret) {
1121 bt_put(iter);
1122 bt_put(tag_field);
1123 ret = BT_COMPONENT_STATUS_ERROR;
1124 goto end;
1125 }
1126 print_field_name_equal(text, rem_(tag_choice));
1127 bt_put(tag_field);
1128 bt_put(iter);
1129 }
1130 ret = print_field(text, field, print_names);
1131 if (ret != BT_COMPONENT_STATUS_OK) {
1132 goto end;
1133 }
1134 text->depth--;
1135 fprintf(text->out, " }");
1136 end:
1137 bt_put(field);
1138 return ret;
1139 }
1140
1141 static
1142 enum bt_component_status print_field(struct text_component *text,
1143 struct bt_ctf_field *field, bool print_names)
1144 {
1145 enum bt_ctf_type_id type_id;
1146
1147 type_id = bt_ctf_field_get_type_id(field);
1148 switch (type_id) {
1149 case CTF_TYPE_INTEGER:
1150 return print_integer(text, field);
1151 case CTF_TYPE_FLOAT:
1152 {
1153 double v;
1154
1155 if (bt_ctf_field_floating_point_get_value(field, &v)) {
1156 return BT_COMPONENT_STATUS_ERROR;
1157 }
1158 if (text->use_colors) {
1159 fputs(COLOR_NUMBER_VALUE, text->out);
1160 }
1161 fprintf(text->out, "%g", v);
1162 if (text->use_colors) {
1163 fputs(COLOR_RST, text->out);
1164 }
1165 return BT_COMPONENT_STATUS_OK;
1166 }
1167 case CTF_TYPE_ENUM:
1168 return print_enum(text, field);
1169 case CTF_TYPE_STRING:
1170 if (text->use_colors) {
1171 fputs(COLOR_STRING_VALUE, text->out);
1172 }
1173 // TODO: escape the string value
1174 fprintf(text->out, "\"%s\"",
1175 bt_ctf_field_string_get_value(field));
1176 if (text->use_colors) {
1177 fputs(COLOR_RST, text->out);
1178 }
1179 return BT_COMPONENT_STATUS_OK;
1180 case CTF_TYPE_STRUCT:
1181 return print_struct(text, field, print_names);
1182 case CTF_TYPE_UNTAGGED_VARIANT:
1183 case CTF_TYPE_VARIANT:
1184 return print_variant(text, field, print_names);
1185 case CTF_TYPE_ARRAY:
1186 return print_array(text, field, print_names);
1187 case CTF_TYPE_SEQUENCE:
1188 return print_sequence(text, field, print_names);
1189 default:
1190 fprintf(text->err, "[error] Unknown type id: %d\n", (int) type_id);
1191 return BT_COMPONENT_STATUS_ERROR;
1192 }
1193 }
1194
1195 static
1196 enum bt_component_status print_stream_packet_context(struct text_component *text,
1197 struct bt_ctf_event *event)
1198 {
1199 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
1200 struct bt_ctf_packet *packet = NULL;
1201 struct bt_ctf_field *main_field = NULL;
1202
1203 packet = bt_ctf_event_get_packet(event);
1204 if (!packet) {
1205 ret = BT_COMPONENT_STATUS_ERROR;
1206 goto end;
1207 }
1208 main_field = bt_ctf_packet_get_context(packet);
1209 if (!main_field) {
1210 goto end;
1211 }
1212 if (!text->start_line) {
1213 fputs(", ", text->out);
1214 }
1215 text->start_line = false;
1216 if (text->options.print_scope_field_names) {
1217 print_name_equal(text, "stream.packet.context");
1218 }
1219 ret = print_field(text, main_field,
1220 text->options.print_context_field_names);
1221 end:
1222 bt_put(main_field);
1223 bt_put(packet);
1224 return ret;
1225 }
1226
1227 static
1228 enum bt_component_status print_event_header_raw(struct text_component *text,
1229 struct bt_ctf_event *event)
1230 {
1231 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
1232 struct bt_ctf_field *main_field = NULL;
1233
1234 main_field = bt_ctf_event_get_header(event);
1235 if (!main_field) {
1236 goto end;
1237 }
1238 if (!text->start_line) {
1239 fputs(", ", text->out);
1240 }
1241 text->start_line = false;
1242 if (text->options.print_scope_field_names) {
1243 print_name_equal(text, "stream.event.header");
1244 }
1245 ret = print_field(text, main_field,
1246 text->options.print_header_field_names);
1247 end:
1248 bt_put(main_field);
1249 return ret;
1250 }
1251
1252 static
1253 enum bt_component_status print_stream_event_context(struct text_component *text,
1254 struct bt_ctf_event *event)
1255 {
1256 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
1257 struct bt_ctf_field *main_field = NULL;
1258
1259 main_field = bt_ctf_event_get_stream_event_context(event);
1260 if (!main_field) {
1261 goto end;
1262 }
1263 if (!text->start_line) {
1264 fputs(", ", text->out);
1265 }
1266 text->start_line = false;
1267 if (text->options.print_scope_field_names) {
1268 print_name_equal(text, "stream.event.context");
1269 }
1270 ret = print_field(text, main_field,
1271 text->options.print_context_field_names);
1272 end:
1273 bt_put(main_field);
1274 return ret;
1275 }
1276
1277 static
1278 enum bt_component_status print_event_context(struct text_component *text,
1279 struct bt_ctf_event *event)
1280 {
1281 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
1282 struct bt_ctf_field *main_field = NULL;
1283
1284 main_field = bt_ctf_event_get_event_context(event);
1285 if (!main_field) {
1286 goto end;
1287 }
1288 if (!text->start_line) {
1289 fputs(", ", text->out);
1290 }
1291 text->start_line = false;
1292 if (text->options.print_scope_field_names) {
1293 print_name_equal(text, "event.context");
1294 }
1295 ret = print_field(text, main_field,
1296 text->options.print_context_field_names);
1297 end:
1298 bt_put(main_field);
1299 return ret;
1300 }
1301
1302 static
1303 enum bt_component_status print_event_payload(struct text_component *text,
1304 struct bt_ctf_event *event)
1305 {
1306 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
1307 struct bt_ctf_field *main_field = NULL;
1308
1309 main_field = bt_ctf_event_get_payload_field(event);
1310 if (!main_field) {
1311 goto end;
1312 }
1313 if (!text->start_line) {
1314 fputs(", ", text->out);
1315 }
1316 text->start_line = false;
1317 if (text->options.print_scope_field_names) {
1318 print_name_equal(text, "event.fields");
1319 }
1320 ret = print_field(text, main_field,
1321 text->options.print_payload_field_names);
1322 end:
1323 bt_put(main_field);
1324 return ret;
1325 }
1326
1327 BT_HIDDEN
1328 enum bt_component_status text_print_event(struct text_component *text,
1329 struct bt_ctf_event *event)
1330 {
1331 enum bt_component_status ret;
1332
1333 text->start_line = true;
1334 ret = print_event_header(text, event);
1335 if (ret != BT_COMPONENT_STATUS_OK) {
1336 goto end;
1337 }
1338
1339 ret = print_stream_packet_context(text, event);
1340 if (ret != BT_COMPONENT_STATUS_OK) {
1341 goto end;
1342 }
1343
1344 ret = print_event_header_raw(text, event);
1345 if (ret != BT_COMPONENT_STATUS_OK) {
1346 goto end;
1347 }
1348
1349 ret = print_stream_event_context(text, event);
1350 if (ret != BT_COMPONENT_STATUS_OK) {
1351 goto end;
1352 }
1353
1354 ret = print_event_context(text, event);
1355 if (ret != BT_COMPONENT_STATUS_OK) {
1356 goto end;
1357 }
1358
1359 ret = print_event_payload(text, event);
1360 if (ret != BT_COMPONENT_STATUS_OK) {
1361 goto end;
1362 }
1363
1364 fputc('\n', text->out);
1365 end:
1366 return ret;
1367 }
This page took 0.054753 seconds and 3 git commands to generate.