2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 #include <babeltrace2/babeltrace.h>
28 #include "common/assert.h"
29 #include "common/common.h"
30 #include "common/uuid.h"
33 #include "obj-lifetime-mgmt.h"
37 const char *plural(uint64_t value
)
39 return value
== 1 ? "" : "s";
43 void incr_indent_by(struct details_write_ctx
*ctx
, unsigned int value
)
46 ctx
->indent_level
+= value
;
50 void incr_indent(struct details_write_ctx
*ctx
)
52 incr_indent_by(ctx
, 2);
56 void decr_indent_by(struct details_write_ctx
*ctx
, unsigned int value
)
59 BT_ASSERT_DBG(ctx
->indent_level
>= value
);
60 ctx
->indent_level
-= value
;
64 void decr_indent(struct details_write_ctx
*ctx
)
66 decr_indent_by(ctx
, 2);
70 void format_uint(char *buf
, uint64_t value
, unsigned int base
)
72 const char *spec
= "%" PRIu64
;
73 char *buf_start
= buf
;
74 unsigned int digits_per_group
= 3;
76 bool sep_digits
= true;
81 /* TODO: Support binary format */
97 * Do not insert digit separators for numbers
98 * under 10,000 as it looks weird.
108 sprintf(buf_start
, spec
, value
);
111 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
116 void format_int(char *buf
, int64_t value
, unsigned int base
)
118 const char *spec
= "%" PRIu64
;
119 char *buf_start
= buf
;
120 unsigned int digits_per_group
= 3;
122 bool sep_digits
= true;
123 uint64_t abs_value
= value
< 0 ? (uint64_t) -value
: (uint64_t) value
;
133 /* TODO: Support binary format */
135 strcpy(buf_start
, "0x");
137 digits_per_group
= 4;
142 strcpy(buf_start
, "0");
147 if (value
>= -9999 && value
<= 9999) {
149 * Do not insert digit separators for numbers
150 * over -10,000 and under 10,000 as it looks
161 sprintf(buf_start
, spec
, abs_value
);
164 bt_common_sep_digits(buf_start
, digits_per_group
, sep
);
169 void write_nl(struct details_write_ctx
*ctx
)
172 g_string_append_c(ctx
->str
, '\n');
176 void write_sp(struct details_write_ctx
*ctx
)
179 g_string_append_c(ctx
->str
, ' ');
183 void write_indent(struct details_write_ctx
*ctx
)
189 for (i
= 0; i
< ctx
->indent_level
; i
++) {
195 void write_compound_member_name(struct details_write_ctx
*ctx
, const char *name
)
198 g_string_append_printf(ctx
->str
, "%s%s%s:",
199 color_fg_cyan(ctx
), name
, color_reset(ctx
));
203 void write_array_index(struct details_write_ctx
*ctx
, uint64_t index
,
209 format_uint(buf
, index
, 10);
210 g_string_append_printf(ctx
->str
, "%s[%s]%s:",
211 color
, buf
, color_reset(ctx
));
215 void write_obj_type_name(struct details_write_ctx
*ctx
, const char *name
)
217 g_string_append_printf(ctx
->str
, "%s%s%s%s",
218 color_bold(ctx
), color_fg_bright_yellow(ctx
), name
,
223 void write_prop_name(struct details_write_ctx
*ctx
, const char *prop_name
)
225 g_string_append_printf(ctx
->str
, "%s%s%s",
226 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
230 void write_prop_name_line(struct details_write_ctx
*ctx
, const char *prop_name
)
233 g_string_append_printf(ctx
->str
, "%s%s%s:",
234 color_fg_magenta(ctx
), prop_name
, color_reset(ctx
));
238 void write_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
240 g_string_append_printf(ctx
->str
, "%s%s%s",
241 color_bold(ctx
), value
, color_reset(ctx
));
245 void write_none_prop_value(struct details_write_ctx
*ctx
, const char *value
)
247 g_string_append_printf(ctx
->str
, "%s%s%s%s",
248 color_bold(ctx
), color_fg_bright_magenta(ctx
),
249 value
, color_reset(ctx
));
253 void write_uint_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
255 write_str_prop_value(ctx
, value
);
259 void write_uint_prop_value(struct details_write_ctx
*ctx
, uint64_t value
)
263 format_uint(buf
, value
, 10);
264 write_uint_str_prop_value(ctx
, buf
);
268 void write_int_prop_value(struct details_write_ctx
*ctx
, int64_t value
)
272 format_int(buf
, value
, 10);
273 write_uint_str_prop_value(ctx
, buf
);
277 void write_float_prop_value(struct details_write_ctx
*ctx
, double value
)
279 g_string_append_printf(ctx
->str
, "%s%f%s",
280 color_bold(ctx
), value
, color_reset(ctx
));
284 void write_str_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
285 const char *prop_value
)
287 BT_ASSERT_DBG(prop_value
);
289 write_prop_name(ctx
, prop_name
);
290 g_string_append(ctx
->str
, ": ");
291 write_str_prop_value(ctx
, prop_value
);
296 void write_uint_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
300 write_prop_name(ctx
, prop_name
);
301 g_string_append(ctx
->str
, ": ");
302 write_uint_prop_value(ctx
, prop_value
);
307 void write_int_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
311 write_prop_name(ctx
, prop_name
);
312 g_string_append(ctx
->str
, ": ");
313 write_int_prop_value(ctx
, prop_value
);
318 void write_int_str_prop_value(struct details_write_ctx
*ctx
, const char *value
)
320 write_str_prop_value(ctx
, value
);
324 void write_bool_prop_value(struct details_write_ctx
*ctx
, bt_bool prop_value
)
328 g_string_append(ctx
->str
, color_bold(ctx
));
331 g_string_append(ctx
->str
, color_fg_bright_green(ctx
));
334 g_string_append(ctx
->str
, color_fg_bright_red(ctx
));
338 g_string_append_printf(ctx
->str
, "%s%s", str
, color_reset(ctx
));
342 void write_bool_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
346 write_prop_name(ctx
, prop_name
);
347 g_string_append(ctx
->str
, ": ");
348 write_bool_prop_value(ctx
, prop_value
);
353 void write_uuid_prop_line(struct details_write_ctx
*ctx
, const char *prop_name
,
358 write_prop_name(ctx
, prop_name
);
359 g_string_append_printf(ctx
->str
,
360 ": %s" BT_UUID_FMT
"%s\n",
362 BT_UUID_FMT_VALUES(uuid
),
367 gint
compare_strings(const char **a
, const char **b
)
369 return strcmp(*a
, *b
);
373 bt_value_map_foreach_entry_const_func_status
map_value_foreach_add_key_to_array(
374 const char *key
, const bt_value
*object
, void *data
)
376 GPtrArray
*keys
= data
;
379 g_ptr_array_add(keys
, (void *) key
);
380 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK
;
384 void write_value(struct details_write_ctx
*ctx
, const bt_value
*value
,
388 bt_value_type value_type
= bt_value_get_type(value
);
389 GPtrArray
*keys
= g_ptr_array_new();
394 /* Write field's name */
396 write_prop_name_line(ctx
, name
);
399 /* Write field's value */
400 switch (value_type
) {
401 case BT_VALUE_TYPE_NULL
:
403 write_none_prop_value(ctx
, "Null");
405 case BT_VALUE_TYPE_BOOL
:
407 write_bool_prop_value(ctx
, bt_value_bool_get(value
));
409 case BT_VALUE_TYPE_UNSIGNED_INTEGER
:
410 format_uint(buf
, bt_value_integer_unsigned_get(value
), 10);
412 write_uint_str_prop_value(ctx
, buf
);
414 case BT_VALUE_TYPE_SIGNED_INTEGER
:
415 format_int(buf
, bt_value_integer_signed_get(value
), 10);
417 write_int_str_prop_value(ctx
, buf
);
419 case BT_VALUE_TYPE_REAL
:
421 write_float_prop_value(ctx
, bt_value_real_get(value
));
423 case BT_VALUE_TYPE_STRING
:
425 write_str_prop_value(ctx
, bt_value_string_get(value
));
427 case BT_VALUE_TYPE_ARRAY
:
429 uint64_t length
= bt_value_array_get_length(value
);
433 write_none_prop_value(ctx
, "Empty");
435 g_string_append(ctx
->str
, " Length ");
436 write_uint_prop_value(ctx
, length
);
437 g_string_append_c(ctx
->str
, ':');
442 for (i
= 0; i
< length
; i
++) {
443 const bt_value
*elem_value
=
444 bt_value_array_borrow_element_by_index_const(
448 write_array_index(ctx
, i
, color_fg_magenta(ctx
));
449 write_value(ctx
, elem_value
, NULL
);
455 case BT_VALUE_TYPE_MAP
:
457 bt_value_map_foreach_entry_const_status foreach_status
=
458 bt_value_map_foreach_entry_const(value
,
459 map_value_foreach_add_key_to_array
, keys
);
461 BT_ASSERT_DBG(foreach_status
==
462 BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK
);
463 g_ptr_array_sort(keys
, (GCompareFunc
) compare_strings
);
468 for (i
= 0; i
< keys
->len
; i
++) {
469 const char *key
= keys
->pdata
[i
];
470 const bt_value
*entry_value
=
471 bt_value_map_borrow_entry_value_const(
475 write_value(ctx
, entry_value
, key
);
481 write_none_prop_value(ctx
, "Empty");
490 g_ptr_array_free(keys
, TRUE
);
494 void write_user_attributes(struct details_write_ctx
*ctx
,
495 const bt_value
*user_attrs
, bool write_newline
, bool *written
)
497 BT_ASSERT_DBG(user_attrs
);
499 if (!bt_value_map_is_empty(user_attrs
)) {
500 write_value(ctx
, user_attrs
, "User attributes");
513 void write_int_field_class_props(struct details_write_ctx
*ctx
,
514 const bt_field_class
*fc
, bool close
)
516 g_string_append_printf(ctx
->str
, "(%s%" PRIu64
"-bit%s, Base ",
518 bt_field_class_integer_get_field_value_range(fc
),
521 switch (bt_field_class_integer_get_preferred_display_base(fc
)) {
522 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
523 write_uint_prop_value(ctx
, 2);
525 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
526 write_uint_prop_value(ctx
, 8);
528 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
529 write_uint_prop_value(ctx
, 10);
531 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
532 write_uint_prop_value(ctx
, 16);
539 g_string_append(ctx
->str
, ")");
555 struct enum_field_class_mapping
{
559 /* Array of `struct int_range` */
564 gint
compare_enum_field_class_mappings(struct enum_field_class_mapping
**a
,
565 struct enum_field_class_mapping
**b
)
567 return strcmp((*a
)->label
, (*b
)->label
);
571 gint
compare_int_ranges_signed(struct int_range
*a
, struct int_range
*b
)
574 if (a
->lower
.i
< b
->lower
.i
) {
576 } else if (a
->lower
.i
> b
->lower
.i
) {
579 if (a
->upper
.i
< b
->upper
.i
) {
581 } else if (a
->upper
.i
> b
->upper
.i
) {
590 gint
compare_int_ranges_unsigned(struct int_range
*a
, struct int_range
*b
)
592 if (a
->lower
.u
< b
->lower
.u
) {
594 } else if (a
->lower
.u
> b
->lower
.u
) {
597 if (a
->upper
.u
< b
->upper
.u
) {
599 } else if (a
->upper
.u
> b
->upper
.u
) {
608 GArray
*range_set_to_int_ranges(const void *spec_range_set
, bool is_signed
)
611 const bt_integer_range_set
*range_set
;
612 GArray
*ranges
= g_array_new(FALSE
, TRUE
, sizeof(struct int_range
));
619 range_set
= bt_integer_range_set_signed_as_range_set_const(
622 range_set
= bt_integer_range_set_unsigned_as_range_set_const(
626 for (i
= 0; i
< bt_integer_range_set_get_range_count(range_set
); i
++) {
627 struct int_range range
;
630 const bt_integer_range_signed
*orig_range
=
631 bt_integer_range_set_signed_borrow_range_by_index_const(
634 range
.lower
.i
= bt_integer_range_signed_get_lower(orig_range
);
635 range
.upper
.i
= bt_integer_range_signed_get_upper(orig_range
);
637 const bt_integer_range_unsigned
*orig_range
=
638 bt_integer_range_set_unsigned_borrow_range_by_index_const(
641 range
.lower
.u
= bt_integer_range_unsigned_get_lower(orig_range
);
642 range
.upper
.u
= bt_integer_range_unsigned_get_upper(orig_range
);
645 g_array_append_val(ranges
, range
);
649 g_array_sort(ranges
, (GCompareFunc
) compare_int_ranges_signed
);
652 (GCompareFunc
) compare_int_ranges_unsigned
);
660 void destroy_enum_field_class_mapping(struct enum_field_class_mapping
*mapping
)
662 if (mapping
->ranges
) {
663 g_array_free(mapping
->ranges
, TRUE
);
664 mapping
->ranges
= NULL
;
671 struct int_range
*int_range_at(GArray
*ranges
, uint64_t index
)
673 return &g_array_index(ranges
, struct int_range
, index
);
677 void write_int_range(struct details_write_ctx
*ctx
,
678 struct int_range
*range
, bool is_signed
)
680 g_string_append(ctx
->str
, "[");
683 write_int_prop_value(ctx
, range
->lower
.i
);
685 write_int_prop_value(ctx
, range
->lower
.u
);
688 if (range
->lower
.u
!= range
->upper
.u
) {
689 g_string_append(ctx
->str
, ", ");
692 write_int_prop_value(ctx
, range
->upper
.i
);
694 write_int_prop_value(ctx
, range
->upper
.u
);
698 g_string_append(ctx
->str
, "]");
702 void write_enum_field_class_mappings(struct details_write_ctx
*ctx
,
703 const bt_field_class
*fc
)
708 bool is_signed
= bt_field_class_get_type(fc
) ==
709 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
;
711 mappings
= g_ptr_array_new_with_free_func(
712 (GDestroyNotify
) destroy_enum_field_class_mapping
);
713 BT_ASSERT_DBG(mappings
);
716 * Copy field class's mappings to our own arrays and structures
719 for (i
= 0; i
< bt_field_class_enumeration_get_mapping_count(fc
); i
++) {
720 const void *fc_mapping
;
721 const void *fc_range_set
;
722 struct enum_field_class_mapping
*mapping
= g_new0(
723 struct enum_field_class_mapping
, 1);
725 BT_ASSERT_DBG(mapping
);
728 fc_mapping
= bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
730 fc_range_set
= bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
733 fc_mapping
= bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
735 fc_range_set
= bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
739 mapping
->label
= bt_field_class_enumeration_mapping_get_label(
740 bt_field_class_enumeration_signed_mapping_as_mapping_const(
742 mapping
->ranges
= range_set_to_int_ranges(fc_range_set
,
744 BT_ASSERT_DBG(mapping
->ranges
);
745 g_ptr_array_add(mappings
, mapping
);
748 /* Sort mappings (ranges are already sorted within mappings) */
749 g_ptr_array_sort(mappings
,
750 (GCompareFunc
) compare_enum_field_class_mappings
);
753 for (i
= 0; i
< mappings
->len
; i
++) {
754 struct enum_field_class_mapping
*mapping
= mappings
->pdata
[i
];
757 write_prop_name_line(ctx
, mapping
->label
);
759 for (range_i
= 0; range_i
< mapping
->ranges
->len
; range_i
++) {
762 int_range_at(mapping
->ranges
, range_i
),
767 g_ptr_array_free(mappings
, TRUE
);
771 void write_field_path(struct details_write_ctx
*ctx
,
772 const bt_field_path
*field_path
)
776 g_string_append_c(ctx
->str
, '[');
778 switch (bt_field_path_get_root_scope(field_path
)) {
779 case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT
:
780 write_str_prop_value(ctx
, "Packet context");
782 case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT
:
783 write_str_prop_value(ctx
, "Event common context");
785 case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT
:
786 write_str_prop_value(ctx
, "Event specific context");
788 case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD
:
789 write_str_prop_value(ctx
, "Event payload");
795 g_string_append(ctx
->str
, ": ");
797 for (i
= 0; i
< bt_field_path_get_item_count(field_path
); i
++) {
798 const bt_field_path_item
*fp_item
=
799 bt_field_path_borrow_item_by_index_const(field_path
, i
);
802 g_string_append(ctx
->str
, ", ");
805 switch (bt_field_path_item_get_type(fp_item
)) {
806 case BT_FIELD_PATH_ITEM_TYPE_INDEX
:
807 write_uint_prop_value(ctx
,
808 bt_field_path_item_index_get_index(fp_item
));
810 case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT
:
811 write_str_prop_value(ctx
, "<current>");
818 g_string_append_c(ctx
->str
, ']');
822 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
);
825 void write_variant_field_class_option(struct details_write_ctx
*ctx
,
826 const bt_field_class
*fc
, uint64_t index
)
828 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
829 const bt_field_class_variant_option
*option
=
830 bt_field_class_variant_borrow_option_by_index_const(
832 const void *orig_ranges
= NULL
;
833 GArray
*int_ranges
= NULL
;
835 const bt_value
*user_attrs
=
836 bt_field_class_variant_option_borrow_user_attributes_const(
838 const bt_field_class
*option_fc
=
839 bt_field_class_variant_option_borrow_field_class_const(option
);
842 write_compound_member_name(ctx
,
843 bt_field_class_variant_option_get_name(option
));
845 if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
846 const bt_field_class_variant_with_selector_field_integer_unsigned_option
*spec_opt
=
847 bt_field_class_variant_with_selector_field_integer_unsigned_borrow_option_by_index_const(
851 bt_field_class_variant_with_selector_field_integer_unsigned_option_borrow_ranges_const(
854 } else if (fc_type
== BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
855 const bt_field_class_variant_with_selector_field_integer_signed_option
*spec_opt
=
856 bt_field_class_variant_with_selector_field_integer_signed_borrow_option_by_index_const(
860 bt_field_class_variant_with_selector_field_integer_signed_option_borrow_ranges_const(
868 int_ranges
= range_set_to_int_ranges(orig_ranges
, is_signed
);
869 BT_ASSERT_DBG(int_ranges
);
871 for (i
= 0; i
< int_ranges
->len
; i
++) {
872 struct int_range
*range
= int_range_at(int_ranges
, i
);
875 write_int_range(ctx
, range
, is_signed
);
878 g_string_append(ctx
->str
, ": ");
883 if (bt_value_map_is_empty(user_attrs
)) {
884 write_field_class(ctx
, option_fc
);
890 write_prop_name_line(ctx
, "Field class");
892 write_field_class(ctx
, option_fc
);
895 /* User attributes */
896 write_user_attributes(ctx
, user_attrs
,
903 g_array_free(int_ranges
, TRUE
);
908 void write_field_class(struct details_write_ctx
*ctx
, const bt_field_class
*fc
)
912 bt_field_class_type fc_type
= bt_field_class_get_type(fc
);
913 const bt_value
*user_attrs
;
914 bool wrote_user_attrs
= false;
916 /* Write field class's type */
918 case BT_FIELD_CLASS_TYPE_BOOL
:
921 case BT_FIELD_CLASS_TYPE_BIT_ARRAY
:
924 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
:
925 type
= "Unsigned integer";
927 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER
:
928 type
= "Signed integer";
930 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION
:
931 type
= "Unsigned enumeration";
933 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION
:
934 type
= "Signed enumeration";
936 case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
:
937 type
= "Single-precision real";
939 case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
:
940 type
= "Double-precision real";
942 case BT_FIELD_CLASS_TYPE_STRING
:
945 case BT_FIELD_CLASS_TYPE_STRUCTURE
:
948 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY
:
949 type
= "Static array";
951 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD
:
952 type
= "Dynamic array (no length field)";
954 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
:
955 type
= "Dynamic array (with length field)";
957 case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD
:
958 type
= "Option (no selector)";
960 case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
:
961 type
= "Option (boolean selector)";
963 case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
964 type
= "Option (unsigned integer selector)";
966 case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
967 type
= "Option (signed integer selector)";
969 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD
:
970 type
= "Variant (no selector)";
972 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
:
973 type
= "Variant (unsigned integer selector)";
975 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD
:
976 type
= "Variant (signed integer selector)";
982 g_string_append_printf(ctx
->str
, "%s%s%s",
983 color_fg_blue(ctx
), type
, color_reset(ctx
));
985 /* Write field class's single-line properties */
986 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
987 uint64_t mapping_count
=
988 bt_field_class_enumeration_get_mapping_count(fc
);
991 write_int_field_class_props(ctx
, fc
, false);
992 g_string_append(ctx
->str
, ", ");
993 write_uint_prop_value(ctx
, mapping_count
);
994 g_string_append_printf(ctx
->str
, " mapping%s)",
995 plural(mapping_count
));
996 } else if (bt_field_class_type_is(fc_type
,
997 BT_FIELD_CLASS_TYPE_INTEGER
)) {
999 write_int_field_class_props(ctx
, fc
, true);
1000 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1001 uint64_t member_count
=
1002 bt_field_class_structure_get_member_count(fc
);
1004 g_string_append(ctx
->str
, " (");
1005 write_uint_prop_value(ctx
, member_count
);
1006 g_string_append_printf(ctx
->str
, " member%s)",
1007 plural(member_count
));
1008 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STATIC_ARRAY
) {
1009 g_string_append(ctx
->str
, " (Length ");
1010 write_uint_prop_value(ctx
,
1011 bt_field_class_array_static_get_length(fc
));
1012 g_string_append_c(ctx
->str
, ')');
1013 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD
) {
1014 const bt_field_path
*length_field_path
=
1015 bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
1018 g_string_append(ctx
->str
, " (Length field path ");
1019 write_field_path(ctx
, length_field_path
);
1020 g_string_append_c(ctx
->str
, ')');
1021 } else if (bt_field_class_type_is(fc_type
,
1022 BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD
)) {
1023 const bt_field_path
*selector_field_path
=
1024 bt_field_class_option_with_selector_field_borrow_selector_field_path_const(
1027 g_string_append(ctx
->str
, " (Selector field path ");
1028 write_field_path(ctx
, selector_field_path
);
1029 g_string_append_c(ctx
->str
, ')');
1030 } else if (bt_field_class_type_is(fc_type
,
1031 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1032 uint64_t option_count
=
1033 bt_field_class_variant_get_option_count(fc
);
1034 const bt_field_path
*sel_field_path
= NULL
;
1036 if (bt_field_class_type_is(fc_type
,
1037 BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD
)) {
1039 bt_field_class_variant_with_selector_field_borrow_selector_field_path_const(
1041 BT_ASSERT_DBG(sel_field_path
);
1044 g_string_append(ctx
->str
, " (");
1045 write_uint_prop_value(ctx
, option_count
);
1046 g_string_append_printf(ctx
->str
, " option%s",
1047 plural(option_count
));
1049 if (sel_field_path
) {
1050 g_string_append(ctx
->str
, ", Selector field path ");
1051 write_field_path(ctx
, sel_field_path
);
1054 g_string_append_c(ctx
->str
, ')');
1058 user_attrs
= bt_field_class_borrow_user_attributes_const(fc
);
1059 if (!bt_value_map_is_empty(user_attrs
)) {
1060 g_string_append(ctx
->str
, ":\n");
1061 write_user_attributes(ctx
, user_attrs
, false, NULL
);
1062 wrote_user_attrs
= true;
1065 /* Write field class's complex properties */
1066 if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ENUMERATION
)) {
1067 uint64_t mapping_count
=
1068 bt_field_class_enumeration_get_mapping_count(fc
);
1070 if (mapping_count
> 0) {
1071 if (wrote_user_attrs
) {
1074 write_prop_name(ctx
, "Mappings");
1075 g_string_append_c(ctx
->str
, ':');
1078 /* Each mapping starts with its own newline */
1079 g_string_append_c(ctx
->str
, ':');
1082 write_enum_field_class_mappings(ctx
, fc
);
1084 if (wrote_user_attrs
) {
1088 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1089 uint64_t member_count
=
1090 bt_field_class_structure_get_member_count(fc
);
1092 if (member_count
> 0) {
1093 if (wrote_user_attrs
) {
1096 write_prop_name(ctx
, "Members");
1097 g_string_append_c(ctx
->str
, ':');
1100 /* Each member starts with its own newline */
1101 g_string_append_c(ctx
->str
, ':');
1104 for (i
= 0; i
< member_count
; i
++) {
1105 const bt_field_class_structure_member
*member
=
1106 bt_field_class_structure_borrow_member_by_index_const(
1108 const bt_value
*member_user_attrs
;
1109 const bt_field_class
*member_fc
=
1110 bt_field_class_structure_member_borrow_field_class_const(member
);
1113 write_compound_member_name(ctx
,
1114 bt_field_class_structure_member_get_name(member
));
1115 member_user_attrs
= bt_field_class_structure_member_borrow_user_attributes_const(
1118 if (bt_value_map_is_empty(member_user_attrs
)) {
1120 write_field_class(ctx
, member_fc
);
1126 write_prop_name_line(ctx
, "Field class");
1128 write_field_class(ctx
, member_fc
);
1131 /* User attributes */
1132 write_user_attributes(ctx
, member_user_attrs
,
1139 if (wrote_user_attrs
) {
1143 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1144 if (wrote_user_attrs
) {
1147 g_string_append(ctx
->str
, ":\n");
1150 write_prop_name_line(ctx
, "Element");
1152 write_field_class(ctx
,
1153 bt_field_class_array_borrow_element_field_class_const(fc
));
1154 } else if (bt_field_class_type_is(fc_type
,
1155 BT_FIELD_CLASS_TYPE_OPTION
)) {
1156 const void *ranges
= NULL
;
1157 bool selector_is_signed
= false;
1159 if (wrote_user_attrs
) {
1162 g_string_append(ctx
->str
, ":\n");
1165 if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD
) {
1166 write_bool_prop_line(ctx
, "Selector is reversed",
1167 bt_field_class_option_with_selector_field_bool_selector_is_reversed(fc
));
1168 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD
) {
1169 ranges
= bt_field_class_option_with_selector_field_integer_unsigned_borrow_selector_ranges_const(fc
);
1170 } else if (fc_type
== BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD
) {
1171 ranges
= bt_field_class_option_with_selector_field_integer_signed_borrow_selector_ranges_const(fc
);
1172 selector_is_signed
= true;
1176 GArray
*sorted_ranges
= range_set_to_int_ranges(
1177 ranges
, selector_is_signed
);
1179 BT_ASSERT_DBG(sorted_ranges
);
1180 BT_ASSERT_DBG(sorted_ranges
->len
> 0);
1181 write_prop_name_line(ctx
, "Selector ranges");
1183 for (i
= 0; i
< sorted_ranges
->len
; i
++) {
1185 write_int_range(ctx
,
1186 int_range_at(sorted_ranges
, i
),
1187 selector_is_signed
);
1191 g_array_free(sorted_ranges
, TRUE
);
1194 write_prop_name_line(ctx
, "Content");
1196 write_field_class(ctx
,
1197 bt_field_class_option_borrow_field_class_const(fc
));
1198 } else if (bt_field_class_type_is(fc_type
,
1199 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1200 uint64_t option_count
=
1201 bt_field_class_variant_get_option_count(fc
);
1203 if (option_count
> 0) {
1204 if (wrote_user_attrs
) {
1207 write_prop_name(ctx
, "Options");
1208 g_string_append_c(ctx
->str
, ':');
1211 /* Each option starts with its own newline */
1212 g_string_append_c(ctx
->str
, ':');
1215 for (i
= 0; i
< option_count
; i
++) {
1216 write_variant_field_class_option(ctx
, fc
, i
);
1219 if (wrote_user_attrs
) {
1229 void write_root_field_class(struct details_write_ctx
*ctx
, const char *name
,
1230 const bt_field_class
*fc
)
1232 BT_ASSERT_DBG(name
);
1235 write_prop_name(ctx
, name
);
1236 g_string_append(ctx
->str
, ": ");
1237 write_field_class(ctx
, fc
);
1242 void write_event_class(struct details_write_ctx
*ctx
, const bt_event_class
*ec
)
1244 const char *name
= bt_event_class_get_name(ec
);
1245 const char *emf_uri
;
1246 const bt_field_class
*fc
;
1247 bt_event_class_log_level log_level
;
1250 write_obj_type_name(ctx
, "Event class");
1252 /* Write name and ID */
1254 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1255 color_fg_green(ctx
), name
, color_reset(ctx
));
1258 g_string_append(ctx
->str
, " (ID ");
1259 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
1260 g_string_append(ctx
->str
, "):\n");
1262 /* Write properties */
1265 /* Write user attributes */
1266 write_user_attributes(ctx
,
1267 bt_event_class_borrow_user_attributes_const(ec
), true, NULL
);
1269 /* Write log level */
1270 if (bt_event_class_get_log_level(ec
, &log_level
) ==
1271 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
1272 const char *ll_str
= NULL
;
1274 switch (log_level
) {
1275 case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY
:
1276 ll_str
= "Emergency";
1278 case BT_EVENT_CLASS_LOG_LEVEL_ALERT
:
1281 case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL
:
1282 ll_str
= "Critical";
1284 case BT_EVENT_CLASS_LOG_LEVEL_ERROR
:
1287 case BT_EVENT_CLASS_LOG_LEVEL_WARNING
:
1290 case BT_EVENT_CLASS_LOG_LEVEL_NOTICE
:
1293 case BT_EVENT_CLASS_LOG_LEVEL_INFO
:
1296 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
:
1297 ll_str
= "Debug (system)";
1299 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
:
1300 ll_str
= "Debug (program)";
1302 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
:
1303 ll_str
= "Debug (process)";
1305 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
:
1306 ll_str
= "Debug (module)";
1308 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
:
1309 ll_str
= "Debug (unit)";
1311 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
:
1312 ll_str
= "Debug (function)";
1314 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
:
1315 ll_str
= "Debug (line)";
1317 case BT_EVENT_CLASS_LOG_LEVEL_DEBUG
:
1324 write_str_prop_line(ctx
, "Log level", ll_str
);
1328 emf_uri
= bt_event_class_get_emf_uri(ec
);
1330 write_str_prop_line(ctx
, "EMF URI", emf_uri
);
1333 /* Write specific context field class */
1334 fc
= bt_event_class_borrow_specific_context_field_class_const(ec
);
1336 write_root_field_class(ctx
, "Specific context field class", fc
);
1339 /* Write payload field class */
1340 fc
= bt_event_class_borrow_payload_field_class_const(ec
);
1342 write_root_field_class(ctx
, "Payload field class", fc
);
1349 void write_clock_class_prop_lines(struct details_write_ctx
*ctx
,
1350 const bt_clock_class
*cc
)
1352 int64_t offset_seconds
;
1353 uint64_t offset_cycles
;
1356 str
= bt_clock_class_get_name(cc
);
1358 write_str_prop_line(ctx
, "Name", str
);
1361 write_user_attributes(ctx
,
1362 bt_clock_class_borrow_user_attributes_const(cc
), true, NULL
);
1363 str
= bt_clock_class_get_description(cc
);
1365 write_str_prop_line(ctx
, "Description", str
);
1368 write_uint_prop_line(ctx
, "Frequency (Hz)",
1369 bt_clock_class_get_frequency(cc
));
1370 write_uint_prop_line(ctx
, "Precision (cycles)",
1371 bt_clock_class_get_precision(cc
));
1372 bt_clock_class_get_offset(cc
, &offset_seconds
, &offset_cycles
);
1373 write_int_prop_line(ctx
, "Offset (s)", offset_seconds
);
1374 write_uint_prop_line(ctx
, "Offset (cycles)", offset_cycles
);
1375 write_bool_prop_line(ctx
, "Origin is Unix epoch",
1376 bt_clock_class_origin_is_unix_epoch(cc
));
1378 if (ctx
->details_comp
->cfg
.with_uuid
) {
1379 bt_uuid uuid
= bt_clock_class_get_uuid(cc
);
1382 write_uuid_prop_line(ctx
, "UUID", uuid
);
1388 gint
compare_event_classes(const bt_event_class
**a
, const bt_event_class
**b
)
1390 uint64_t id_a
= bt_event_class_get_id(*a
);
1391 uint64_t id_b
= bt_event_class_get_id(*b
);
1395 } else if (id_a
> id_b
) {
1403 void write_stream_class(struct details_write_ctx
*ctx
,
1404 const bt_stream_class
*sc
)
1406 const bt_field_class
*fc
;
1407 GPtrArray
*event_classes
= g_ptr_array_new();
1411 write_obj_type_name(ctx
, "Stream class");
1413 /* Write name and ID */
1414 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
1415 const char *name
= bt_stream_class_get_name(sc
);
1418 g_string_append(ctx
->str
, " `");
1419 write_str_prop_value(ctx
, name
);
1420 g_string_append(ctx
->str
, "`");
1424 g_string_append(ctx
->str
, " (ID ");
1425 write_uint_prop_value(ctx
, bt_stream_class_get_id(sc
));
1426 g_string_append(ctx
->str
, "):\n");
1428 /* Write properties */
1431 /* Write user attributes */
1432 write_user_attributes(ctx
,
1433 bt_stream_class_borrow_user_attributes_const(sc
), true, NULL
);
1435 /* Write configuration */
1436 write_bool_prop_line(ctx
,
1437 "Supports packets", bt_stream_class_supports_packets(sc
));
1439 if (bt_stream_class_supports_packets(sc
)) {
1440 write_bool_prop_line(ctx
,
1441 "Packets have beginning default clock snapshot",
1442 bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
));
1443 write_bool_prop_line(ctx
,
1444 "Packets have end default clock snapshot",
1445 bt_stream_class_packets_have_end_default_clock_snapshot(sc
));
1448 write_bool_prop_line(ctx
,
1449 "Supports discarded events",
1450 bt_stream_class_supports_discarded_events(sc
));
1452 if (bt_stream_class_supports_discarded_events(sc
)) {
1453 write_bool_prop_line(ctx
,
1454 "Discarded events have default clock snapshots",
1455 bt_stream_class_discarded_events_have_default_clock_snapshots(sc
));
1458 write_bool_prop_line(ctx
,
1459 "Supports discarded packets",
1460 bt_stream_class_supports_discarded_packets(sc
));
1462 if (bt_stream_class_supports_discarded_packets(sc
)) {
1463 write_bool_prop_line(ctx
,
1464 "Discarded packets have default clock snapshots",
1465 bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
));
1468 /* Write default clock class */
1469 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1471 write_prop_name(ctx
, "Default clock class");
1472 g_string_append_c(ctx
->str
, ':');
1475 write_clock_class_prop_lines(ctx
,
1476 bt_stream_class_borrow_default_clock_class_const(sc
));
1480 fc
= bt_stream_class_borrow_packet_context_field_class_const(sc
);
1482 write_root_field_class(ctx
, "Packet context field class", fc
);
1485 fc
= bt_stream_class_borrow_event_common_context_field_class_const(sc
);
1487 write_root_field_class(ctx
, "Event common context field class",
1491 for (i
= 0; i
< bt_stream_class_get_event_class_count(sc
); i
++) {
1492 g_ptr_array_add(event_classes
,
1493 (gpointer
) bt_stream_class_borrow_event_class_by_index_const(
1497 g_ptr_array_sort(event_classes
, (GCompareFunc
) compare_event_classes
);
1499 for (i
= 0; i
< event_classes
->len
; i
++) {
1500 write_event_class(ctx
, event_classes
->pdata
[i
]);
1504 g_ptr_array_free(event_classes
, TRUE
);
1508 gint
compare_stream_classes(const bt_stream_class
**a
, const bt_stream_class
**b
)
1510 uint64_t id_a
= bt_stream_class_get_id(*a
);
1511 uint64_t id_b
= bt_stream_class_get_id(*b
);
1515 } else if (id_a
> id_b
) {
1523 void write_trace_class(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
)
1525 GPtrArray
*stream_classes
= g_ptr_array_new();
1527 bool printed_prop
= false;
1530 write_obj_type_name(ctx
, "Trace class");
1533 for (i
= 0; i
< bt_trace_class_get_stream_class_count(tc
); i
++) {
1534 g_ptr_array_add(stream_classes
,
1535 (gpointer
) bt_trace_class_borrow_stream_class_by_index_const(
1539 g_ptr_array_sort(stream_classes
, (GCompareFunc
) compare_stream_classes
);
1541 if (stream_classes
->len
> 0) {
1542 if (!printed_prop
) {
1543 g_string_append(ctx
->str
, ":\n");
1544 printed_prop
= true;
1550 /* Write user attributes */
1551 write_user_attributes(ctx
,
1552 bt_trace_class_borrow_user_attributes_const(tc
), true,
1555 /* Write stream classes */
1556 for (i
= 0; i
< stream_classes
->len
; i
++) {
1557 write_stream_class(ctx
, stream_classes
->pdata
[i
]);
1560 if (!printed_prop
) {
1565 g_ptr_array_free(stream_classes
, TRUE
);
1569 int try_write_meta(struct details_write_ctx
*ctx
, const bt_trace_class
*tc
,
1570 const bt_stream_class
*sc
, const bt_event_class
*ec
)
1576 if (details_need_to_write_trace_class(ctx
, tc
)) {
1579 if (ctx
->details_comp
->cfg
.compact
&&
1580 ctx
->details_comp
->printed_something
) {
1582 * There are no empty line between messages in
1583 * compact mode, so write one here to decouple
1584 * the trace class from the next message.
1590 * write_trace_class() also writes all its stream
1591 * classes their event classes, so we don't need to
1594 write_trace_class(ctx
, tc
);
1597 * Mark this trace class as written, as well as all
1598 * its stream classes and their event classes.
1600 ret
= details_did_write_trace_class(ctx
, tc
);
1605 for (sc_i
= 0; sc_i
< bt_trace_class_get_stream_class_count(tc
);
1608 const bt_stream_class
*tc_sc
=
1609 bt_trace_class_borrow_stream_class_by_index_const(
1612 details_did_write_meta_object(ctx
, tc
, tc_sc
);
1614 for (ec_i
= 0; ec_i
<
1615 bt_stream_class_get_event_class_count(tc_sc
);
1617 details_did_write_meta_object(ctx
, tc
,
1618 bt_stream_class_borrow_event_class_by_index_const(
1626 if (sc
&& details_need_to_write_meta_object(ctx
, tc
, sc
)) {
1631 if (ctx
->details_comp
->cfg
.compact
&&
1632 ctx
->details_comp
->printed_something
) {
1634 * There are no empty line between messages in
1635 * compact mode, so write one here to decouple
1636 * the stream class from the next message.
1642 * write_stream_class() also writes all its event
1643 * classes, so we don't need to rewrite `ec`.
1645 write_stream_class(ctx
, sc
);
1648 * Mark this stream class as written, as well as all its
1651 details_did_write_meta_object(ctx
, tc
, sc
);
1653 for (ec_i
= 0; ec_i
<
1654 bt_stream_class_get_event_class_count(sc
);
1656 details_did_write_meta_object(ctx
, tc
,
1657 bt_stream_class_borrow_event_class_by_index_const(
1664 if (ec
&& details_need_to_write_meta_object(ctx
, tc
, ec
)) {
1667 if (ctx
->details_comp
->cfg
.compact
&&
1668 ctx
->details_comp
->printed_something
) {
1670 * There are no empty line between messages in
1671 * compact mode, so write one here to decouple
1672 * the event class from the next message.
1677 write_event_class(ctx
, ec
);
1678 details_did_write_meta_object(ctx
, tc
, ec
);
1687 void write_time_str(struct details_write_ctx
*ctx
, const char *str
)
1689 if (!ctx
->details_comp
->cfg
.with_time
) {
1693 g_string_append_printf(ctx
->str
, "[%s%s%s%s]",
1694 color_bold(ctx
), color_fg_bright_blue(ctx
), str
,
1697 if (ctx
->details_comp
->cfg
.compact
) {
1708 void write_time(struct details_write_ctx
*ctx
, const bt_clock_snapshot
*cs
)
1710 bt_clock_snapshot_get_ns_from_origin_status cs_status
;
1711 int64_t ns_from_origin
;
1714 if (!ctx
->details_comp
->cfg
.with_time
) {
1718 format_uint(buf
, bt_clock_snapshot_get_value(cs
), 10);
1719 g_string_append_printf(ctx
->str
, "[%s%s%s%s%s",
1720 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1722 ctx
->details_comp
->cfg
.compact
? "" : " cycles");
1723 cs_status
= bt_clock_snapshot_get_ns_from_origin(cs
, &ns_from_origin
);
1724 if (cs_status
== BT_CLOCK_SNAPSHOT_GET_NS_FROM_ORIGIN_STATUS_OK
) {
1725 format_int(buf
, ns_from_origin
, 10);
1726 g_string_append_printf(ctx
->str
, "%s %s%s%s%s%s",
1727 ctx
->details_comp
->cfg
.compact
? "" : ",",
1728 color_bold(ctx
), color_fg_bright_blue(ctx
), buf
,
1730 ctx
->details_comp
->cfg
.compact
? "" : " ns from origin");
1733 g_string_append(ctx
->str
, "]");
1735 if (ctx
->details_comp
->cfg
.compact
) {
1746 int write_message_follow_tag(struct details_write_ctx
*ctx
,
1747 const bt_stream
*stream
)
1750 uint64_t unique_trace_id
;
1751 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
1752 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
1754 ret
= details_trace_unique_id(ctx
, trace
, &unique_trace_id
);
1759 if (ctx
->details_comp
->cfg
.compact
) {
1760 g_string_append_printf(ctx
->str
,
1761 "%s{%s%s%" PRIu64
" %" PRIu64
" %" PRIu64
"%s%s}%s ",
1762 color_fg_cyan(ctx
), color_bold(ctx
),
1763 color_fg_bright_cyan(ctx
),
1764 unique_trace_id
, bt_stream_class_get_id(sc
),
1765 bt_stream_get_id(stream
),
1766 color_reset(ctx
), color_fg_cyan(ctx
), color_reset(ctx
));
1768 g_string_append_printf(ctx
->str
,
1769 "%s{Trace %s%s%" PRIu64
"%s%s, Stream class ID %s%s%" PRIu64
"%s%s, Stream ID %s%s%" PRIu64
"%s%s}%s\n",
1771 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1772 unique_trace_id
, color_reset(ctx
),
1774 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1775 bt_stream_class_get_id(sc
), color_reset(ctx
),
1777 color_bold(ctx
), color_fg_bright_cyan(ctx
),
1778 bt_stream_get_id(stream
), color_reset(ctx
),
1779 color_fg_cyan(ctx
), color_reset(ctx
));
1787 void write_field(struct details_write_ctx
*ctx
, const bt_field
*field
,
1791 bt_field_class_type fc_type
= bt_field_get_class_type(field
);
1792 const bt_field_class
*fc
;
1795 /* Write field's name */
1797 write_compound_member_name(ctx
, name
);
1800 /* Write field's value */
1801 if (fc_type
== BT_FIELD_CLASS_TYPE_BOOL
) {
1803 write_bool_prop_value(ctx
, bt_field_bool_get_value(field
));
1804 } else if (fc_type
== BT_FIELD_CLASS_TYPE_BIT_ARRAY
) {
1805 format_uint(buf
, bt_field_bit_array_get_value_as_integer(field
),
1808 write_uint_str_prop_value(ctx
, buf
);
1809 } else if (bt_field_class_type_is(fc_type
,
1810 BT_FIELD_CLASS_TYPE_INTEGER
)) {
1811 unsigned int fmt_base
;
1812 bt_field_class_integer_preferred_display_base base
;
1814 fc
= bt_field_borrow_class_const(field
);
1815 base
= bt_field_class_integer_get_preferred_display_base(fc
);
1818 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
:
1821 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
:
1824 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
:
1827 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
:
1834 if (bt_field_class_type_is(fc_type
,
1835 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER
)) {
1837 bt_field_integer_unsigned_get_value(field
),
1840 write_uint_str_prop_value(ctx
, buf
);
1843 bt_field_integer_signed_get_value(field
),
1846 write_int_str_prop_value(ctx
, buf
);
1848 } else if (fc_type
== BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL
) {
1850 write_float_prop_value(ctx
, bt_field_real_single_precision_get_value(field
));
1851 } else if (fc_type
== BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL
) {
1853 write_float_prop_value(ctx
, bt_field_real_double_precision_get_value(field
));
1854 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRING
) {
1856 write_str_prop_value(ctx
, bt_field_string_get_value(field
));
1857 } else if (fc_type
== BT_FIELD_CLASS_TYPE_STRUCTURE
) {
1858 uint64_t member_count
;
1860 fc
= bt_field_borrow_class_const(field
);
1861 member_count
= bt_field_class_structure_get_member_count(fc
);
1863 if (member_count
> 0) {
1866 for (i
= 0; i
< member_count
; i
++) {
1867 const bt_field_class_structure_member
*member
=
1868 bt_field_class_structure_borrow_member_by_index_const(
1870 const bt_field
*member_field
=
1871 bt_field_structure_borrow_member_field_by_index_const(
1875 write_field(ctx
, member_field
,
1876 bt_field_class_structure_member_get_name(member
));
1882 write_none_prop_value(ctx
, "Empty");
1884 } else if (bt_field_class_type_is(fc_type
, BT_FIELD_CLASS_TYPE_ARRAY
)) {
1885 uint64_t length
= bt_field_array_get_length(field
);
1889 write_none_prop_value(ctx
, "Empty");
1891 g_string_append(ctx
->str
, " Length ");
1892 write_uint_prop_value(ctx
, length
);
1893 g_string_append_c(ctx
->str
, ':');
1898 for (i
= 0; i
< length
; i
++) {
1899 const bt_field
*elem_field
=
1900 bt_field_array_borrow_element_field_by_index_const(
1904 write_array_index(ctx
, i
, color_fg_cyan(ctx
));
1905 write_field(ctx
, elem_field
, NULL
);
1909 } else if (bt_field_class_type_is(fc_type
,
1910 BT_FIELD_CLASS_TYPE_OPTION
)) {
1911 const bt_field
*content_field
=
1912 bt_field_option_borrow_field_const(field
);
1914 if (!content_field
) {
1916 write_none_prop_value(ctx
, "None");
1918 write_field(ctx
, content_field
, NULL
);
1920 } else if (bt_field_class_type_is(fc_type
,
1921 BT_FIELD_CLASS_TYPE_VARIANT
)) {
1923 bt_field_variant_borrow_selected_option_field_const(
1931 void write_root_field(struct details_write_ctx
*ctx
, const char *name
,
1932 const bt_field
*field
)
1934 BT_ASSERT_DBG(name
);
1935 BT_ASSERT_DBG(field
);
1937 write_prop_name(ctx
, name
);
1938 g_string_append(ctx
->str
, ":");
1939 write_field(ctx
, field
, NULL
);
1944 int write_event_message(struct details_write_ctx
*ctx
,
1945 const bt_message
*msg
)
1948 const bt_event
*event
= bt_message_event_borrow_event_const(msg
);
1949 const bt_stream
*stream
= bt_event_borrow_stream_const(event
);
1950 const bt_event_class
*ec
= bt_event_borrow_class_const(event
);
1951 const bt_stream_class
*sc
= bt_event_class_borrow_stream_class_const(ec
);
1952 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
1953 const char *ec_name
;
1954 const bt_field
*field
;
1956 ret
= try_write_meta(ctx
, tc
, sc
, ec
);
1961 if (!ctx
->details_comp
->cfg
.with_data
) {
1965 if (ctx
->str
->len
> 0) {
1967 * Output buffer contains metadata: separate blocks with
1974 if (bt_stream_class_borrow_default_clock_class_const(sc
)) {
1976 bt_message_event_borrow_default_clock_snapshot_const(
1980 /* Write follow tag for message */
1981 ret
= write_message_follow_tag(ctx
, stream
);
1986 /* Write object's basic properties */
1987 write_obj_type_name(ctx
, "Event");
1988 ec_name
= bt_event_class_get_name(ec
);
1990 g_string_append_printf(ctx
->str
, " `%s%s%s`",
1991 color_fg_green(ctx
), ec_name
, color_reset(ctx
));
1994 g_string_append(ctx
->str
, " (");
1996 if (!ctx
->details_comp
->cfg
.compact
) {
1997 g_string_append(ctx
->str
, "Class ID ");
2000 write_uint_prop_value(ctx
, bt_event_class_get_id(ec
));
2001 g_string_append(ctx
->str
, ")");
2003 if (ctx
->details_comp
->cfg
.compact
) {
2009 g_string_append(ctx
->str
, ":\n");
2011 field
= bt_event_borrow_common_context_field_const(event
);
2013 write_root_field(ctx
, "Common context", field
);
2016 field
= bt_event_borrow_specific_context_field_const(event
);
2018 write_root_field(ctx
, "Specific context", field
);
2021 field
= bt_event_borrow_payload_field_const(event
);
2023 write_root_field(ctx
, "Payload", field
);
2033 gint
compare_streams(const bt_stream
**a
, const bt_stream
**b
)
2035 uint64_t id_a
= bt_stream_get_id(*a
);
2036 uint64_t id_b
= bt_stream_get_id(*b
);
2040 } else if (id_a
> id_b
) {
2043 const bt_stream_class
*a_sc
= bt_stream_borrow_class_const(*a
);
2044 const bt_stream_class
*b_sc
= bt_stream_borrow_class_const(*b
);
2045 uint64_t a_sc_id
= bt_stream_class_get_id(a_sc
);
2046 uint64_t b_sc_id
= bt_stream_class_get_id(b_sc
);
2048 if (a_sc_id
< b_sc_id
) {
2050 } else if (a_sc_id
> b_sc_id
) {
2059 void write_trace(struct details_write_ctx
*ctx
, const bt_trace
*trace
)
2061 GPtrArray
*streams
= g_ptr_array_new();
2063 bool printed_prop
= false;
2064 GPtrArray
*env_names
= g_ptr_array_new();
2068 write_obj_type_name(ctx
, "Trace");
2071 if (ctx
->details_comp
->cfg
.with_trace_name
) {
2072 const char *name
= bt_trace_get_name(trace
);
2074 g_string_append(ctx
->str
, " `");
2075 write_str_prop_value(ctx
, name
);
2076 g_string_append(ctx
->str
, "`");
2080 /* Write properties */
2084 if (ctx
->details_comp
->cfg
.with_uuid
) {
2085 bt_uuid uuid
= bt_trace_get_uuid(trace
);
2088 if (!printed_prop
) {
2089 g_string_append(ctx
->str
, ":\n");
2090 printed_prop
= true;
2093 write_uuid_prop_line(ctx
, "UUID", uuid
);
2097 /* Write environment */
2098 env_count
= bt_trace_get_environment_entry_count(trace
);
2099 if (env_count
> 0) {
2100 if (!printed_prop
) {
2101 g_string_append(ctx
->str
, ":\n");
2102 printed_prop
= true;
2106 write_prop_name(ctx
, "Environment");
2107 g_string_append(ctx
->str
, " (");
2108 write_uint_prop_value(ctx
, env_count
);
2109 g_string_append_printf(ctx
->str
, " entr%s):",
2110 env_count
== 1 ? "y" : "ies");
2114 for (i
= 0; i
< env_count
; i
++) {
2116 const bt_value
*value
;
2118 bt_trace_borrow_environment_entry_by_index_const(
2119 trace
, i
, &name
, &value
);
2120 g_ptr_array_add(env_names
, (gpointer
) name
);
2123 g_ptr_array_sort(env_names
, (GCompareFunc
) compare_strings
);
2125 for (i
= 0; i
< env_names
->len
; i
++) {
2126 const char *name
= env_names
->pdata
[i
];
2127 const bt_value
*value
=
2128 bt_trace_borrow_environment_entry_value_by_name_const(
2131 BT_ASSERT_DBG(value
);
2132 write_compound_member_name(ctx
, name
);
2135 if (bt_value_get_type(value
) ==
2136 BT_VALUE_TYPE_SIGNED_INTEGER
) {
2137 write_int_prop_value(ctx
,
2138 bt_value_integer_signed_get(value
));
2139 } else if (bt_value_get_type(value
) ==
2140 BT_VALUE_TYPE_STRING
) {
2141 write_str_prop_value(ctx
,
2142 bt_value_string_get(value
));
2153 for (i
= 0; i
< bt_trace_get_stream_count(trace
); i
++) {
2154 g_ptr_array_add(streams
,
2155 (gpointer
) bt_trace_borrow_stream_by_index_const(
2159 g_ptr_array_sort(streams
, (GCompareFunc
) compare_streams
);
2161 if (streams
->len
> 0 && !printed_prop
) {
2162 g_string_append(ctx
->str
, ":\n");
2163 printed_prop
= true;
2166 for (i
= 0; i
< streams
->len
; i
++) {
2167 const bt_stream
*stream
= streams
->pdata
[i
];
2170 write_obj_type_name(ctx
, "Stream");
2171 g_string_append(ctx
->str
, " (ID ");
2172 write_uint_prop_value(ctx
, bt_stream_get_id(stream
));
2173 g_string_append(ctx
->str
, ", Class ID ");
2174 write_uint_prop_value(ctx
, bt_stream_class_get_id(
2175 bt_stream_borrow_class_const(stream
)));
2176 g_string_append(ctx
->str
, ")");
2182 if (!printed_prop
) {
2186 g_ptr_array_free(streams
, TRUE
);
2187 g_ptr_array_free(env_names
, TRUE
);
2191 int write_stream_beginning_message(struct details_write_ctx
*ctx
,
2192 const bt_message
*msg
)
2195 const bt_stream
*stream
=
2196 bt_message_stream_beginning_borrow_stream_const(msg
);
2197 const bt_trace
*trace
= bt_stream_borrow_trace_const(stream
);
2198 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2199 const bt_clock_class
*cc
= bt_stream_class_borrow_default_clock_class_const(sc
);
2200 const bt_trace_class
*tc
= bt_stream_class_borrow_trace_class_const(sc
);
2203 ret
= try_write_meta(ctx
, tc
, sc
, NULL
);
2208 if (!ctx
->details_comp
->cfg
.with_data
) {
2212 if (ctx
->str
->len
> 0) {
2214 * Output buffer contains metadata: separate blocks with
2222 const bt_clock_snapshot
*cs
;
2223 bt_message_stream_clock_snapshot_state cs_state
=
2224 bt_message_stream_beginning_borrow_default_clock_snapshot_const(msg
, &cs
);
2226 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2227 write_time(ctx
, cs
);
2229 write_time_str(ctx
, "Unknown");
2233 /* Write follow tag for message */
2234 ret
= write_message_follow_tag(ctx
, stream
);
2239 /* Write stream properties */
2240 write_obj_type_name(ctx
, "Stream beginning");
2242 if (ctx
->details_comp
->cfg
.compact
) {
2247 g_string_append(ctx
->str
, ":\n");
2250 if (ctx
->details_comp
->cfg
.with_stream_name
) {
2251 name
= bt_stream_get_name(stream
);
2253 write_str_prop_line(ctx
, "Name", name
);
2257 if (ctx
->details_comp
->cfg
.with_stream_class_name
) {
2258 name
= bt_stream_class_get_name(sc
);
2260 write_str_prop_line(ctx
, "Class name", name
);
2264 write_trace(ctx
, trace
);
2272 int write_stream_end_message(struct details_write_ctx
*ctx
,
2273 const bt_message
*msg
)
2276 const bt_stream
*stream
=
2277 bt_message_stream_end_borrow_stream_const(msg
);
2278 const bt_stream_class
*sc
=
2279 bt_stream_borrow_class_const(stream
);
2280 const bt_clock_class
*cc
=
2281 bt_stream_class_borrow_default_clock_class_const(sc
);
2283 if (!ctx
->details_comp
->cfg
.with_data
) {
2289 const bt_clock_snapshot
*cs
;
2290 bt_message_stream_clock_snapshot_state cs_state
=
2291 bt_message_stream_end_borrow_default_clock_snapshot_const(msg
, &cs
);
2293 if (cs_state
== BT_MESSAGE_STREAM_CLOCK_SNAPSHOT_STATE_KNOWN
) {
2294 write_time(ctx
, cs
);
2296 write_time_str(ctx
, "Unknown");
2300 /* Write follow tag for message */
2301 ret
= write_message_follow_tag(ctx
, stream
);
2306 /* Write stream properties */
2307 write_obj_type_name(ctx
, "Stream end\n");
2314 int write_packet_beginning_message(struct details_write_ctx
*ctx
,
2315 const bt_message
*msg
)
2318 const bt_packet
*packet
=
2319 bt_message_packet_beginning_borrow_packet_const(msg
);
2320 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2321 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2322 const bt_field
*field
;
2324 if (!ctx
->details_comp
->cfg
.with_data
) {
2329 if (bt_stream_class_packets_have_beginning_default_clock_snapshot(sc
)) {
2331 bt_message_packet_beginning_borrow_default_clock_snapshot_const(
2335 /* Write follow tag for message */
2336 ret
= write_message_follow_tag(ctx
, stream
);
2341 write_obj_type_name(ctx
, "Packet beginning");
2343 if (ctx
->details_comp
->cfg
.compact
) {
2349 field
= bt_packet_borrow_context_field_const(packet
);
2351 g_string_append(ctx
->str
, ":\n");
2353 write_root_field(ctx
, "Context", field
);
2364 int write_discarded_items_message(struct details_write_ctx
*ctx
,
2365 const char *name
, const bt_stream
*stream
,
2366 const bt_clock_snapshot
*beginning_cs
,
2367 const bt_clock_snapshot
*end_cs
, uint64_t count
)
2373 write_time(ctx
, beginning_cs
);
2374 BT_ASSERT_DBG(end_cs
);
2375 write_time(ctx
, end_cs
);
2378 /* Write follow tag for message */
2379 ret
= write_message_follow_tag(ctx
, stream
);
2384 write_obj_type_name(ctx
, "Discarded ");
2385 write_obj_type_name(ctx
, name
);
2388 if (count
== UINT64_C(-1)) {
2393 g_string_append(ctx
->str
, " (");
2394 write_uint_prop_value(ctx
, count
);
2395 g_string_append_printf(ctx
->str
, " %s)\n", name
);
2402 int write_discarded_events_message(struct details_write_ctx
*ctx
,
2403 const bt_message
*msg
)
2406 const bt_stream
*stream
= bt_message_discarded_events_borrow_stream_const(
2408 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2409 const bt_clock_snapshot
*beginning_cs
= NULL
;
2410 const bt_clock_snapshot
*end_cs
= NULL
;
2413 if (!ctx
->details_comp
->cfg
.with_data
) {
2417 if (bt_stream_class_discarded_events_have_default_clock_snapshots(sc
)) {
2419 bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
2422 bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
2426 if (bt_message_discarded_events_get_count(msg
, &count
) !=
2427 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2428 count
= UINT64_C(-1);
2431 ret
= write_discarded_items_message(ctx
, "events", stream
,
2432 beginning_cs
, end_cs
, count
);
2439 int write_discarded_packets_message(struct details_write_ctx
*ctx
,
2440 const bt_message
*msg
)
2443 const bt_stream
*stream
= bt_message_discarded_packets_borrow_stream_const(
2445 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2446 const bt_clock_snapshot
*beginning_cs
= NULL
;
2447 const bt_clock_snapshot
*end_cs
= NULL
;
2450 if (!ctx
->details_comp
->cfg
.with_data
) {
2454 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(sc
)) {
2456 bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
2459 bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
2463 if (bt_message_discarded_packets_get_count(msg
, &count
) !=
2464 BT_PROPERTY_AVAILABILITY_AVAILABLE
) {
2465 count
= UINT64_C(-1);
2468 ret
= write_discarded_items_message(ctx
, "packets", stream
,
2469 beginning_cs
, end_cs
, count
);
2476 int write_packet_end_message(struct details_write_ctx
*ctx
,
2477 const bt_message
*msg
)
2480 const bt_packet
*packet
=
2481 bt_message_packet_end_borrow_packet_const(msg
);
2482 const bt_stream
*stream
= bt_packet_borrow_stream_const(packet
);
2483 const bt_stream_class
*sc
= bt_stream_borrow_class_const(stream
);
2485 if (!ctx
->details_comp
->cfg
.with_data
) {
2490 if (bt_stream_class_packets_have_end_default_clock_snapshot(sc
)) {
2492 bt_message_packet_end_borrow_default_clock_snapshot_const(
2496 /* Write follow tag for message */
2497 ret
= write_message_follow_tag(ctx
, stream
);
2502 write_obj_type_name(ctx
, "Packet end");
2510 int write_message_iterator_inactivity_message(struct details_write_ctx
*ctx
,
2511 const bt_message
*msg
)
2514 const bt_clock_snapshot
*cs
=
2515 bt_message_message_iterator_inactivity_borrow_clock_snapshot_const(
2519 write_time(ctx
, cs
);
2520 write_obj_type_name(ctx
, "Message iterator inactivity");
2522 if (ctx
->details_comp
->cfg
.compact
) {
2527 /* Write clock class properties */
2528 g_string_append(ctx
->str
, ":\n");
2531 write_prop_name(ctx
, "Clock class");
2532 g_string_append_c(ctx
->str
, ':');
2535 write_clock_class_prop_lines(ctx
,
2536 bt_clock_snapshot_borrow_clock_class_const(cs
));
2544 int details_write_message(struct details_comp
*details_comp
,
2545 const bt_message
*msg
)
2548 struct details_write_ctx ctx
= {
2549 .details_comp
= details_comp
,
2550 .str
= details_comp
->str
,
2554 /* Reset output buffer */
2555 g_string_assign(details_comp
->str
, "");
2557 switch (bt_message_get_type(msg
)) {
2558 case BT_MESSAGE_TYPE_EVENT
:
2559 ret
= write_event_message(&ctx
, msg
);
2561 case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY
:
2562 ret
= write_message_iterator_inactivity_message(&ctx
, msg
);
2564 case BT_MESSAGE_TYPE_STREAM_BEGINNING
:
2565 ret
= write_stream_beginning_message(&ctx
, msg
);
2567 case BT_MESSAGE_TYPE_STREAM_END
:
2568 ret
= write_stream_end_message(&ctx
, msg
);
2570 case BT_MESSAGE_TYPE_PACKET_BEGINNING
:
2571 ret
= write_packet_beginning_message(&ctx
, msg
);
2573 case BT_MESSAGE_TYPE_PACKET_END
:
2574 ret
= write_packet_end_message(&ctx
, msg
);
2576 case BT_MESSAGE_TYPE_DISCARDED_EVENTS
:
2577 ret
= write_discarded_events_message(&ctx
, msg
);
2579 case BT_MESSAGE_TYPE_DISCARDED_PACKETS
:
2580 ret
= write_discarded_packets_message(&ctx
, msg
);
2587 * If this component printed at least one character so far, and
2588 * we're not in compact mode, and there's something in the
2589 * output buffer for this message, then prepend a newline to the
2590 * output buffer to visually separate message blocks.
2592 if (details_comp
->printed_something
&& !details_comp
->cfg
.compact
&&
2593 details_comp
->str
->len
> 0) {
2594 /* TODO: Optimize this */
2595 g_string_prepend_c(details_comp
->str
, '\n');