sessiond: ust: conditionally enable the underscore prefix variant quirk
[lttng-tools.git] / src / bin / lttng-sessiond / field.hpp
index 23c67b04ce1ebe705172523624af6b3ff34dcf2d..2e3a67bf42f23f39a2b4242a1817096daff92778 100644 (file)
@@ -8,15 +8,17 @@
 #ifndef LTTNG_FIELD_H
 #define LTTNG_FIELD_H
 
-#include "trace-class.hpp"
+#include <common/format.hpp>
+#include <common/make-unique.hpp>
 
+#include <vendor/optional.hpp>
+
+#include <algorithm>
 #include <memory>
 #include <string>
 #include <type_traits>
 #include <vector>
 
-#include <vendor/optional.hpp>
-
 namespace lttng {
 namespace sessiond {
 namespace trace {
@@ -24,6 +26,31 @@ namespace trace {
 class field_visitor;
 class type_visitor;
 
+enum class byte_order {
+       BIG_ENDIAN_,
+       LITTLE_ENDIAN_,
+};
+
+class field_location {
+public:
+       enum class root {
+               PACKET_HEADER,
+               PACKET_CONTEXT,
+               EVENT_RECORD_HEADER,
+               EVENT_RECORD_COMMON_CONTEXT,
+               EVENT_RECORD_SPECIFIC_CONTEXT,
+               EVENT_RECORD_PAYLOAD,
+       };
+
+       using elements = std::vector<std::string>;
+
+       field_location(root lookup_root, elements elements);
+       bool operator==(const field_location& other) const noexcept;
+
+       const root root_;
+       const elements elements_;
+};
+
 /*
  * Field, and the various field types, represents fields as exposed by the
  * LTTng tracers. These classes do not attempt to describe the complete spectrum of the CTF
@@ -39,6 +66,10 @@ public:
        bool operator==(const type& other) const noexcept;
        bool operator!=(const type& other) const noexcept;
        virtual ~type();
+
+       /* Obtain an independent copy of `type`. */
+       virtual type::cuptr copy() const = 0;
+
        virtual void accept(type_visitor& visitor) const = 0;
 
        const unsigned int alignment;
@@ -52,14 +83,20 @@ private:
 
 class field {
 public:
+       using uptr = std::unique_ptr<field>;
        using cuptr = std::unique_ptr<const field>;
 
        field(std::string name, type::cuptr type);
        void accept(field_visitor& visitor) const;
        bool operator==(const field& other) const noexcept;
 
+       const type& get_type() const;
+       type::cuptr move_type() noexcept;
+
        const std::string name;
-       const type::cuptr _type;
+
+private:
+       type::cuptr _type;
 };
 
 class integer_type : public type {
@@ -76,18 +113,45 @@ public:
                HEXADECIMAL = 16,
        };
 
+       enum class role {
+               DEFAULT_CLOCK_TIMESTAMP,
+               /* Packet header field class specific roles. */
+               DATA_STREAM_CLASS_ID,
+               DATA_STREAM_ID,
+               PACKET_MAGIC_NUMBER,
+               /* Packet context field class specific roles. */
+               DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT,
+               PACKET_CONTENT_LENGTH,
+               PACKET_END_DEFAULT_CLOCK_TIMESTAMP,
+               PACKET_SEQUENCE_NUMBER,
+               PACKET_TOTAL_LENGTH,
+               /* Event record field class roles. */
+               EVENT_RECORD_CLASS_ID,
+       };
+
+       using roles = std::vector<role>;
+
        integer_type(unsigned int alignment,
                        byte_order byte_order,
                        unsigned int size,
                        signedness signedness,
-                       base base);
+                       base base,
+                       roles roles = {});
+
+       virtual type::cuptr copy() const override;
 
        virtual void accept(type_visitor& visitor) const override;
 
        const enum byte_order byte_order;
        const unsigned int size;
-       const signedness signedness;
-       const base base;
+       /*
+        * signedness and base are suffixed with '_' to work-around a bug in older
+        * GCCs (before 6) that do not recognize hidden/shadowed enumeration as valid
+        * nested-name-specifiers.
+        */
+       const signedness signedness_;
+       const base base_;
+       const roles roles_;
 
 protected:
        virtual bool _is_equal(const type& other) const noexcept override;
@@ -100,6 +164,8 @@ public:
                        unsigned int exponent_digits,
                        unsigned int mantissa_digits);
 
+       virtual type::cuptr copy() const override final;
+
        virtual void accept(type_visitor& visitor) const override final;
 
        const enum byte_order byte_order;
@@ -116,7 +182,8 @@ protected:
                        enum byte_order byte_order,
                        unsigned int size,
                        enum signedness signedness,
-                       enum base base);
+                       enum base base,
+                       integer_type::roles roles = {});
 
        virtual void accept(type_visitor& visitor) const = 0;
 };
