X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fust-field-convert.cpp;h=b51ba7bfc2c7e55ea4749b0e2d41807a7a33deed;hb=f9a4135756da1947c2aa00e5b1e3c8e572d02107;hp=81fa7bc7dec6952008fc6f7609c187f6e5797f59;hpb=e7360180aa8c4d8f5bfec86a6a020bbc616ff2c0;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/ust-field-convert.cpp b/src/bin/lttng-sessiond/ust-field-convert.cpp index 81fa7bc7d..b51ba7bfc 100644 --- a/src/bin/lttng-sessiond/ust-field-convert.cpp +++ b/src/bin/lttng-sessiond/ust-field-convert.cpp @@ -7,14 +7,25 @@ #include "ust-field-convert.hpp" +#include #include #include +#include namespace lst = lttng::sessiond::trace; namespace lsu = lttng::sessiond::ust; -namespace { +/* + * fmtlib helper that must be under the same namespace as lttng_ust_ctl_abstract_types + * (global). + */ +static int format_as(lttng_ust_ctl_abstract_types type) +{ + return fmt::underlying(type); +} + +namespace { /* * Type enclosing the session information that may be required during the decoding * of the lttng_ust_ctl_field array provided by applications on registration of @@ -23,12 +34,13 @@ namespace { class session_attributes { public: using registry_enum_getter_fn = - std::function; + std::function; session_attributes(registry_enum_getter_fn reg_enum_getter, - lst::byte_order native_trace_byte_order) : - get_registry_enum{reg_enum_getter}, _native_trace_byte_order{native_trace_byte_order} + lst::byte_order native_trace_byte_order) : + get_registry_enum{ std::move(reg_enum_getter) }, + _native_trace_byte_order{ native_trace_byte_order } { } @@ -37,36 +49,50 @@ public: }; /* Used to publish fields on which a field being decoded has an implicit dependency. */ -using publish_field_fn = std::function; - -lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field, - publish_field_fn publish_field); +using publish_field_fn = std::function; + +/* Look-up field from a field location. */ +using lookup_field_fn = std::function; + +lst::type::cuptr +create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const publish_field_fn& publish_field, + const lookup_field_fn& lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks); void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field, - publish_field_fn publish_field); + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const publish_field_fn& publish_field, + const lookup_field_fn& lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks); template -enum lst::null_terminated_string_type::encoding ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding) +enum lst::null_terminated_string_type::encoding +ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding) { - static const std::unordered_map - encoding_conversion_map = { - {(UstCtlEncodingType) lttng_ust_ctl_encode_ASCII, - lst::null_terminated_string_type::encoding::ASCII}, - {(UstCtlEncodingType) lttng_ust_ctl_encode_UTF8, - lst::null_terminated_string_type::encoding::UTF8}, - }; + static const std::unordered_map + encoding_conversion_map = { + { (UstCtlEncodingType) lttng_ust_ctl_encode_ASCII, + lst::null_terminated_string_type::encoding::ASCII }, + { (UstCtlEncodingType) lttng_ust_ctl_encode_UTF8, + lst::null_terminated_string_type::encoding::UTF8 }, + }; const auto encoding_it = encoding_conversion_map.find(encoding); if (encoding_it == encoding_conversion_map.end()) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field", - encoding)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field", + encoding)); } return encoding_it->second; @@ -76,103 +102,111 @@ template enum lst::integer_type::base ust_ctl_base_to_integer_field_base(UstCtlBaseType base) { static const std::unordered_map - base_conversion_map = {{2, lst::integer_type::base::BINARY}, - {8, lst::integer_type::base::OCTAL}, - {10, lst::integer_type::base::DECIMAL}, - {16, lst::integer_type::base::HEXADECIMAL}}; + base_conversion_map = { { 2, lst::integer_type::base::BINARY }, + { 8, lst::integer_type::base::OCTAL }, + { 10, lst::integer_type::base::DECIMAL }, + { 16, lst::integer_type::base::HEXADECIMAL } }; const auto base_it = base_conversion_map.find(base); if (base_it == base_conversion_map.end()) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unknown integer base value `{}` encountered when decoding integer field", - base)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unknown integer base value `{}` encountered when decoding integer field", + base)); } return base_it->second; } -lst::type::cuptr create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field) +lst::type::cuptr +create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + lsu::ctl_field_quirks quirks __attribute__((unused))) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } const auto base = ust_ctl_base_to_integer_field_base(current->type.u.integer.base); const auto signedness = current->type.u.integer.signedness ? - lst::integer_type::signedness::SIGNED : - lst::integer_type::signedness::UNSIGNED; + lst::integer_type::signedness::SIGNED : + lst::integer_type::signedness::UNSIGNED; const auto byte_order = current->type.u.integer.reverse_byte_order ? - lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) : - session_attributes._native_trace_byte_order; + lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) : + session_attributes._native_trace_byte_order; *next_ust_ctl_field = current + 1; return lttng::make_unique(current->type.u.integer.alignment, - byte_order, current->type.u.integer.size, signedness, base); + byte_order, + current->type.u.integer.size, + signedness, + base); } -lst::type::cuptr create_floating_point_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field) +lst::type::cuptr +create_floating_point_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + lsu::ctl_field_quirks quirks __attribute__((unused))) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } *next_ust_ctl_field = current + 1; const auto byte_order = current->type.u._float.reverse_byte_order ? - lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) : - session_attributes._native_trace_byte_order; + lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) : + session_attributes._native_trace_byte_order; try { return lttng::make_unique( - current->type.u._float.alignment, byte_order, - current->type.u._float.exp_dig, current->type.u._float.mant_dig); + current->type.u._float.alignment, + byte_order, + current->type.u._float.exp_dig, + current->type.u._float.mant_dig); } catch (lttng::invalid_argument_error& ex) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format("Invalid floating point attribute in {}: {}", - typeid(*current), ex.what())); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Invalid floating point attribute in {}: {}", typeid(*current), ex.what())); } } -lst::type::cuptr create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field) +lst::type::cuptr +create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + lsu::ctl_field_quirks quirks __attribute__((unused))) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } uint64_t enumeration_id; const auto& enum_uctl_field = *current; const char *enumeration_name; const auto *enum_container_uctl_type = - ¤t->type.u.legacy.basic.enumeration.container_type; + ¤t->type.u.legacy.basic.enumeration.container_type; if (enum_uctl_field.type.atype == lttng_ust_ctl_atype_enum_nestable) { /* Nestable enumeration fields are followed by their container type. */ ++current; if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Array of {} is too short to contain nestable enumeration's container", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Array of {} is too short to contain nestable enumeration's container", + typeid(*current))); } if (current->type.atype != lttng_ust_ctl_atype_integer) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Invalid type of nestable enum container: type id = {}", - current->type.atype)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Invalid type of nestable enum container: type id = {}", + current->type.atype)); } enum_container_uctl_type = ¤t->type.u.integer; @@ -187,81 +221,88 @@ lst::type::cuptr create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl const auto base = ust_ctl_base_to_integer_field_base(enum_container_uctl_type->base); const auto byte_order = enum_container_uctl_type->reverse_byte_order ? - lst::integer_type::reverse_byte_order( - session_attributes._native_trace_byte_order) : - session_attributes._native_trace_byte_order; + lst::integer_type::reverse_byte_order(session_attributes._native_trace_byte_order) : + session_attributes._native_trace_byte_order; + const auto signedness = enum_container_uctl_type->signedness ? + lst::integer_type::signedness::SIGNED : + lst::integer_type::signedness::UNSIGNED; - if (enum_container_uctl_type->signedness) { + if (signedness == lst::integer_type::signedness::SIGNED) { const auto& enum_registry = static_cast( - *session_attributes.get_registry_enum( - enumeration_name, enumeration_id)); + *session_attributes.get_registry_enum(enumeration_name, enumeration_id)); return lttng::make_unique( - enum_container_uctl_type->alignment, byte_order, - enum_container_uctl_type->size, base, - enum_registry._mappings); + enum_container_uctl_type->alignment, + byte_order, + enum_container_uctl_type->size, + base, + enum_registry._mappings); } else { const auto& enum_registry = static_cast( - *session_attributes.get_registry_enum( - enumeration_name, enumeration_id)); + *session_attributes.get_registry_enum(enumeration_name, enumeration_id)); return lttng::make_unique( - enum_container_uctl_type->alignment, byte_order, - enum_container_uctl_type->size, base, - enum_registry._mappings); + enum_container_uctl_type->alignment, + byte_order, + enum_container_uctl_type->size, + base, + enum_registry._mappings); } } -lst::type::cuptr create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes __attribute__((unused)), - const lttng_ust_ctl_field **next_ust_ctl_field) +lst::type::cuptr +create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes + __attribute__((unused)), + const lttng_ust_ctl_field **next_ust_ctl_field, + lsu::ctl_field_quirks quirks __attribute__((unused))) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } const auto& string_uctl_field = *current; *next_ust_ctl_field = current + 1; - const auto encoding = ust_ctl_encoding_to_string_field_encoding( - string_uctl_field.type.u.string.encoding); + const auto encoding = + ust_ctl_encoding_to_string_field_encoding(string_uctl_field.type.u.string.encoding); return lttng::make_unique(1, encoding); } -lst::type::cuptr create_integer_type_from_ust_ctl_basic_type( - const lttng_ust_ctl_basic_type& type, const session_attributes& session_attributes) +lst::type::cuptr +create_integer_type_from_ust_ctl_basic_type(const lttng_ust_ctl_basic_type& type, + const session_attributes& session_attributes) { /* Checked by caller. */ LTTNG_ASSERT(type.atype == lttng_ust_ctl_atype_integer); const auto byte_order = type.u.basic.integer.reverse_byte_order ? - lst::integer_type::reverse_byte_order( - session_attributes._native_trace_byte_order) : - session_attributes._native_trace_byte_order; + lst::integer_type::reverse_byte_order(session_attributes._native_trace_byte_order) : + session_attributes._native_trace_byte_order; const auto signedness = type.u.basic.integer.signedness ? - lst::integer_type::signedness::SIGNED : - lst::integer_type::signedness::UNSIGNED; + lst::integer_type::signedness::SIGNED : + lst::integer_type::signedness::UNSIGNED; const auto base = ust_ctl_base_to_integer_field_base(type.u.basic.integer.base); const auto size = type.u.basic.integer.size; const auto alignment = type.u.basic.integer.alignment; return lttng::make_unique( - alignment, byte_order, size, signedness, base); + alignment, byte_order, size, signedness, base); } -lst::type::cuptr create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field) +lst::type::cuptr +create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + lsu::ctl_field_quirks quirks __attribute__((unused))) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } const auto& array_uctl_field = *current; @@ -274,51 +315,56 @@ lst::type::cuptr create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field const auto& element_uctl_type = array_uctl_field.type.u.legacy.array.elem_type; if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})", - element_uctl_type.atype, lttng_ust_ctl_atype_integer)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})", + element_uctl_type.atype, + lttng_ust_ctl_atype_integer)); } - element_type = create_integer_type_from_ust_ctl_basic_type( - element_uctl_type, session_attributes); + element_type = + create_integer_type_from_ust_ctl_basic_type(element_uctl_type, session_attributes); if (element_uctl_type.atype == lttng_ust_ctl_atype_integer && - element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) { + element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) { /* Element represents a text character. */ element_encoding = ust_ctl_encoding_to_string_field_encoding( - element_uctl_type.u.basic.integer.encoding); + element_uctl_type.u.basic.integer.encoding); } *next_ust_ctl_field = current + 1; if (element_encoding) { const auto integer_element_size = - static_cast(*element_type).size; + static_cast(*element_type).size; if (integer_element_size != 8) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}", - integer_element_size)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}", + integer_element_size)); } /* Array is a static-length string. */ return lttng::make_unique( - array_alignment, *element_encoding, array_length); + array_alignment, *element_encoding, array_length); } return lttng::make_unique( - array_alignment, std::move(element_type), array_length); + array_alignment, std::move(element_type), array_length); } -lst::type::cuptr create_array_nestable_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field, - publish_field_fn publish_field) +lst::type::cuptr create_array_nestable_type_from_ust_ctl_fields( + const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const publish_field_fn& publish_field, + const lookup_field_fn& lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } const auto& array_uctl_field = *current; @@ -333,48 +379,58 @@ lst::type::cuptr create_array_nestable_type_from_ust_ctl_fields(const lttng_ust_ const auto& element_uctl_field = *(current + 1); /* next_ust_ctl_field is updated as needed. */ - element_type = create_type_from_ust_ctl_fields(&element_uctl_field, end, session_attributes, - next_ust_ctl_field, publish_field); + element_type = create_type_from_ust_ctl_fields(&element_uctl_field, + end, + session_attributes, + next_ust_ctl_field, + publish_field, + lookup_field, + lookup_root, + current_field_location_elements, + quirks); if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer && - element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) { + element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) { /* Element represents a text character. */ element_encoding = ust_ctl_encoding_to_string_field_encoding( - element_uctl_field.type.u.integer.encoding); + element_uctl_field.type.u.integer.encoding); } if (element_encoding) { const auto integer_element_size = - static_cast(*element_type).size; + static_cast(*element_type).size; if (integer_element_size != 8) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unexpected array element type: integer has encoding but size is not 8: size = {}", - integer_element_size)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unexpected array element type: integer has encoding but size is not 8: size = {}", + integer_element_size)); } /* Array is a static-length string. */ return lttng::make_unique( - array_alignment, *element_encoding, array_length); + array_alignment, *element_encoding, array_length); } return lttng::make_unique( - array_alignment, std::move(element_type), array_length); + array_alignment, std::move(element_type), array_length); } /* * For legacy sequence types, LTTng-UST expresses both the sequence and sequence * length as part of the same lttng_ust_ctl_field entry. */ -lst::type::cuptr create_sequence_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field, - publish_field_fn publish_field) +lst::type::cuptr create_sequence_type_from_ust_ctl_fields( + const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const publish_field_fn& publish_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks __attribute__((unused))) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } const auto& sequence_uctl_field = *current; @@ -383,66 +439,79 @@ lst::type::cuptr create_sequence_type_from_ust_ctl_fields(const lttng_ust_ctl_fi const auto sequence_alignment = 0U; if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})", - element_uctl_type.atype, lttng_ust_ctl_atype_integer)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})", + element_uctl_type.atype, + lttng_ust_ctl_atype_integer)); } if (length_uctl_type.atype != lttng_ust_ctl_atype_integer) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})", - length_uctl_type.atype, lttng_ust_ctl_atype_integer)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})", + length_uctl_type.atype, + lttng_ust_ctl_atype_integer)); } nonstd::optional element_encoding; if (element_uctl_type.atype == lttng_ust_ctl_atype_integer && - element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) { + element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) { /* Element represents a text character. */ element_encoding = ust_ctl_encoding_to_string_field_encoding( - element_uctl_type.u.basic.integer.encoding); + element_uctl_type.u.basic.integer.encoding); } - const auto length_field_name = fmt::format("_{}_length", sequence_uctl_field.name); - auto element_type = create_integer_type_from_ust_ctl_basic_type( - element_uctl_type, session_attributes); - auto length_type = create_integer_type_from_ust_ctl_basic_type( - length_uctl_type, session_attributes); + auto length_field_name = lttng::format("_{}_length", sequence_uctl_field.name); + auto element_type = + create_integer_type_from_ust_ctl_basic_type(element_uctl_type, session_attributes); + auto length_type = + create_integer_type_from_ust_ctl_basic_type(length_uctl_type, session_attributes); + + lst::field_location::elements length_field_location_elements = + current_field_location_elements; + length_field_location_elements.emplace_back(length_field_name); + + lst::field_location length_field_location{ lookup_root, + std::move(length_field_location_elements) }; /* Publish an implicit length field _before_ the sequence field. */ - publish_field(lttng::make_unique(length_field_name, std::move(length_type))); + publish_field(lttng::make_unique(std::move(length_field_name), + std::move(length_type))); *next_ust_ctl_field = current + 1; if (element_encoding) { const auto integer_element_size = - static_cast(*element_type).size; + static_cast(*element_type).size; if (integer_element_size != 8) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}", - integer_element_size)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}", + integer_element_size)); } /* Sequence is a dynamic-length string. */ - return lttng::make_unique(sequence_alignment, - *element_encoding, std::move(length_field_name)); + return lttng::make_unique( + sequence_alignment, *element_encoding, std::move(length_field_location)); } return lttng::make_unique( - sequence_alignment, std::move(element_type), std::move(length_field_name)); + sequence_alignment, std::move(element_type), std::move(length_field_location)); } lst::type::cuptr create_sequence_nestable_type_from_ust_ctl_fields( - const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field, - publish_field_fn publish_field) + const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const publish_field_fn& publish_field, + const lookup_field_fn& lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } const auto& sequence_uctl_field = *current; @@ -454,50 +523,75 @@ lst::type::cuptr create_sequence_nestable_type_from_ust_ctl_fields( nonstd::optional element_encoding; if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer && - element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) { + element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) { /* Element represents a text character. */ element_encoding = ust_ctl_encoding_to_string_field_encoding( - element_uctl_field.type.u.integer.encoding); + element_uctl_field.type.u.integer.encoding); } /* next_ust_ctl_field is updated as needed. */ - auto element_type = create_type_from_ust_ctl_fields(&element_uctl_field, end, - session_attributes, next_ust_ctl_field, publish_field); + auto element_type = create_type_from_ust_ctl_fields(&element_uctl_field, + end, + session_attributes, + next_ust_ctl_field, + publish_field, + lookup_field, + lookup_root, + current_field_location_elements, + quirks); if (lttng_strnlen(sequence_uctl_field.type.u.sequence_nestable.length_name, - sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) == - sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) { + sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) == + sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) { LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated"); } + lst::field_location::elements length_field_location_elements = + current_field_location_elements; + length_field_location_elements.emplace_back(length_field_name); + + lst::field_location length_field_location{ lookup_root, + std::move(length_field_location_elements) }; + + /* Validate existence of length field (throws if not found). */ + const auto& length_field = lookup_field(length_field_location); + const auto *integer_selector_field = + dynamic_cast(&length_field.get_type()); + if (!integer_selector_field) { + LTTNG_THROW_PROTOCOL_ERROR( + "Invalid selector field type referenced from sequence: expected integer or enumeration"); + } + if (element_encoding) { const auto integer_element_size = - static_cast(*element_type).size; + static_cast(*element_type).size; if (integer_element_size != 8) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unexpected array element type: integer has encoding but size is not 8: size = {}", - integer_element_size)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Unexpected array element type: integer has encoding but size is not 8: size = {}", + integer_element_size)); } /* Sqeuence is a dynamic-length string. */ - return lttng::make_unique(sequence_alignment, - *element_encoding, std::move(length_field_name)); + return lttng::make_unique( + sequence_alignment, *element_encoding, std::move(length_field_location)); } return lttng::make_unique( - sequence_alignment, std::move(element_type), std::move(length_field_name)); + sequence_alignment, std::move(element_type), std::move(length_field_location)); } -lst::type::cuptr create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes __attribute__((unused)), - const lttng_ust_ctl_field **next_ust_ctl_field) +lst::type::cuptr +create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes + __attribute__((unused)), + const lttng_ust_ctl_field **next_ust_ctl_field, + lsu::ctl_field_quirks quirks __attribute__((unused))) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } uint32_t field_count; @@ -513,24 +607,104 @@ lst::type::cuptr create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_ } if (field_count != 0) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Only empty structures are supported by LTTng-UST: nr_fields = {}", - field_count)); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Only empty structures are supported by LTTng-UST: nr_fields = {}", + field_count)); } *next_ust_ctl_field = current + 1; return lttng::make_unique(alignment, lst::structure_type::fields()); } -lst::type::cuptr create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field) +template +typename lst::variant_type::choices +create_typed_variant_choices(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + lookup_field_fn lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + unsigned int choice_count, + const lst::field& selector_field, + lsu::ctl_field_quirks quirks) +{ + typename lst::variant_type::choices choices; + const auto& typed_enumeration = + static_cast&>( + selector_field.get_type()); + + for (unsigned int i = 0; i < choice_count; i++) { + create_field_from_ust_ctl_fields( + current, + end, + session_attributes, + next_ust_ctl_field, + [&choices, &typed_enumeration, &selector_field, quirks]( + lst::field::uptr field) { + /* + * Find the enumeration mapping that matches the + * field's name. + */ + const auto mapping_it = std::find_if( + typed_enumeration.mappings_->begin(), + typed_enumeration.mappings_->end(), + [&field, + quirks](const typename std::remove_reference< + decltype(typed_enumeration)>::type::mapping& + mapping) { + if (static_cast( + quirks & + lsu::ctl_field_quirks:: + UNDERSCORE_PREFIXED_VARIANT_TAG_MAPPINGS)) { + /* + * Check if they match with + * a prepended underscore + * and, if not, perform the + * regular check. + */ + if ((std::string("_") + field->name) == + mapping.name) { + return true; + } + } + + return mapping.name == field->name; + }); + + if (mapping_it == typed_enumeration.mappings_->end()) { + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "Invalid variant choice: `{}` does not match any mapping in `{}` enumeration", + field->name, + selector_field.name)); + } + + choices.emplace_back(*mapping_it, field->move_type()); + }, + lookup_field, + lookup_root, + current_field_location_elements, + quirks); + + current = *next_ust_ctl_field; + } + + return choices; +} + +lst::type::cuptr create_variant_field_from_ust_ctl_fields( + const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const lookup_field_fn& lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks) { if (current >= end) { - LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("End of {} array reached unexpectedly during decoding", - typeid(*current))); + LTTNG_THROW_PROTOCOL_ERROR(lttng::format( + "End of {} array reached unexpectedly during decoding", typeid(*current))); } const auto& variant_uctl_field = *current; @@ -550,84 +724,202 @@ lst::type::cuptr create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_fi tag_name = variant_uctl_field.type.u.variant_nestable.tag_name; } - /* Choices follow. next_ust_ctl_field is updated as needed. */ - lst::variant_type::choices choices; - for (unsigned int i = 0; i < choice_count; i++) { - create_field_from_ust_ctl_fields(current, end, session_attributes, - next_ust_ctl_field, [&choices](lst::field::cuptr field) { - choices.emplace_back(std::move(field)); - }); + lst::field_location::elements selector_field_location_elements = + current_field_location_elements; + selector_field_location_elements.emplace_back(tag_name); - current = *next_ust_ctl_field; + lst::field_location selector_field_location{ lookup_root, + std::move(selector_field_location_elements) }; + + /* Validate existence of selector field (throws if not found). */ + const auto& selector_field = lookup_field(selector_field_location); + const auto *enumeration_selector_type = + dynamic_cast(&selector_field.get_type()); + if (!enumeration_selector_type) { + LTTNG_THROW_PROTOCOL_ERROR( + "Invalid selector field type referenced from variant: expected enumeration"); } - return lttng::make_unique(alignment, tag_name, std::move(choices)); + const bool selector_is_signed = enumeration_selector_type->signedness_ == + lst::integer_type::signedness::SIGNED; + + /* Choices follow. next_ust_ctl_field is updated as needed. */ + if (selector_is_signed) { + lst::variant_type:: + choices choices = create_typed_variant_choices( + current, + end, + session_attributes, + next_ust_ctl_field, + lookup_field, + lookup_root, + current_field_location_elements, + choice_count, + selector_field, + quirks); + + return lttng::make_unique>( + alignment, std::move(selector_field_location), std::move(choices)); + } else { + lst::variant_type< + lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::choices + choices = create_typed_variant_choices( + current, + end, + session_attributes, + next_ust_ctl_field, + lookup_field, + lookup_root, + current_field_location_elements, + choice_count, + selector_field, + quirks); + + return lttng::make_unique>( + alignment, std::move(selector_field_location), std::move(choices)); + } } -lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field, - publish_field_fn publish_field) +lst::type::cuptr +create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const publish_field_fn& publish_field, + const lookup_field_fn& lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks) { switch (current->type.atype) { case lttng_ust_ctl_atype_integer: return create_integer_type_from_ust_ctl_fields( - current, end, session_attributes, next_ust_ctl_field); + current, end, session_attributes, next_ust_ctl_field, quirks); case lttng_ust_ctl_atype_enum: case lttng_ust_ctl_atype_enum_nestable: return create_enumeration_type_from_ust_ctl_fields( - current, end, session_attributes, next_ust_ctl_field); + current, end, session_attributes, next_ust_ctl_field, quirks); case lttng_ust_ctl_atype_float: return create_floating_point_type_from_ust_ctl_fields( - current, end, session_attributes, next_ust_ctl_field); + current, end, session_attributes, next_ust_ctl_field, quirks); case lttng_ust_ctl_atype_string: return create_string_type_from_ust_ctl_fields( - current, end, session_attributes, next_ust_ctl_field); + current, end, session_attributes, next_ust_ctl_field, quirks); case lttng_ust_ctl_atype_array: - return create_array_type_from_ust_ctl_fields(current, end, session_attributes, - next_ust_ctl_field); + return create_array_type_from_ust_ctl_fields( + current, end, session_attributes, next_ust_ctl_field, quirks); case lttng_ust_ctl_atype_array_nestable: - return create_array_nestable_type_from_ust_ctl_fields(current, end, - session_attributes, next_ust_ctl_field, publish_field); + return create_array_nestable_type_from_ust_ctl_fields( + current, + end, + session_attributes, + next_ust_ctl_field, + publish_field, + lookup_field, + lookup_root, + current_field_location_elements, + quirks); case lttng_ust_ctl_atype_sequence: - return create_sequence_type_from_ust_ctl_fields(current, end, session_attributes, - next_ust_ctl_field, publish_field); + return create_sequence_type_from_ust_ctl_fields(current, + end, + session_attributes, + next_ust_ctl_field, + publish_field, + lookup_root, + current_field_location_elements, + quirks); case lttng_ust_ctl_atype_sequence_nestable: - return create_sequence_nestable_type_from_ust_ctl_fields(current, end, - session_attributes, next_ust_ctl_field, publish_field); + return create_sequence_nestable_type_from_ust_ctl_fields( + current, + end, + session_attributes, + next_ust_ctl_field, + publish_field, + lookup_field, + lookup_root, + current_field_location_elements, + quirks); case lttng_ust_ctl_atype_struct: case lttng_ust_ctl_atype_struct_nestable: return create_structure_field_from_ust_ctl_fields( - current, end, session_attributes, next_ust_ctl_field); + current, end, session_attributes, next_ust_ctl_field, quirks); case lttng_ust_ctl_atype_variant: case lttng_ust_ctl_atype_variant_nestable: - return create_variant_field_from_ust_ctl_fields( - current, end, session_attributes, next_ust_ctl_field); + return create_variant_field_from_ust_ctl_fields(current, + end, + session_attributes, + next_ust_ctl_field, + lookup_field, + lookup_root, + current_field_location_elements, + quirks); default: - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Unknown {} value `{}` encountered while converting {} to {}", - typeid(current->type.atype), current->type.atype, typeid(*current), - typeid(lst::type::cuptr::element_type))); + LTTNG_THROW_PROTOCOL_ERROR( + lttng::format("Unknown {} value `{}` encountered while converting {} to {}", + typeid(current->type.atype), + current->type.atype, + typeid(*current), + typeid(lst::type::cuptr::element_type))); } } void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end, - const session_attributes& session_attributes, - const lttng_ust_ctl_field **next_ust_ctl_field, - publish_field_fn publish_field) + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + const publish_field_fn& publish_field, + const lookup_field_fn& lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + lsu::ctl_field_quirks quirks) { LTTNG_ASSERT(current < end); if (lttng_strnlen(current->name, sizeof(current->name)) == sizeof(current->name)) { LTTNG_THROW_PROTOCOL_ERROR( - fmt::format("Name of {} is not null-terminated", typeid(*current))); + lttng::format("Name of {} is not null-terminated", typeid(*current))); + } + + publish_field(lttng::make_unique( + current->name, + create_type_from_ust_ctl_fields(current, + end, + session_attributes, + next_ust_ctl_field, + publish_field, + lookup_field, + lookup_root, + current_field_location_elements, + quirks))); +} + +std::vector::iterator +lookup_field_in_vector(std::vector& fields, const lst::field_location& location) +{ + if (location.elements_.size() != 1) { + LTTNG_THROW_ERROR(lttng::format( + "Unexpected field location received during field look-up: location = {}", + location)); + } + + /* + * In the context of fields received from LTTng-UST, field + * look-up is extremely naive as the protocol can only + * express empty structures. It is safe to assume that + * location has a depth of 1 and directly refers to a field + * in the 'fields' vector. + */ + const auto field_it = + std::find_if(fields.begin(), fields.end(), [location](lst::field::cuptr& field) { + return field->name == location.elements_[0]; + }); + + if (field_it == fields.end()) { + LTTNG_THROW_PROTOCOL_ERROR( + lttng::format("Failed to look-up field: location = {}", location)); } - publish_field(lttng::make_unique(current->name, - create_type_from_ust_ctl_fields(current, end, session_attributes, - next_ust_ctl_field, publish_field))); + return field_it; } /* @@ -638,18 +930,23 @@ void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, * * Always returns a new field, throws on error. */ -std::vector create_fields_from_ust_ctl_fields( - const lsu::registry_session& session, - const lttng_ust_ctl_field *current, - const lttng_ust_ctl_field *end) +std::vector +create_fields_from_ust_ctl_fields(const lsu::registry_session& session, + const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + lst::field_location::root lookup_root, + lsu::ctl_field_quirks quirks) { std::vector fields; const auto trace_native_byte_order = session.abi.byte_order; const session_attributes session_attributes{ - [&session](const char *enum_name, uint64_t enum_id) { - return session.get_enumeration(enum_name, enum_id); - }, - trace_native_byte_order}; + [&session](const char *enum_name, uint64_t enum_id) { + return session.enumeration(enum_name, enum_id); + }, + trace_native_byte_order + }; + /* Location of field being created. */ + lst::field_location::elements current_field_location_elements; while (current < end) { auto *next_field = current; @@ -663,10 +960,24 @@ std::vector create_fields_from_ust_ctl_fields( * The lambda allows the factory functions to push as many fields as * needed depending on the decoded field's type. */ - create_field_from_ust_ctl_fields(current, end, session_attributes, &next_field, - [&fields](lst::field::cuptr field) { - fields.emplace_back(std::move(field)); - }); + create_field_from_ust_ctl_fields( + current, + end, + session_attributes, + &next_field, + [&fields](lst::field::cuptr field) { + /* Publishing a field simply adds it to the converted + * fields. */ + fields.emplace_back(std::move(field)); + }, + [&fields](const lst::field_location& location) + -> lookup_field_fn::result_type { + /* Resolve location to a previously-constructed field. */ + return **lookup_field_in_vector(fields, location); + }, + lookup_root, + current_field_location_elements, + quirks); current = next_field; } @@ -675,10 +986,13 @@ std::vector create_fields_from_ust_ctl_fields( } } /* namespace */ -std::vector lsu::create_trace_fields_from_ust_ctl_fields( - const lsu::registry_session& session, - const lttng_ust_ctl_field *fields, - std::size_t field_count) +std::vector +lsu::create_trace_fields_from_ust_ctl_fields(const lsu::registry_session& session, + const lttng_ust_ctl_field *fields, + std::size_t field_count, + lst::field_location::root lookup_root, + lsu::ctl_field_quirks quirks) { - return create_fields_from_ust_ctl_fields(session, fields, fields + field_count); + return create_fields_from_ust_ctl_fields( + session, fields, fields + field_count, lookup_root, quirks); }