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