@@ -147,14 +214,13 @@ class enumeration_mapping {
 public:
        using range_t = enumeration_mapping_range<MappingIntegerType>;
 
-       enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = delete;
+       enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = default;
        enumeration_mapping(const enumeration_mapping<MappingIntegerType>&& other) :
                name{std::move(other.name)}, range{other.range}
        {
        }
 
-       /* Mapping with an implicit value. */
-       enumeration_mapping(std::string in_name) : name{std::move(in_name)}
+       enumeration_mapping(std::string in_name, MappingIntegerType value) : name{std::move(in_name)}, range{value, value}
        {
        }
 
@@ -163,7 +229,12 @@ public:
        }
 
        const std::string name;
-       const nonstd::optional<range_t> range;
+       /*
+        * Only one range per mapping is supported for the moment as
+        * the tracers (and CTF 1.8) can't express multiple ranges per
+        * mapping, which is allowed by CTF 2.
+        */
+       const range_t range;
 };
 
 template <class MappingIntegerType>
@@ -174,7 +245,7 @@ bool operator==(const enumeration_mapping<MappingIntegerType>& lhs,
 }
 } /* namespace details */
 
-template <class MappingIntegerType>
+template <typename MappingIntegerType>
 class typed_enumeration_type : public enumeration_type {
 public:
        using mapping = details::enumeration_mapping<MappingIntegerType>;
@@ -187,21 +258,30 @@ public:
        typed_enumeration_type(unsigned int in_alignment,
                        enum byte_order in_byte_order,
                        unsigned int in_size,
-                       enum signedness in_signedness,
                        enum base in_base,
-                       const std::shared_ptr<const mappings>& in_mappings) :
+                       const std::shared_ptr<const mappings>& in_mappings,
+                       integer_type::roles in_roles = {}) :
                enumeration_type(in_alignment,
                                in_byte_order,
                                in_size,
-                               in_signedness,
-                               in_base),
-               _mappings{std::move(in_mappings)}
+                               std::is_signed<MappingIntegerType>::value ?
+                                               integer_type::signedness::SIGNED :
+                                                     integer_type::signedness::UNSIGNED,
+                               in_base,
+                               std::move(in_roles)),
+               mappings_{std::move(in_mappings)}
        {
        }
 
+       virtual type::cuptr copy() const override
+       {
+               return lttng::make_unique<typed_enumeration_type<MappingIntegerType>>(
+                               alignment, byte_order, size, base_, mappings_, roles_);
+       }
+
        virtual void accept(type_visitor& visitor) const override final;
 
-       const std::shared_ptr<const mappings> _mappings;
+       const std::shared_ptr<const mappings> mappings_;
 
 private:
        virtual bool _is_equal(const type& base_other) const noexcept override final
@@ -209,7 +289,7 @@ private:
                const auto& other = static_cast<const typed_enumeration_type<MappingIntegerType>&>(
                                base_other);
 
-               return integer_type::_is_equal(base_other) && *this->_mappings == *other._mappings;
+               return integer_type::_is_equal(base_other) && *this->mappings_ == *other.mappings_;
        }
 };
 
@@ -233,6 +313,8 @@ public:
                        type::cuptr element_type,
                        uint64_t in_length);
 
+       virtual type::cuptr copy() const override final;
+
        virtual void accept(type_visitor& visitor) const override final;
 
        const uint64_t length;
