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