@@ -245,11 +327,49 @@ class dynamic_length_array_type : public array_type {
 public:
        dynamic_length_array_type(unsigned int alignment,
                        type::cuptr element_type,
-                       std::string length_field_name);
+                       field_location length_field_location);
+
+       virtual type::cuptr copy() const override final;
+
+       virtual void accept(type_visitor& visitor) const override final;
+
+       const field_location length_field_location;
+
+private:
+       virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class static_length_blob_type : public type {
+public:
+       enum class role {
+               /* Packet header field class specific role. */
+               METADATA_STREAM_UUID,
+       };
+
+       using roles = std::vector<role>;
+
+       static_length_blob_type(unsigned int alignment, uint64_t in_length_bytes, roles roles = {});
+
+       virtual type::cuptr copy() const override final;
+
+       virtual void accept(type_visitor& visitor) const override final;
+
+       const uint64_t length_bytes;
+       const roles roles_;
+
+private:
+       virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class dynamic_length_blob_type : public type {
+public:
+       dynamic_length_blob_type(unsigned int alignment, field_location length_field_location);
+
+       virtual type::cuptr copy() const override final;
 
        virtual void accept(type_visitor& visitor) const override final;
 
-       const std::string length_field_name;
+       const field_location length_field_location;
 
 private:
        virtual bool _is_equal(const type& base_other) const noexcept override final;
@@ -264,7 +384,12 @@ public:
 
        string_type(unsigned int alignment, enum encoding encoding);
 
-       const encoding encoding;
+       /*
+        * encoding is suffixed with '_' to work-around a bug in older
+        * GCCs (before 6) that do not recognize hidden/shadowed enumeration as valid
+        * nested-name-specifiers.
+        */
+       const encoding encoding_;
 
 protected:
        virtual bool _is_equal(const type& base_other) const noexcept override;
@@ -274,6 +399,9 @@ class static_length_string_type : public string_type {
 public:
        static_length_string_type(
                        unsigned int alignment, enum encoding in_encoding, uint64_t length);
+
+       virtual type::cuptr copy() const override final;
+
        virtual void accept(type_visitor& visitor) const override final;
 
        const uint64_t length;
@@ -286,10 +414,13 @@ class dynamic_length_string_type : public string_type {
 public:
        dynamic_length_string_type(unsigned int alignment,
                        enum encoding in_encoding,
-                       std::string length_field_name);
+                       field_location length_field_location);
+
+       virtual type::cuptr copy() const override final;
+
        virtual void accept(type_visitor& visitor) const override final;
 
-       const std::string length_field_name;
+       const field_location length_field_location;
 
 private:
        virtual bool _is_equal(const type& base_other) const noexcept override final;
@@ -298,6 +429,9 @@ private:
 class null_terminated_string_type : public string_type {
 public:
        null_terminated_string_type(unsigned int alignment, enum encoding in_encoding);
+
+       virtual type::cuptr copy() const override final;
+
        virtual void accept(type_visitor& visitor) const override final;
 };
 
@@ -307,27 +441,81 @@ public:
 
        structure_type(unsigned int alignment, fields in_fields);
 
+       virtual type::cuptr copy() const override final;
+
        virtual void accept(type_visitor& visitor) const override final;
 
-       const fields _fields;
+       const fields fields_;
 
 private:
        virtual bool _is_equal(const type& base_other) const noexcept override final;
 };
 
+template <typename MappingIntegerType>
 class variant_type : public type {
+       static_assert(std::is_same<MappingIntegerType,
+                                       unsigned_enumeration_type::mapping::range_t::
+                                                       range_integer_t>::value ||
+                                       std::is_same<MappingIntegerType,
+                                                       signed_enumeration_type::mapping::range_t::
+                                                                       range_integer_t>::value,
+                       "Variant mapping integer type must be one of those allowed by typed_enumeration_type");
+
 public:
-       using choices = std::vector<field::cuptr>;
+       using choice = std::pair<const details::enumeration_mapping<MappingIntegerType>, type::cuptr>;
+       using choices = std::vector<choice>;
+
+       variant_type(unsigned int in_alignment,
+                       field_location in_selector_field_location,
+                       choices in_choices) :
+               type(in_alignment),
+               selector_field_location{std::move(in_selector_field_location)},
+               choices_{std::move(in_choices)}
+       {
+       }
 
-       variant_type(unsigned int alignment, std::string tag_name, choices in_choices);
+       virtual type::cuptr copy() const override final
+       {
+               choices copy_of_choices;
+
+               copy_of_choices.reserve(choices_.size());
+               for (const auto& current_choice : choices_) {
+                       copy_of_choices.emplace_back(
+                                       current_choice.first, current_choice.second->copy());
+               }
+
+               return lttng::make_unique<variant_type<MappingIntegerType>>(
+                       alignment, selector_field_location, std::move(copy_of_choices));
+       }
 
        virtual void accept(type_visitor& visitor) const override final;
 
-       const std::string tag_name;
-       const choices _choices;
+       const field_location selector_field_location;
+       const choices choices_;
 
 private:
-       virtual bool _is_equal(const type& base_other) const noexcept override final;
+       static bool _choices_are_equal(const choices& a, const choices& b)
+       {
+               if (a.size() != b.size()) {
+                       return false;
+               }
+
+               return true;
+
+               return std::equal(a.cbegin(), a.cend(), b.cbegin(),
+                               [](const choice& choice_a, const choice& choice_b) {
+                                       return choice_a.first == choice_b.first &&
+                                               *choice_a.second == *choice_b.second;
+                               });
+       }
+
+       virtual bool _is_equal(const type& base_other) const noexcept override final
+       {
+               const auto& other = static_cast<decltype(*this)&>(base_other);
+
+               return selector_field_location == other.selector_field_location &&
+                               _choices_are_equal(choices_, other.choices_);
+       }
 };
 
 class field_visitor {
@@ -348,11 +536,14 @@ public:
        virtual void visit(const unsigned_enumeration_type& type) = 0;
        virtual void visit(const static_length_array_type& type) = 0;
        virtual void visit(const dynamic_length_array_type& type) = 0;
+       virtual void visit(const static_length_blob_type& type) = 0;
+       virtual void visit(const dynamic_length_blob_type& type) = 0;
        virtual void visit(const null_terminated_string_type& type) = 0;
        virtual void visit(const static_length_string_type& type) = 0;
        virtual void visit(const dynamic_length_string_type& type) = 0;
        virtual void visit(const structure_type& type) = 0;
-       virtual void visit(const variant_type& type) = 0;
+       virtual void visit(const variant_type<signed_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
+       virtual void visit(const variant_type<unsigned_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
 
 protected:
        type_visitor() = default;
@@ -362,4 +553,96 @@ protected:
 } /* namespace sessiond */
 } /* namespace lttng */
 
+/*
+ * Field formatters for libfmt.
+ *
+ * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace,
+ * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480.
+ */
+namespace fmt {
+template <>
+struct formatter<lttng::sessiond::trace::field_location> : formatter<std::string> {
+       template <typename FormatCtx>
+       typename FormatCtx::iterator format(
+                       const lttng::sessiond::trace::field_location& location, FormatCtx& ctx)
+       {
+               std::string location_str{"["};
+
+               switch (location.root_) {
+               case lttng::sessiond::trace::field_location::root::PACKET_HEADER:
+                       location_str += "\"packet-header\"";
+                       break;
+               case lttng::sessiond::trace::field_location::root::PACKET_CONTEXT:
+                       location_str += "\"packet-context\"";
+                       break;
+               case lttng::sessiond::trace::field_location::root::EVENT_RECORD_HEADER:
+                       location_str += "\"event-record-header\"";
+                       break;
+               case lttng::sessiond::trace::field_location::root::EVENT_RECORD_COMMON_CONTEXT:
+                       location_str += "\"event-record-common-context\"";
+                       break;
+               case lttng::sessiond::trace::field_location::root::EVENT_RECORD_SPECIFIC_CONTEXT:
+                       location_str += "\"event-record-specific-context\"";
+                       break;
+               case lttng::sessiond::trace::field_location::root::EVENT_RECORD_PAYLOAD:
+                       location_str += "\"event-record-payload\"";
+                       break;
+               }
+
+               for (const auto &name : location.elements_) {
+                       location_str += ", \"" + name + "\"";
+               }
+
+               location_str += "]";
+               return format_to(ctx.out(), location_str);
+       }
+};
+
+namespace details {
+template <typename MappingIntegerType>
+::std::string format_mapping_range(typename lttng::sessiond::trace::typed_enumeration_type<
+               MappingIntegerType>::mapping::range_t range)
+{
+       if (range.begin == range.end) {
+               return ::fmt::format("[{}]", range.begin);
+       } else {
+               return ::fmt::format("[{}, {}]", range.begin, range.end);
+       }
+}
+} /* namespace details */
+
+template <>
+struct formatter<typename lttng::sessiond::trace::signed_enumeration_type::mapping::range_t>
+       : formatter<std::string> {
+       template <typename FormatCtx>
+       typename FormatCtx::iterator
+       format(typename lttng::sessiond::trace::signed_enumeration_type::mapping::range_t range,
+                       FormatCtx& ctx)
+       {
+               return format_to(ctx.out(),
+                               details::format_mapping_range<
+                                               lttng::sessiond::trace::signed_enumeration_type::
+                                                               mapping::range_t::range_integer_t>(
+                                               range));
+       }
+};
+
+template <>
+struct formatter<typename lttng::sessiond::trace::unsigned_enumeration_type::mapping::range_t>
+       : formatter<std::string> {
+       template <typename FormatCtx>
+       typename FormatCtx::iterator
+       format(typename lttng::sessiond::trace::unsigned_enumeration_type::mapping::range_t range,
+                       FormatCtx& ctx)
+       {
+               return format_to(ctx.out(),
+                               details::format_mapping_range<
+                                               lttng::sessiond::trace::unsigned_enumeration_type::
+                                                               mapping::range_t::range_integer_t>(
+                                               range));
+       }
+};
+
+} /* namespace fmt */
+
 #endif /* LTTNG_FIELD_H */
This page took 0.029652 seconds and 4 git commands to generate.