*
*/
+#include "common/bytecode/bytecode.hpp"
+#include "common/macros.hpp"
+#include "common/uuid.hpp"
+#include <endian.h>
#define _LGPL_SOURCE
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <inttypes.h>
-#include <common/common.h>
-#include <common/time.h>
+#include <common/common.hpp>
+#include <common/time.hpp>
+#include <vector>
+#include <vendor/nlohmann/json.hpp>
-#include "ust-registry.h"
-#include "ust-clock.h"
-#include "ust-app.h"
-
-#ifndef max_t
-#define max_t(type, a, b) ((type) ((a) > (b) ? (a) : (b)))
-#endif
+#include "ust-registry.hpp"
+#include "ust-clock.hpp"
+#include "ust-app.hpp"
#define NR_CLOCK_OFFSET_SAMPLES 10
+using json = nlohmann::json;
+
struct offset_sample {
int64_t offset; /* correlation offset */
uint64_t measure_delta; /* lower is better */
};
+enum class byte_order
+{
+ BIG,
+ LITTLE,
+};
+
+enum class display_base
+{
+ BINARY,
+ OCTAL,
+ DECIMAL,
+ HEXADECIMAL,
+};
+
+struct metadata_generation_exception : public std::runtime_error
+{
+ metadata_generation_exception(const char *what)
+ : std::runtime_error(what)
+ {}
+};
+
+struct lttng_ust_ctl_field_iterator
+{
+ lttng_ust_ctl_field_iterator(const lttng_ust_ctl_field *array,
+ size_t len)
+ : _array(array), _len(len)
+ {}
+
+ /* Make sure we don't pass it by value, by mistake. */
+ lttng_ust_ctl_field_iterator(const lttng_ust_ctl_field_iterator &) = delete;
+ void operator=(const lttng_ust_ctl_field_iterator &) = delete;
+
+ const lttng_ust_ctl_field &get_next()
+ {
+ if (done()) {
+ throw metadata_generation_exception(
+ "Field iterator overflow");
+ };
+
+ return _array[_cur++];
+ }
+
+ bool done() const
+ {
+ return _cur >= _len;
+ }
+
+private:
+ const lttng_ust_ctl_field *_array;
+ size_t _cur = 0;
+ size_t _len;
+};
+
+static
+byte_order get_byte_order(const ust_registry_session &session, bool reverse)
+{
+ if (session.byte_order == BIG_ENDIAN) {
+ return reverse ? byte_order::LITTLE : byte_order::BIG;
+ } else {
+ return reverse ? byte_order::BIG : byte_order::LITTLE;
+ }
+}
+
+struct bits
+{
+ using underlying_type = uint64_t;
+ explicit bits(uint64_t val)
+ : _val(val)
+ {}
+
+ underlying_type to_underlying() const
+ {
+ return static_cast<underlying_type>(_val);
+ }
+
+ bool operator==(bits other)
+ {
+ return to_underlying() == other.to_underlying();
+ }
+
+ bool operator!=(bits other)
+ {
+ return to_underlying() != other.to_underlying();
+ }
+
+private:
+ const uint64_t _val;
+};
+
+static
+bits operator"" _bits(unsigned long long val)
+{
+ return bits(val);
+}
+
+static
+json make_fragment(const char *type)
+{
+ return {
+ { "type", type }
+ };
+}
+
+static
+json make_field_class(const char *type, const char *role)
+{
+ json fc {
+ { "type", type },
+ };
+
+ if (role) {
+ fc["roles"] = {role};
+ }
+
+ return fc;
+}
+
+static
+const char *make_byte_order(byte_order byte_order)
+{
+ switch (byte_order) {
+ case byte_order::BIG:
+ return "big-endian";
+ case byte_order::LITTLE:
+ return "little-endian";
+ default:
+ abort();
+ }
+}
+
+static
+json make_fixed_length_bit_array_field_class(const char *type, bits length,
+ byte_order byte_order, bits alignment, const char *role)
+{
+ json fc = make_field_class(type, role);
+
+ fc.update ({
+ { "length", length.to_underlying() },
+ { "byte-order", make_byte_order(byte_order) },
+ });
+
+ if (alignment != 0_bits) {
+ fc["alignment"] = alignment.to_underlying();
+ }
+
+ return fc;
+}
+
+static
+json make_display_base(display_base display_base)
+{
+ switch (display_base) {
+ case display_base::BINARY:
+ return 2;
+ case display_base::OCTAL:
+ return 8;
+ case display_base::DECIMAL:
+ return 10;
+ case display_base::HEXADECIMAL:
+ return 16;
+ default:
+ abort();
+ }
+}
+
+static
+json make_abstract_integer_field_class(display_base preferred_display_base)
+{
+ json base = json::object();
+ if (preferred_display_base != display_base::DECIMAL) {
+ base = {
+ { "preferred-display-base",
+ make_display_base(preferred_display_base)},
+
+ };
+ }
+ return base;
+}
+
+static
+json make_fixed_length_unsigned_integer_field_class(const char *type,
+ bits length, byte_order byte_order, bits alignment,
+ display_base preferred_display_base, const char *role)
+{
+ json fc = make_fixed_length_bit_array_field_class(type, length,
+ byte_order, alignment, role);
+ fc.update(make_abstract_integer_field_class(preferred_display_base));
+ return fc;
+}
+
+static
+json make_fixed_length_signed_integer_field_class(const char *type,
+ bits length, byte_order byte_order, bits alignment,
+ display_base preferred_display_base, const char *role)
+{
+ json fc = make_fixed_length_bit_array_field_class(type, length,
+ byte_order, alignment, role);
+ fc.update(make_abstract_integer_field_class(preferred_display_base));
+ return fc;
+}
+
+static
+json make_fixed_length_unsigned_integer_field_class(bits length,
+ byte_order byte_order, bits alignment,
+ display_base preferred_display_base, const char *role)
+{
+ return make_fixed_length_unsigned_integer_field_class(
+ "fixed-length-unsigned-integer", length, byte_order,
+ alignment, preferred_display_base, role);
+}
+
+static
+json make_fixed_length_signed_integer_field_class(bits length,
+ byte_order byte_order, bits alignment,
+ display_base preferred_display_base, const char *role)
+{
+ return make_fixed_length_signed_integer_field_class(
+ "fixed-length-signed-integer", length, byte_order,
+ alignment, preferred_display_base, role);
+}
+
+static
+json make_fixed_length_floating_point_number_field_class(
+ bits length, byte_order byte_order, bits alignment) {
+ return make_fixed_length_bit_array_field_class(
+ "fixed-length-floating-point-number",
+ length, byte_order, alignment, nullptr);
+}
+
+struct integer_range
+{
+ integer_range(int64_t lower_bound_, int64_t upper_bound_)
+ : is_signed(true), lower_bound(lower_bound_), upper_bound(upper_bound_)
+ {}
+
+ integer_range(uint64_t lower_bound_, uint64_t upper_bound_)
+ : is_signed(false), lower_bound(lower_bound_), upper_bound(upper_bound_)
+ {}
+
+ const bool is_signed;
+ const int64_t lower_bound, upper_bound;
+};
+
+struct integer_range_set
+{
+ using vec_type = std::vector<integer_range>;
+ using const_iterator = vec_type::const_iterator;
+
+ integer_range_set() = default;
+ DISABLE_COPY_AND_ASSIGN(integer_range_set);
+ integer_range_set(integer_range_set &&) = default;
+
+ void add_range(int64_t lower_bound, int64_t upper_bound)
+ {
+ _ranges.emplace_back(lower_bound, upper_bound);
+ }
+
+ void add_range(uint64_t lower_bound, uint64_t upper_bound)
+ {
+ _ranges.emplace_back(lower_bound, upper_bound);
+ }
+
+ const_iterator begin() const
+ { return _ranges.begin(); }
+
+ const_iterator end() const
+ { return _ranges.end(); }
+
+private:
+ vec_type _ranges;
+};
+
+struct enumeration_mapping
+{
+ enumeration_mapping(const char *name_, json ranges_)
+ : name(name_), ranges(std::move(ranges_))
+ {}
+
+ const char *const name;
+ json ranges;
+};
+
+struct enumeration_mappings
+{
+ using vec_type = std::vector<enumeration_mapping>;
+ using const_iterator = vec_type::const_iterator;
+
+ enumeration_mappings() = default;
+ DISABLE_COPY_AND_ASSIGN(enumeration_mappings);
+ enumeration_mappings(enumeration_mappings &&) = default;
+
+ void add_mapping(const char *name_, json ranges_)
+ {
+ _mappings.emplace_back(name_, std::move(ranges_));
+ }
+
+ const_iterator begin() const
+ { return _mappings.begin(); }
+
+ const_iterator end() const
+ { return _mappings.end(); }
+
+private:
+ vec_type _mappings;
+};
+
+static
+json make_integer_range_set(const integer_range_set &ranges)
+{
+ json rs = json::array();
+
+ for (const integer_range &range : ranges) {
+ rs.push_back({ range.lower_bound, range.upper_bound });
+ }
+
+ return rs;
+}
+
+static json
+make_enumeration_mappings(enumeration_mappings mappings)
+{
+ json mappings_obj = json::object();
+
+ for (const enumeration_mapping &mapping : mappings) {
+ mappings_obj[mapping.name] = std::move(mapping.ranges);
+ }
+
+ return mappings_obj;
+}
+
static
-int _lttng_field_statedump(struct ust_registry_session *session,
- const struct lttng_ust_ctl_field *fields, size_t nr_fields,
- size_t *iter_field, size_t nesting);
+json make_abstract_enumeration_field_class(display_base preferred_display_base,
+ enumeration_mappings mappings)
+{
+ json fc = make_abstract_integer_field_class(preferred_display_base);
+ fc["mappings"] = make_enumeration_mappings(std::move(mappings));
+ return fc;
+}
+
+
+static
+json make_fixed_length_unsigned_enumeration_field_class(bits length,
+ byte_order byte_order, bits alignment,
+ display_base preferred_display_base, const char *role,
+ enumeration_mappings mappings)
+{
+ json fc = make_fixed_length_unsigned_integer_field_class(
+ "fixed-length-unsigned-enumeration", length, byte_order,
+ alignment, preferred_display_base, role);
+ fc.update(make_abstract_enumeration_field_class(preferred_display_base,
+ std::move(mappings)));
+ return fc;
+}
+
+static
+json make_fixed_length_signed_enumeration_field_class(bits length,
+ byte_order byte_order, bits alignment,
+ display_base preferred_display_base, const char *role,
+ enumeration_mappings mappings)
+{
+ json fc = make_fixed_length_signed_integer_field_class(
+ "fixed-length-signed-enumeration", length, byte_order,
+ alignment, preferred_display_base, role);
+ fc.update(make_abstract_enumeration_field_class(preferred_display_base,
+ std::move(mappings)));
+ return fc;
+}
+
+static
+json make_fixed_length_enumeration_field_class(bool signedness,
+ bits length, byte_order byte_order, bits alignment,
+ display_base preferred_display_base,
+ enumeration_mappings mappings)
+{
+ if (signedness) {
+ return make_fixed_length_signed_enumeration_field_class(
+ length, byte_order, alignment, preferred_display_base,
+ nullptr, std::move(mappings));
+ } else {
+ return make_fixed_length_unsigned_enumeration_field_class(
+ length, byte_order, alignment, preferred_display_base,
+ nullptr, std::move(mappings));
+ }
+}
+
+static
+json make_static_length_blob_field_class(uint64_t length, const char *role)
+{
+ json fc = make_field_class("static-length-blob", role);
+
+ fc.update({
+ { "length", length },
+ });
+
+ return fc;
+}
+
+static
+json make_uuid_field_class(const char *role)
+{
+ return make_static_length_blob_field_class(16, role);
+}
+
+struct structure_member
+{
+ structure_member(const char *name_, json field_class_)
+ : name(name_), field_class(std::move(field_class_))
+ {}
+
+ DISABLE_COPY_AND_ASSIGN(structure_member);
+ structure_member(structure_member &&) = default;
+
+ const char *const name;
+ json field_class;
+};
+
+struct structure_members
+{
+ using vec_type = std::vector<structure_member>;
+
+ structure_members() = default;
+ structure_members(const structure_members &) = delete;
+ structure_members(structure_members &&) = default;
+ structure_members &operator=(const structure_members &) = delete;
+
+ void add_member(const char *name, json field_class)
+ {
+ _members.emplace_back(structure_member(
+ name, std::move(field_class)
+ ));
+ }
+
+ vec_type::iterator begin()
+ { return _members.begin (); }
+
+ vec_type::iterator end()
+ { return _members.end (); }
+
+private:
+ vec_type _members;
+};
+
+static
+json make_struct_member(structure_member member)
+{
+ return {
+ { "name", member.name },
+ { "field-class", std::move(member.field_class) },
+ };
+}
+
+static
+json make_structure_members(structure_members members)
+{
+ json members_obj = json::array();
+
+ for (structure_member &member : members) {
+ members_obj.push_back(make_struct_member(std::move(member)));
+ }
+
+ return members_obj;
+}
+
+static
+json make_structure_field_class(bits minimum_alignment,
+ structure_members members)
+{
+ json fc = make_field_class("structure", nullptr);
+
+ fc["member-classes"] = make_structure_members(std::move(members));
+
+ if (minimum_alignment != 0_bits) {
+ fc["minimum-alignment"] = minimum_alignment.to_underlying();
+ }
+
+ return fc;
+}
+
+
+struct variant_option
+{
+ variant_option(const char *name_,
+ json selector_field_ranges_,
+ json field_class_)
+ : name(name_),
+ selector_field_ranges(std::move(selector_field_ranges_)),
+ field_class(std::move(field_class_))
+ {}
+
+ variant_option(std::string name_,
+ json selector_field_ranges_,
+ json field_class_)
+ : _name_buf(std::move(name_)),
+ name(_name_buf.c_str()),
+ selector_field_ranges(std::move(selector_field_ranges_)),
+ field_class(std::move(field_class_))
+ {}
+
+ DISABLE_COPY_AND_ASSIGN(variant_option);
+
+ variant_option(variant_option &&other)
+ : _name_buf(std::move(other._name_buf)),
+ /*
+ * If `_name_buf` is empty, `name` is not managed by us,
+ * just copy the pointer. If `_name_buf` is not empty,
+ * make `name` point to our local copy.
+ */
+ name(_name_buf.empty() ? other.name : _name_buf.c_str()),
+ selector_field_ranges(other.selector_field_ranges),
+ field_class(other.field_class)
+
+ {}
+
+private:
+ /*
+ * Buffer for `name`, if it is dynamically allocated andmanaged by us.
+ */
+ const std::string _name_buf;
+
+public:
+ const char *name;
+ json selector_field_ranges;
+ json field_class;
+};
+
+struct variant_options
+{
+ using vec_type = std::vector<variant_option>;
+ using iterator = vec_type::iterator;
+ using const_iterator = vec_type::const_iterator;
+
+ variant_options() = default;
+ DISABLE_COPY_AND_ASSIGN(variant_options);
+ variant_options(variant_options &&) = default;
+
+ void add_option(const char *name, json selector_field_ranges,
+ json field_class)
+ {
+ _options.emplace_back(variant_option(
+ name, std::move(selector_field_ranges),
+ std::move(field_class)
+ ));
+ }
+
+ void add_option(std::string name, json selector_field_ranges,
+ json field_class)
+ {
+ _options.emplace_back(variant_option(
+ std::move(name), std::move(selector_field_ranges),
+ std::move(field_class)
+ ));
+ }
+
+ iterator begin()
+ { return _options.begin(); }
+
+ iterator end()
+ { return _options.end(); }
+
+ const_iterator begin() const
+ { return _options.begin(); }
+
+ const_iterator end() const
+ { return _options.end(); }
+
+private:
+ vec_type _options;
+};
+
+struct field_path
+{
+ using vec_type = std::vector<const char *>;
+
+ struct popper
+ {
+ popper(struct field_path &path)
+ : _path(path)
+ {}
+
+ popper(const popper &) = delete;
+ popper(popper &&) = default;
+ void operator=(const popper &) = delete;
+
+ ~popper()
+ {
+ _path._path.pop_back();
+
+ }
+
+ private:
+ field_path &_path;
+ };
+
+ field_path(const char *root)
+ : _path({root})
+ {}
+
+ field_path(std::initializer_list<const char *> list)
+ : _path(list)
+ {}
+
+ const vec_type &path() const
+ {
+ return _path;
+ }
+
+ popper push(const char *element)
+ {
+ _path.push_back(element);
+ return popper(*this);
+ }
+
+private:
+ vec_type _path;
+};
+
+static
+json make_variant_option(variant_option option)
+{
+ return {
+ { "name", option.name },
+ { "selector-field-ranges", std::move(option.selector_field_ranges) },
+ { "field-class", std::move(option.field_class ) },
+ };
+}
+
+static
+json make_variant_options(variant_options options)
+{
+ json options_obj = json::array();
+
+ for (variant_option &option : options) {
+ options_obj.push_back(make_variant_option(std::move(option)));
+ }
+
+ return options_obj;
+}
+
+static
+json make_field_location(const field_path &field_location)
+{
+ return field_location.path();
+}
+
+static
+json make_variant_field_class(variant_options options,
+ const field_path &selector_field_location)
+{
+ json fc = make_field_class("variant", nullptr);
+
+ fc["options"] = make_variant_options(std::move(options));
+ fc["selector-field-location"] =
+ make_field_location(selector_field_location);
+
+ return fc;
+}
+
+static
+json make_array_field_class(const char *type, json element_field_class,
+ bits minimum_alignment)
+{
+ json fc = make_field_class(type, nullptr);
+
+ fc["element-field-class"] = std::move(element_field_class);
+
+ if (minimum_alignment != 0_bits) {
+ fc["minimum-alignment"] = minimum_alignment.to_underlying();
+ }
+
+ return fc;
+}
+
+static
+json make_static_length_array_field_class(json element_field_class,
+ uint64_t length, bits minimum_alignment)
+{
+ json fc = make_array_field_class("static-length-array",
+ element_field_class, minimum_alignment);
+
+ fc["length"] = length;
+
+ return fc;
+}
+
+static
+json make_dynamic_length_array_field_class(json element_field_class,
+ const field_path &length_field_location, bits minimum_alignment)
+{
+ json fc = make_array_field_class("dynamic-length-array",
+ element_field_class, minimum_alignment);
+
+ fc["length-field-location"] =
+ make_field_location(length_field_location);
+
+ return fc;
+}
+
+static
+json make_string_field_class()
+{
+ return make_field_class("null-terminated-string", nullptr);
+}
+
+static
+json make_packet_header_field_class(const ust_registry_session &session)
+{
+ byte_order bo = get_byte_order(session, false);
+
+ structure_members members;
+
+ members.add_member("magic",
+ make_fixed_length_unsigned_integer_field_class(
+ 32_bits, bo, 8_bits, display_base::HEXADECIMAL,
+ "packet-magic-number"));
+ members.add_member("uuid",
+ make_uuid_field_class("trace-class-uuid"));
+ members.add_member("stream_id",
+ make_fixed_length_unsigned_integer_field_class(
+ 32_bits, bo, 8_bits, display_base::DECIMAL,
+ "data-stream-class-id"));
+ members.add_member("stream_instance_id",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "data-stream-id"));
+
+ return make_structure_field_class(0_bits, std::move(members));
+}
+
+static
+json make_uuid(uint8_t uuid_bytes[LTTNG_UUID_LEN])
+{
+ json uuid = json::array();
+
+ for (size_t i = 0; i < LTTNG_UUID_LEN; ++i) {
+ uuid.push_back(uuid_bytes[i]);
+ }
+
+ return uuid;
+}
+
+static
+json make_clock_offset(int64_t offset_cycles, uint64_t freq)
+{
+ // FIXME: not tested at all, especially not for negative values of offset
+
+ /* Whole seconds. */
+ int64_t s = offset_cycles / freq;
+
+ /* Remaining cycles. */
+ int64_t cycles = offset_cycles % freq;
+
+ return {
+ { "seconds", s },
+ { "cycles", cycles },
+ };
+}
static inline
int get_count_order(unsigned int count)
* Returns offset where to write in metadata array, or negative error value on error.
*/
static
-ssize_t metadata_reserve(struct ust_registry_session *session, size_t len)
+ssize_t metadata_reserve(ust_registry_session &session, size_t len)
{
- size_t new_len = session->metadata_len + len;
+ size_t new_len = session.metadata_len + len;
size_t new_alloc_len = new_len;
- size_t old_alloc_len = session->metadata_alloc_len;
+ size_t old_alloc_len = session.metadata_alloc_len;
ssize_t ret;
if (new_alloc_len > (UINT32_MAX >> 1))
char *newptr;
new_alloc_len =
- max_t(size_t, 1U << get_count_order(new_alloc_len), old_alloc_len << 1);
- newptr = (char *) realloc(session->metadata, new_alloc_len);
+ std::max<size_t>(1U << get_count_order(new_alloc_len), old_alloc_len << 1);
+ newptr = (char *) realloc(session.metadata, new_alloc_len);
if (!newptr)
return -ENOMEM;
- session->metadata = newptr;
+ session.metadata = newptr;
/* We zero directly the memory from start of allocation. */
- memset(&session->metadata[old_alloc_len], 0, new_alloc_len - old_alloc_len);
- session->metadata_alloc_len = new_alloc_len;
+ memset(&session.metadata[old_alloc_len], 0, new_alloc_len - old_alloc_len);
+ session.metadata_alloc_len = new_alloc_len;
}
- ret = session->metadata_len;
- session->metadata_len += len;
+ ret = session.metadata_len;
+ session.metadata_len += len;
return ret;
}
static
-int metadata_file_append(struct ust_registry_session *session,
+int metadata_file_append(ust_registry_session &session,
const char *str, size_t len)
{
ssize_t written;
- if (session->metadata_fd < 0) {
+ if (session.metadata_fd < 0) {
return 0;
}
/* Write to metadata file */
- written = lttng_write(session->metadata_fd, str, len);
+ written = lttng_write(session.metadata_fd, str, len);
if (written != len) {
return -1;
}
* protects us from concurrent writes.
*/
static ATTR_FORMAT_PRINTF(2, 3)
-int lttng_metadata_printf(struct ust_registry_session *session,
+int lttng_metadata_printf(ust_registry_session &session,
const char *fmt, ...)
{
char *str = NULL;
ret = offset;
goto end;
}
- memcpy(&session->metadata[offset], str, len);
+ memcpy(&session.metadata[offset], str, len);
ret = metadata_file_append(session, str, len);
if (ret) {
PERROR("Error appending to metadata file");
return ret;
}
+
static
-int print_tabs(struct ust_registry_session *session, size_t nesting)
+void lttng_metadata_print_fragment(ust_registry_session &session,
+ const json &fragment)
{
- size_t i;
-
- for (i = 0; i < nesting; i++) {
- int ret;
-
- ret = lttng_metadata_printf(session, " ");
- if (ret) {
- return ret;
- }
- }
- return 0;
+ lttng_metadata_printf(session, "\x1e%s", fragment.dump(2).c_str());
}
static
-void sanitize_ctf_identifier(char *out, const char *in)
+display_base int_to_display_base(int base)
{
- size_t i;
-
- for (i = 0; i < LTTNG_UST_ABI_SYM_NAME_LEN; i++) {
- switch (in[i]) {
- case '.':
- case '$':
- case ':':
- out[i] = '_';
- break;
- default:
- out[i] = in[i];
- }
+ /* If we ever get an invalid value, default to 10. */
+ switch (base) {
+ case 2:
+ return display_base::BINARY;
+ case 8:
+ return display_base::OCTAL;
+ default:
+ case 10:
+ return display_base::DECIMAL;
+ case 16:
+ return display_base::HEXADECIMAL;
}
}
static
-int print_escaped_ctf_string(struct ust_registry_session *session, const char *string)
-{
- int ret = 0;
- size_t i;
- char cur;
-
- i = 0;
- cur = string[i];
- while (cur != '\0') {
- switch (cur) {
- case '\n':
- ret = lttng_metadata_printf(session, "%s", "\\n");
- break;
- case '\\':
- case '"':
- ret = lttng_metadata_printf(session, "%c", '\\');
- if (ret) {
- goto error;
- }
- /* We still print the current char */
- /* Fallthrough */
- default:
- ret = lttng_metadata_printf(session, "%c", cur);
- break;
- }
-
- if (ret) {
- goto error;
- }
-
- cur = string[++i];
+json make_ust_integer_field_class(const ust_registry_session &session,
+ const lttng_ust_ctl_integer_type &type)
+{
+ if (type.signedness) {
+ return make_fixed_length_signed_integer_field_class(
+ bits(type.size), get_byte_order(session, type.reverse_byte_order),
+ bits(type.alignment), int_to_display_base(type.base),
+ nullptr);
+ } else {
+ return make_fixed_length_unsigned_integer_field_class(
+ bits(type.size), get_byte_order(session, type.reverse_byte_order),
+ bits(type.alignment), int_to_display_base(type.base),
+ nullptr);
}
-error:
- return ret;
}
/* Called with session registry mutex held. */
static
-int ust_metadata_enum_statedump(struct ust_registry_session *session,
- const char *enum_name,
- uint64_t enum_id,
- const struct lttng_ust_ctl_integer_type *container_type,
- const char *field_name, size_t *iter_field, size_t nesting)
-{
- struct ust_registry_enum *reg_enum;
- const struct lttng_ust_ctl_enum_entry *entries;
- size_t nr_entries;
- int ret = 0;
- size_t i;
- char identifier[LTTNG_UST_ABI_SYM_NAME_LEN];
-
+json make_ust_enum_field_class(const ust_registry_session &session,
+ const char *name, uint64_t id,
+ const lttng_ust_ctl_integer_type &container)
+{
rcu_read_lock();
- reg_enum = ust_registry_lookup_enum_by_id(session, enum_name, enum_id);
+ const ust_registry_enum *reg_enum = ust_registry_lookup_enum_by_id(
+ session, name, id);
rcu_read_unlock();
+
/* reg_enum can still be used because session registry mutex is held. */
if (!reg_enum) {
- ret = -ENOENT;
- goto end;
+ return -ENOENT;
}
- entries = reg_enum->entries;
- nr_entries = reg_enum->nr_entries;
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "enum : integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u; } {\n",
- container_type->size,
- container_type->alignment,
- container_type->signedness,
- (container_type->encoding == lttng_ust_ctl_encode_none)
- ? "none"
- : (container_type->encoding == lttng_ust_ctl_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- container_type->base);
- if (ret) {
- goto end;
+ bool is_signed = container.signedness;
+ enumeration_mappings mappings;
+
+ const lttng_ust_ctl_enum_entry *entries = reg_enum->entries;
+
+ union {
+ int64_t sign;
+ uint64_t nosign;
+ } next_auto_low_bound;
+
+ if (is_signed) {
+ next_auto_low_bound.sign = 0;
+ } else {
+ next_auto_low_bound.nosign = 0;
}
- nesting++;
- /* Dump all entries */
- for (i = 0; i < nr_entries; i++) {
- const struct lttng_ust_ctl_enum_entry *entry = &entries[i];
- int j, len;
-
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "\"");
- if (ret) {
- goto end;
- }
- len = strlen(entry->string);
- /* Escape the character '"' */
- for (j = 0; j < len; j++) {
- char c = entry->string[j];
-
- switch (c) {
- case '"':
- ret = lttng_metadata_printf(session,
- "\\\"");
- break;
- case '\\':
- ret = lttng_metadata_printf(session,
- "\\\\");
- break;
- default:
- ret = lttng_metadata_printf(session,
- "%c", c);
- break;
- }
- if (ret) {
- goto end;
- }
- }
- ret = lttng_metadata_printf(session, "\"");
- if (ret) {
- goto end;
- }
- if (entry->u.extra.options &
- LTTNG_UST_CTL_UST_ENUM_ENTRY_OPTION_IS_AUTO) {
- ret = lttng_metadata_printf(session, ",\n");
- if (ret) {
- goto end;
- }
- } else {
- ret = lttng_metadata_printf(session,
- " = ");
- if (ret) {
- goto end;
- }
+ for (size_t i = 0; i < reg_enum->nr_entries; ++i) {
+ const lttng_ust_ctl_enum_entry &entry = entries[i];
- if (entry->start.signedness) {
- ret = lttng_metadata_printf(session,
- "%" PRId64, entry->start.value);
- } else {
- ret = lttng_metadata_printf(session,
- "%" PRIu64, entry->start.value);
- }
- if (ret) {
- goto end;
- }
+ //len = strlen(entry->string);
- if (entry->start.signedness == entry->end.signedness &&
- entry->start.value ==
- entry->end.value) {
- ret = lttng_metadata_printf(session, ",\n");
+ if (entry.u.extra.options &
+ LTTNG_UST_CTL_UST_ENUM_ENTRY_OPTION_IS_AUTO) {
+ if (is_signed) {
+ integer_range_set rs;
+ rs.add_range(next_auto_low_bound.sign, next_auto_low_bound.sign);
+ mappings.add_mapping(entry.string, make_integer_range_set(rs));
+ ++next_auto_low_bound.sign;
} else {
- if (entry->end.signedness) {
- ret = lttng_metadata_printf(session,
- " ... %" PRId64 ",\n",
- entry->end.value);
- } else {
- ret = lttng_metadata_printf(session,
- " ... %" PRIu64 ",\n",
- entry->end.value);
- }
+ integer_range_set rs;
+ rs.add_range(next_auto_low_bound.nosign, next_auto_low_bound.nosign);
+ mappings.add_mapping(entry.string, make_integer_range_set(rs));
+ ++next_auto_low_bound.nosign;
}
- if (ret) {
- goto end;
+ } else {
+ if (is_signed) {
+ integer_range_set rs;
+ // FIXME: not sure if those casts work as intended.
+ rs.add_range((int64_t) entry.start.value, (int64_t) entry.end.value);
+ mappings.add_mapping(entry.string, make_integer_range_set(rs));
+ } else {
+ integer_range_set rs;
+ rs.add_range(entry.start.value, entry.end.value);
+ mappings.add_mapping(entry.string, make_integer_range_set(rs));
}
}
}
- nesting--;
- sanitize_ctf_identifier(identifier, field_name);
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session, "} _%s;\n",
- identifier);
-end:
- (*iter_field)++;
- return ret;
+
+ return make_fixed_length_enumeration_field_class(
+ is_signed, bits(container.size),
+ get_byte_order(session, container.reverse_byte_order),
+ bits(container.alignment), int_to_display_base(container.base),
+ std::move(mappings));
}
static
-int _lttng_variant_statedump(struct ust_registry_session *session,
- uint32_t nr_choices, const char *tag_name,
- uint32_t alignment,
- const struct lttng_ust_ctl_field *fields, size_t nr_fields,
- size_t *iter_field, size_t nesting)
-{
- const struct lttng_ust_ctl_field *variant = &fields[*iter_field];
- uint32_t i;
- int ret;
- char identifier[LTTNG_UST_ABI_SYM_NAME_LEN];
+void make_ust_field_class(const ust_registry_session &session,
+ lttng_ust_ctl_field_iterator &field_iterator,
+ field_path ¤t_field_path,
+ std::function<void(const char *, json)> add_field,
+ std::function<const json &(const char *)> get_last_field);
- if (variant->type.atype != lttng_ust_ctl_atype_variant) {
- ret = -EINVAL;
- goto end;
- }
- (*iter_field)++;
- sanitize_ctf_identifier(identifier, tag_name);
- if (alignment) {
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "struct { } align(%u) _%s_padding;\n",
- alignment * CHAR_BIT,
- variant->name);
- if (ret) {
- goto end;
- }
- }
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "variant <_%s> {\n",
- identifier);
- if (ret) {
- goto end;
- }
+static
+void make_ust_variant_field_class(
+ const ust_registry_session &session,
+ lttng_ust_ctl_field_iterator &field_iterator,
+ field_path ¤t_field_path,
+ const char *field_name,
+ uint32_t nr_options,
+ const char *selector_name,
+ std::function<void(const char *, json)> add_field,
+ std::function<const json &(const char *)> lookup_field)
+{
+ variant_options options;
+ const json &selector_field = lookup_field (selector_name);
+ const json &mappings = selector_field["mappings"];
+
+ auto this_add_field = [&options, &mappings] (const char *option_name, json option_fc) {
+ /* UST prefixes the enumerators with and underscore. */
+ std::string option_name_prefixed = std::string("_") + option_name;
+ const json &ranges = mappings[option_name_prefixed];
+ /*
+ * In CTF 1.8, the variant options were prefixed with an
+ * underscore to match the enumerator names. It is not
+ * necessary to do it in CTF 2, as variant options don't rely
+ * on their names matchin an enumerator name. But do it anyway
+ * to keep the old names, which may help readers migrating from
+ * 1.8 to 2.
+ */
+ options.add_option(std::move(option_name_prefixed), ranges, option_fc);
+ };
- for (i = 0; i < nr_choices; i++) {
- if (*iter_field >= nr_fields) {
- ret = -EOVERFLOW;
- goto end;
- }
- ret = _lttng_field_statedump(session,
- fields, nr_fields,
- iter_field, nesting + 1);
- if (ret) {
- goto end;
+ {
+ auto field_location_popper = current_field_path.push(field_name);
+
+ for (uint32_t i = 0; i < nr_options; i++) {
+ make_ust_field_class(session, field_iterator,
+ current_field_path, this_add_field, lookup_field);
}
}
- sanitize_ctf_identifier(identifier, variant->name);
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "} _%s;\n",
- identifier);
- if (ret) {
- goto end;
- }
-end:
- return ret;
+
+ auto field_location_popper = current_field_path.push(selector_name);
+ add_field(field_name,
+ make_variant_field_class(std::move(options), current_field_path));
}
static
-int _lttng_field_statedump(struct ust_registry_session *session,
- const struct lttng_ust_ctl_field *fields, size_t nr_fields,
- size_t *iter_field, size_t nesting)
-{
- int ret = 0;
- const char *bo_be = " byte_order = be;";
- const char *bo_le = " byte_order = le;";
- const char *bo_native = "";
- const char *bo_reverse;
- const struct lttng_ust_ctl_field *field;
-
- if (*iter_field >= nr_fields) {
- ret = -EOVERFLOW;
- goto end;
- }
- field = &fields[*iter_field];
-
- if (session->byte_order == BIG_ENDIAN) {
- bo_reverse = bo_le;
- } else {
- bo_reverse = bo_be;
- }
+void make_ust_field_class(const ust_registry_session &session,
+ lttng_ust_ctl_field_iterator &field_iterator,
+ field_path ¤t_field_path,
+ std::function<void(const char *, json)> add_field,
+ std::function<const json &(const char *)> lookup_field)
+{
+ const lttng_ust_ctl_field &field = field_iterator.get_next();
- switch (field->type.atype) {
+ switch (field.type.atype) {
case lttng_ust_ctl_atype_integer:
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s;\n",
- field->type.u.integer.size,
- field->type.u.integer.alignment,
- field->type.u.integer.signedness,
- (field->type.u.integer.encoding == lttng_ust_ctl_encode_none)
- ? "none"
- : (field->type.u.integer.encoding == lttng_ust_ctl_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- field->type.u.integer.base,
- field->type.u.integer.reverse_byte_order ? bo_reverse : bo_native,
- field->name);
- (*iter_field)++;
+ add_field(field.name,
+ make_ust_integer_field_class(session,
+ field.type.u.integer));
break;
+
case lttng_ust_ctl_atype_enum:
- ret = ust_metadata_enum_statedump(session,
- field->type.u.legacy.basic.enumeration.name,
- field->type.u.legacy.basic.enumeration.id,
- &field->type.u.legacy.basic.enumeration.container_type,
- field->name, iter_field, nesting);
+ {
+ const auto &enumeration = field.type.u.legacy.basic.enumeration;
+ add_field(field.name,
+ make_ust_enum_field_class(session,
+ enumeration.name, enumeration.id,
+ enumeration.container_type));
break;
+ }
+
case lttng_ust_ctl_atype_float:
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "floating_point { exp_dig = %u; mant_dig = %u; align = %u;%s } _%s;\n",
- field->type.u._float.exp_dig,
- field->type.u._float.mant_dig,
- field->type.u._float.alignment,
- field->type.u._float.reverse_byte_order ? bo_reverse : bo_native,
- field->name);
- (*iter_field)++;
+ {
+ const lttng_ust_ctl_float_type &t = field.type.u._float;
+
+ add_field(field.name,
+ make_fixed_length_floating_point_number_field_class(
+ bits(t.exp_dig + t.mant_dig),
+ get_byte_order(session, t.reverse_byte_order), bits(t.alignment)));
+
break;
+ }
+
case lttng_ust_ctl_atype_array:
{
- const struct lttng_ust_ctl_basic_type *elem_type;
+ const auto &array_type = field.type.u.legacy.array;
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- elem_type = &field->type.u.legacy.array.elem_type;
/* Only integers are currently supported in arrays. */
- if (elem_type->atype != lttng_ust_ctl_atype_integer) {
- ret = -EINVAL;
- goto end;
+ if (array_type.elem_type.atype != lttng_ust_ctl_atype_integer) {
+ throw metadata_generation_exception(
+ "array element type not supported");
}
- ret = lttng_metadata_printf(session,
- "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n",
- elem_type->u.basic.integer.size,
- elem_type->u.basic.integer.alignment,
- elem_type->u.basic.integer.signedness,
- (elem_type->u.basic.integer.encoding == lttng_ust_ctl_encode_none)
- ? "none"
- : (elem_type->u.basic.integer.encoding == lttng_ust_ctl_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- elem_type->u.basic.integer.base,
- elem_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
- field->name, field->type.u.legacy.array.length);
- (*iter_field)++;
+
+ add_field(field.name, make_static_length_array_field_class(
+ make_ust_integer_field_class(
+ session, array_type.elem_type.u.basic.integer),
+ array_type.length, 0_bits));
+
break;
}
+
case lttng_ust_ctl_atype_array_nestable:
{
- uint32_t array_length;
- const struct lttng_ust_ctl_field *array_nestable;
- const struct lttng_ust_ctl_type *elem_type;
-
- array_length = field->type.u.array_nestable.length;
- (*iter_field)++;
-
- if (*iter_field >= nr_fields) {
- ret = -EOVERFLOW;
- goto end;
- }
- array_nestable = &fields[*iter_field];
- elem_type = &array_nestable->type;
+ const struct lttng_ust_ctl_type &element_type =
+ field_iterator.get_next().type;
/* Only integers are currently supported in arrays. */
- if (elem_type->atype != lttng_ust_ctl_atype_integer) {
- ret = -EINVAL;
- goto end;
+ if (element_type.atype != lttng_ust_ctl_atype_integer) {
+ throw metadata_generation_exception(
+ "array element type not supported");
}
- if (field->type.u.array_nestable.alignment) {
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "struct { } align(%u) _%s_padding;\n",
- field->type.u.array_nestable.alignment * CHAR_BIT,
- field->name);
- if (ret) {
- goto end;
- }
- }
+ const auto &array_type = field.type.u.array_nestable;
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n",
- elem_type->u.integer.size,
- elem_type->u.integer.alignment,
- elem_type->u.integer.signedness,
- (elem_type->u.integer.encoding == lttng_ust_ctl_encode_none)
- ? "none"
- : (elem_type->u.integer.encoding == lttng_ust_ctl_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- elem_type->u.integer.base,
- elem_type->u.integer.reverse_byte_order ? bo_reverse : bo_native,
- field->name, array_length);
- (*iter_field)++;
+ /* The array alignment value we receive is in bytes. */
+ add_field(field.name,
+ make_static_length_array_field_class(
+ make_ust_integer_field_class(
+ session, element_type.u.integer),
+ array_type.length, bits(array_type.alignment * 8)));
break;
}
+
case lttng_ust_ctl_atype_sequence:
{
- const struct lttng_ust_ctl_basic_type *elem_type;
- const struct lttng_ust_ctl_basic_type *length_type;
-
- elem_type = &field->type.u.legacy.sequence.elem_type;
- length_type = &field->type.u.legacy.sequence.length_type;
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
+ const auto &t = field.type.u.legacy.sequence;
/* Only integers are currently supported in sequences. */
- if (elem_type->atype != lttng_ust_ctl_atype_integer) {
- ret = -EINVAL;
- goto end;
+ if (t.elem_type.atype != lttng_ust_ctl_atype_integer) {
+ throw metadata_generation_exception(
+ "sequence element type not supported");
}
- ret = lttng_metadata_printf(session,
- "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n",
- length_type->u.basic.integer.size,
- (unsigned int) length_type->u.basic.integer.alignment,
- length_type->u.basic.integer.signedness,
- (length_type->u.basic.integer.encoding == lttng_ust_ctl_encode_none)
- ? "none"
- : ((length_type->u.basic.integer.encoding == lttng_ust_ctl_encode_UTF8)
- ? "UTF8"
- : "ASCII"),
- length_type->u.basic.integer.base,
- length_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
- field->name);
- if (ret) {
- goto end;
- }
+ const lttng_ust_ctl_integer_type &length_type
+ = t.length_type.u.basic.integer;
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[ __%s_length ];\n",
- elem_type->u.basic.integer.size,
- (unsigned int) elem_type->u.basic.integer.alignment,
- elem_type->u.basic.integer.signedness,
- (elem_type->u.basic.integer.encoding == lttng_ust_ctl_encode_none)
- ? "none"
- : ((elem_type->u.basic.integer.encoding == lttng_ust_ctl_encode_UTF8)
- ? "UTF8"
- : "ASCII"),
- elem_type->u.basic.integer.base,
- elem_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
- field->name,
- field->name);
- (*iter_field)++;
+ std::stringstream sstream;
+ sstream << "__" << field.name << "_length";
+ add_field(sstream.str().c_str(),
+ make_ust_integer_field_class(session, length_type));
+
+ auto popper = current_field_path.push(sstream.str().c_str());
+ add_field(field.name,
+ make_dynamic_length_array_field_class(
+ make_ust_integer_field_class(
+ session, t.elem_type.u.basic.integer),
+ current_field_path, 0_bits));
break;
}
case lttng_ust_ctl_atype_sequence_nestable:
{
- const struct lttng_ust_ctl_field *sequence_nestable;
- const struct lttng_ust_ctl_type *elem_type;
-
- (*iter_field)++;
- if (*iter_field >= nr_fields) {
- ret = -EOVERFLOW;
- goto end;
- }
- sequence_nestable = &fields[*iter_field];
- elem_type = &sequence_nestable->type;
+ const struct lttng_ust_ctl_type &element_type =
+ field_iterator.get_next().type;
/* Only integers are currently supported in sequences. */
- if (elem_type->atype != lttng_ust_ctl_atype_integer) {
- ret = -EINVAL;
- goto end;
+ if (element_type.atype != lttng_ust_ctl_atype_integer) {
+ throw metadata_generation_exception(
+ "sequence element type not supported");
}
- if (field->type.u.sequence_nestable.alignment) {
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "struct { } align(%u) _%s_padding;\n",
- field->type.u.sequence_nestable.alignment * CHAR_BIT,
- field->name);
- if (ret) {
- goto end;
- }
- }
-
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[ _%s ];\n",
- elem_type->u.integer.size,
- (unsigned int) elem_type->u.integer.alignment,
- elem_type->u.integer.signedness,
- (elem_type->u.integer.encoding == lttng_ust_ctl_encode_none)
- ? "none"
- : ((elem_type->u.integer.encoding == lttng_ust_ctl_encode_UTF8)
- ? "UTF8"
- : "ASCII"),
- elem_type->u.integer.base,
- elem_type->u.integer.reverse_byte_order ? bo_reverse : bo_native,
- field->name,
- field->type.u.sequence_nestable.length_name);
- (*iter_field)++;
+ const auto &array_type = field.type.u.sequence_nestable;
+ auto popper = current_field_path.push(
+ array_type.length_name);
+
+ /* The array alignment value we receive is in bytes. */
+ add_field(field.name,
+ make_dynamic_length_array_field_class(
+ make_ust_integer_field_class(
+ session, element_type.u.integer),
+ current_field_path,
+ bits(array_type.alignment * 8)));
break;
}
+
case lttng_ust_ctl_atype_string:
- /* Default encoding is UTF8 */
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "string%s _%s;\n",
- field->type.u.string.encoding == lttng_ust_ctl_encode_ASCII ?
- " { encoding = ASCII; }" : "",
- field->name);
- (*iter_field)++;
+ add_field(field.name, make_string_field_class());
break;
+
case lttng_ust_ctl_atype_variant:
- ret = _lttng_variant_statedump(session,
- field->type.u.legacy.variant.nr_choices,
- field->type.u.legacy.variant.tag_name,
- 0,
- fields, nr_fields, iter_field, nesting);
- if (ret) {
- goto end;
- }
+ {
+ const decltype(field.type.u.legacy.variant) &variant_type =
+ field.type.u.legacy.variant;
+
+ make_ust_variant_field_class(session, field_iterator,
+ current_field_path, field.name, variant_type.nr_choices,
+ variant_type.tag_name, add_field, lookup_field);
break;
+ }
+
case lttng_ust_ctl_atype_variant_nestable:
- ret = _lttng_variant_statedump(session,
- field->type.u.variant_nestable.nr_choices,
- field->type.u.variant_nestable.tag_name,
- field->type.u.variant_nestable.alignment,
- fields, nr_fields, iter_field, nesting);
- if (ret) {
- goto end;
- }
+ {
+ const decltype(field.type.u.variant_nestable) &variant_type =
+ field.type.u.variant_nestable;
+
+ make_ust_variant_field_class(session, field_iterator,
+ current_field_path, field.name, variant_type.nr_choices,
+ variant_type.tag_name, add_field, lookup_field);
break;
+ }
+
case lttng_ust_ctl_atype_struct:
- if (field->type.u.legacy._struct.nr_fields != 0) {
+ if (field.type.u.legacy._struct.nr_fields != 0) {
/* Currently only 0-length structures are supported. */
- ret = -EINVAL;
- goto end;
+ throw metadata_generation_exception("Only 0-length structures are supported");
}
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- ret = lttng_metadata_printf(session,
- "struct {} _%s;\n",
- field->name);
- (*iter_field)++;
+
+ /* Don't emit anything */
break;
+
case lttng_ust_ctl_atype_struct_nestable:
- if (field->type.u.struct_nestable.nr_fields != 0) {
+ if (field.type.u.struct_nestable.nr_fields != 0) {
/* Currently only 0-length structures are supported. */
- ret = -EINVAL;
- goto end;
- }
- ret = print_tabs(session, nesting);
- if (ret) {
- goto end;
- }
- if (field->type.u.struct_nestable.alignment) {
- ret = lttng_metadata_printf(session,
- "struct {} align(%u) _%s;\n",
- field->type.u.struct_nestable.alignment * CHAR_BIT,
- field->name);
- if (ret) {
- goto end;
- }
- } else {
- ret = lttng_metadata_printf(session,
- "struct {} _%s;\n",
- field->name);
+ throw metadata_generation_exception("Only 0-length structures are supported");
}
- (*iter_field)++;
+
+ /* Don't emit anything */
break;
+
case lttng_ust_ctl_atype_enum_nestable:
{
- const struct lttng_ust_ctl_field *container_field;
- const struct lttng_ust_ctl_type *container_type;
-
- (*iter_field)++;
- if (*iter_field >= nr_fields) {
- ret = -EOVERFLOW;
- goto end;
- }
- container_field = &fields[*iter_field];
- container_type = &container_field->type;
+ const lttng_ust_ctl_field &container =
+ field_iterator.get_next();
/* Only integers are supported as container types. */
- if (container_type->atype != lttng_ust_ctl_atype_integer) {
- ret = -EINVAL;
- goto end;
+ if (container.type.atype != lttng_ust_ctl_atype_integer) {
+ throw metadata_generation_exception(
+ "Enumeration container type not an integer");
}
- ret = ust_metadata_enum_statedump(session,
- field->type.u.enum_nestable.name,
- field->type.u.enum_nestable.id,
- &container_type->u.integer,
- field->name, iter_field, nesting);
+
+ const auto &enumeration = field.type.u.enum_nestable;
+ add_field(field.name,
+ make_ust_enum_field_class(session,
+ enumeration.name, enumeration.id,
+ container.type.u.integer));
break;
}
default:
- ret = -EINVAL;
+ throw metadata_generation_exception(
+ "Unhandled lttng-ust field type");
}
-end:
- return ret;
}
static
-int _lttng_context_metadata_statedump(struct ust_registry_session *session,
- size_t nr_ctx_fields,
- struct lttng_ust_ctl_field *ctx)
+json make_record_common_context_field_class(
+ const ust_registry_session &session,
+ const ust_registry_channel &chan)
{
- int ret = 0;
- size_t i = 0;
+ lttng_ust_ctl_field_iterator iter(chan.ctx_fields, chan.nr_ctx_fields);
+ field_path fp("event-record-common-context");
+ structure_members members;
- if (!ctx)
- return 0;
- for (;;) {
- if (i >= nr_ctx_fields) {
- break;
- }
- ret = _lttng_field_statedump(session, ctx,
- nr_ctx_fields, &i, 2);
- if (ret) {
- break;
+ auto add_field = [&members] (const char *name, json field_class) {
+ members.add_member(name, field_class);
+ };
+
+ auto lookup_field = [&members] (const char *name) -> const json & {
+ for (const structure_member &member : members) {
+ if (strcmp(member.name, name) == 0) {
+ return member.field_class;
+ }
}
+
+ throw metadata_generation_exception("failed to look up field");
+ };
+
+ while (!iter.done()) {
+ make_ust_field_class(session, iter, fp, add_field,
+ lookup_field);
}
- return ret;
+
+ return make_structure_field_class(0_bits, std::move(members));
}
static
-int _lttng_fields_metadata_statedump(struct ust_registry_session *session,
- struct ust_registry_event *event)
+json make_event_record_class_payload_field_class(
+ const ust_registry_session &session,
+ const ust_registry_event &event)
{
- int ret = 0;
- size_t i = 0;
+ lttng_ust_ctl_field_iterator iter(event.fields, event.nr_fields);
+ field_path fp("event-record-payload");
+ structure_members members;
- for (;;) {
- if (i >= event->nr_fields) {
- break;
- }
- ret = _lttng_field_statedump(session, event->fields,
- event->nr_fields, &i, 2);
- if (ret) {
- break;
+ auto add_field = [&members] (const char *name, json field_class) {
+ members.add_member(name, field_class);
+ };
+
+ auto lookup_field = [&members] (const char *name) {
+ for (const structure_member &member : members) {
+ if (strcmp(member.name, name) == 0) {
+ return member.field_class;
+ }
}
+
+ throw metadata_generation_exception("failed to look up field");
+ };
+
+ while (!iter.done()) {
+ make_ust_field_class(session, iter, fp, add_field,
+ lookup_field);
}
- return ret;
+
+ return make_structure_field_class(0_bits, std::move(members));
+}
+
+static
+json make_user_attributes(json attributes)
+{
+ return {
+ { "lttng.org,2009", attributes }
+ };
+}
+
+static
+json make_event_record_class_user_attributes(const ust_registry_event &event)
+{
+ json user_attributes = make_user_attributes({
+ { "log-level", event.loglevel_value },
+ });
+
+ if (event.model_emf_uri) {
+ user_attributes["emf-uri"] = event.model_emf_uri;
+ }
+
+ return user_attributes;
}
/*
struct ust_registry_channel *chan,
struct ust_registry_event *event)
{
- int ret = 0;
-
/* Don't dump metadata events */
if (chan->chan_id == -1U)
return 0;
- ret = lttng_metadata_printf(session,
- "event {\n"
- " name = \"%s\";\n"
- " id = %u;\n"
- " stream_id = %u;\n",
- event->name,
- event->id,
- chan->chan_id);
- if (ret) {
- goto end;
+ /*
+ * We don't want to output an event's metadata before its parent
+ * stream's metadata. If the stream's metadata hasn't been output yet,
+ * skip this event. Its metadata will be output when we output the
+ * stream's metadata.
+ */
+ if (!chan->metadata_dumped) {
+ return 0;
}
- ret = lttng_metadata_printf(session,
- " loglevel = %d;\n",
- event->loglevel_value);
- if (ret) {
- goto end;
- }
+ LTTNG_ASSERT(!event->metadata_dumped);
+
+ try {
+ json event_record_class = make_fragment("event-record-class");
+ event_record_class.update({
+ { "name", event->name },
+ { "id", event->id },
+ { "data-stream-class-id", chan->chan_id },
+ { "user-attributes", make_event_record_class_user_attributes(*event) },
+ });
- if (event->model_emf_uri) {
- ret = lttng_metadata_printf(session,
- " model.emf.uri = \"%s\";\n",
- event->model_emf_uri);
- if (ret) {
- goto end;
+ if (event->nr_fields) {
+ event_record_class["payload-field-class"] =
+ make_event_record_class_payload_field_class(*session, *event);
}
- }
- ret = lttng_metadata_printf(session,
- " fields := struct {\n"
- );
- if (ret) {
- goto end;
- }
+ lttng_metadata_print_fragment(*session, event_record_class);
- ret = _lttng_fields_metadata_statedump(session, event);
- if (ret) {
- goto end;
- }
+ event->metadata_dumped = 1;
- ret = lttng_metadata_printf(session,
- " };\n"
- "};\n\n");
- if (ret) {
- goto end;
+ return 0;
+ } catch (const std::exception &error) {
+ ERR("%s", error.what());
+ return -LTTNG_ERR_UNK;
+ } catch (...) {
+ return -LTTNG_ERR_UNK;
}
- event->metadata_dumped = 1;
+}
-end:
- return ret;
+static
+json make_packet_context_field_class(const ust_registry_session &session)
+{
+ byte_order bo = get_byte_order(session, false);
+ structure_members members;
+
+ members.add_member("timestamp_begin",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "packet-beginning-default-clock-timestamp"));
+ members.add_member("timestamp_end",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "packet-end-default-clock-timestamp"));
+ members.add_member("content_size",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "packet-content-size"));
+ members.add_member("packet_size",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "packet-total-size"));
+ members.add_member("packet_seq_num",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "packet-sequence-number"));
+ members.add_member("events_discarded",
+ make_fixed_length_unsigned_integer_field_class(
+ bits(session.bits_per_long), bo,
+ bits(session.long_alignment),
+ display_base::DECIMAL,
+ "discarded-event-record-counter-snapshot"));
+ members.add_member("cpu_id",
+ make_fixed_length_unsigned_integer_field_class(
+ 32_bits, bo, 8_bits, display_base::DECIMAL, nullptr));
+
+ return make_structure_field_class(0_bits, std::move(members));
+}
+
+static
+json make_record_header_compact_field_class(const ust_registry_session &session)
+{
+ byte_order bo = get_byte_order(session, false);
+
+ structure_members compact_members;
+ compact_members.add_member("timestamp",
+ make_fixed_length_unsigned_integer_field_class(
+ 27_bits, bo, 1_bits, display_base::DECIMAL,
+ "default-clock-timestamp"));
+
+ structure_members extended_members;
+ extended_members.add_member("id",
+ make_fixed_length_unsigned_integer_field_class(
+ 32_bits, bo, 8_bits, display_base::DECIMAL,
+ "event-record-class-id"));
+ extended_members.add_member("timestamp",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "default-clock-timestamp"));
+
+ integer_range_set compact_ranges, extended_ranges;
+ compact_ranges.add_range(UINT64_C(0), 30);
+ extended_ranges.add_range(UINT64_C(31), 31);
+
+ variant_options options;
+ options.add_option("compact",
+ make_integer_range_set(compact_ranges),
+ make_structure_field_class(0_bits, std::move(compact_members)));
+ options.add_option("extended",
+ make_integer_range_set(extended_ranges),
+ make_structure_field_class(0_bits, std::move(extended_members)));
+
+ enumeration_mappings id_mappings;
+ id_mappings.add_mapping("compact",
+ make_integer_range_set(compact_ranges));
+ id_mappings.add_mapping("extended",
+ make_integer_range_set(extended_ranges));
+
+ structure_members members;
+ members.add_member("id",
+ make_fixed_length_unsigned_enumeration_field_class(
+ 5_bits, bo, 8_bits, display_base::DECIMAL,
+ "event-record-class-id", std::move(id_mappings)));
+ members.add_member("v",
+ make_variant_field_class(std::move(options),
+ {"event-record-header", "id"}));
+
+ return make_structure_field_class(8_bits, std::move(members));
+}
+
+static
+json make_record_header_large_field_class(const ust_registry_session &session)
+{
+ byte_order bo = get_byte_order(session, false);
+
+ structure_members compact_members;
+ compact_members.add_member("timestamp",
+ make_fixed_length_unsigned_integer_field_class(
+ 32_bits, bo, 8_bits, display_base::DECIMAL,
+ "default-clock-timestamp"));
+
+ structure_members extended_members;
+ extended_members.add_member("id",
+ make_fixed_length_unsigned_integer_field_class(
+ 32_bits, bo, 8_bits, display_base::DECIMAL,
+ "event-record-class-id"));
+ extended_members.add_member("timestamp",
+ make_fixed_length_unsigned_integer_field_class(
+ 64_bits, bo, 8_bits, display_base::DECIMAL,
+ "default-clock-timestamp"));
+
+ integer_range_set compact_ranges, extended_ranges;
+ compact_ranges.add_range(UINT64_C(0), 65534);
+ extended_ranges.add_range(UINT64_C(65535), 65535);
+
+ variant_options options;
+ options.add_option("compact",
+ make_integer_range_set(compact_ranges),
+ make_structure_field_class(0_bits, std::move(compact_members)));
+ options.add_option("extended",
+ make_integer_range_set(extended_ranges),
+ make_structure_field_class(0_bits, std::move(extended_members)));
+
+ enumeration_mappings id_mappings;
+ id_mappings.add_mapping("compact",
+ make_integer_range_set(compact_ranges));
+ id_mappings.add_mapping("extended",
+ make_integer_range_set(extended_ranges));
+
+ structure_members members;
+ members.add_member("id",
+ make_fixed_length_unsigned_enumeration_field_class(
+ 16_bits, bo, 8_bits, display_base::DECIMAL,
+ "event-record-class-id", std::move(id_mappings)));
+ members.add_member("v",
+ make_variant_field_class(std::move(options),
+ { "event-record-header", "id" }));
+
+ return make_structure_field_class(8_bits, std::move(members));
+}
+
+static
+json make_record_header_field_class(const ust_registry_session &session,
+ const ust_registry_channel &chan)
+{
+ if (chan.header_type == LTTNG_UST_CTL_CHANNEL_HEADER_COMPACT) {
+ return make_record_header_compact_field_class(session);
+ } else {
+ return make_record_header_large_field_class(session);
+ }
}
/*
int ust_metadata_channel_statedump(struct ust_registry_session *session,
struct ust_registry_channel *chan)
{
- int ret = 0;
-
/* Don't dump metadata events */
if (chan->chan_id == -1U)
return 0;
if (!chan->header_type)
return -EINVAL;
- ret = lttng_metadata_printf(session,
- "stream {\n"
- " id = %u;\n"
- " event.header := %s;\n"
- " packet.context := struct packet_context;\n",
- chan->chan_id,
- chan->header_type == LTTNG_UST_CTL_CHANNEL_HEADER_COMPACT ?
- "struct event_header_compact" :
- "struct event_header_large");
- if (ret) {
- goto end;
- }
-
- if (chan->ctx_fields) {
- ret = lttng_metadata_printf(session,
- " event.context := struct {\n");
- if (ret) {
- goto end;
- }
- }
- ret = _lttng_context_metadata_statedump(session,
- chan->nr_ctx_fields,
- chan->ctx_fields);
- if (ret) {
- goto end;
- }
- if (chan->ctx_fields) {
- ret = lttng_metadata_printf(session,
- " };\n");
- if (ret) {
- goto end;
+ try {
+ json data_stream_class = make_fragment("data-stream-class");
+ data_stream_class.update({
+ { "id", chan->chan_id },
+ { "packet-context-field-class",
+ make_packet_context_field_class(*session) },
+ { "event-record-header-field-class",
+ make_record_header_field_class(*session, *chan) },
+ });
+
+ if (chan->ctx_fields) {
+ data_stream_class.update({
+ { "event-record-common-context-field-class",
+ make_record_common_context_field_class(*session, *chan) }
+ });
}
- }
- ret = lttng_metadata_printf(session,
- "};\n\n");
- /* Flag success of metadata dump. */
- chan->metadata_dumped = 1;
+ lttng_metadata_print_fragment(*session, data_stream_class);
-end:
- return ret;
-}
+ /* Flag success of metadata dump. */
+ chan->metadata_dumped = 1;
-static
-int _lttng_stream_packet_context_declare(struct ust_registry_session *session)
-{
- return lttng_metadata_printf(session,
- "struct packet_context {\n"
- " uint64_clock_monotonic_t timestamp_begin;\n"
- " uint64_clock_monotonic_t timestamp_end;\n"
- " uint64_t content_size;\n"
- " uint64_t packet_size;\n"
- " uint64_t packet_seq_num;\n"
- " unsigned long events_discarded;\n"
- " uint32_t cpu_id;\n"
- "};\n\n"
- );
-}
+ /*
+ * Output the metadata of any existing event.
+ *
+ * Sort the events by id. This is not necessary, but it's nice to have
+ * a more predictable order in the metadata file.
+ */
+ std::vector<ust_registry_event *> events;
+ {
+ cds_lfht_iter event_iter;
+ ust_registry_event *event;
+ cds_lfht_for_each_entry(chan->events->ht, &event_iter, event,
+ node.node) {
+ events.push_back(event);
+ }
+ }
-/*
- * Compact header:
- * id: range: 0 - 30.
- * id 31 is reserved to indicate an extended header.
- *
- * Large header:
- * id: range: 0 - 65534.
- * id 65535 is reserved to indicate an extended header.
- */
-static
-int _lttng_event_header_declare(struct ust_registry_session *session)
-{
- return lttng_metadata_printf(session,
- "struct event_header_compact {\n"
- " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
- " variant <id> {\n"
- " struct {\n"
- " uint27_clock_monotonic_t timestamp;\n"
- " } compact;\n"
- " struct {\n"
- " uint32_t id;\n"
- " uint64_clock_monotonic_t timestamp;\n"
- " } extended;\n"
- " } v;\n"
- "} align(%u);\n"
- "\n"
- "struct event_header_large {\n"
- " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n"
- " variant <id> {\n"
- " struct {\n"
- " uint32_clock_monotonic_t timestamp;\n"
- " } compact;\n"
- " struct {\n"
- " uint32_t id;\n"
- " uint64_clock_monotonic_t timestamp;\n"
- " } extended;\n"
- " } v;\n"
- "} align(%u);\n\n",
- session->uint32_t_alignment,
- session->uint16_t_alignment
- );
+ std::sort(events.begin(), events.end(),
+ [] (ust_registry_event *a, ust_registry_event *b) {
+ return a->id < b->id;
+ });
+
+ for (ust_registry_event *event : events) {
+ ust_metadata_event_statedump(session, chan, event);
+ }
+
+ return 0;
+ } catch (const std::exception &error) {
+ ERR("%s", error.what());
+ return -LTTNG_ERR_UNK;
+ } catch (...) {
+ return -LTTNG_ERR_UNK;
+ }
}
/*
return offset_best_sample.offset;
}
-static
-int print_metadata_session_information(struct ust_registry_session *registry)
-{
- int ret;
- struct ltt_session *session = NULL;
- char creation_datetime[ISO8601_STR_LEN];
-
- rcu_read_lock();
- session = session_find_by_id(registry->tracing_id);
- if (!session) {
- ret = -1;
- goto error;
- }
-
- /* Print the trace name */
- ret = lttng_metadata_printf(registry, " trace_name = \"");
- if (ret) {
- goto error;
- }
-
- /*
- * This is necessary since the creation time is present in the session
- * name when it is generated.
- */
- if (session->has_auto_generated_name) {
- ret = print_escaped_ctf_string(registry, DEFAULT_SESSION_NAME);
- } else {
- ret = print_escaped_ctf_string(registry, session->name);
- }
- if (ret) {
- goto error;
- }
-
- ret = lttng_metadata_printf(registry, "\";\n");
- if (ret) {
- goto error;
- }
-
- /* Prepare creation time */
- ret = time_to_iso8601_str(session->creation_time, creation_datetime,
- sizeof(creation_datetime));
- if (ret) {
- goto error;
- }
-
- /* Output the reste of the information */
- ret = lttng_metadata_printf(registry,
- " trace_creation_datetime = \"%s\";\n"
- " hostname = \"%s\";\n",
- creation_datetime, session->hostname);
- if (ret) {
- goto error;
- }
-
-error:
- if (session) {
- session_put(session);
- }
- rcu_read_unlock();
- return ret;
-}
-
-static
-int print_metadata_app_information(struct ust_registry_session *registry,
- struct ust_app *app)
-{
- int ret;
- char datetime[ISO8601_STR_LEN];
-
- if (!app) {
- ret = 0;
- goto end;
- }
-
- ret = time_to_iso8601_str(
- app->registration_time, datetime, sizeof(datetime));
- if (ret) {
- goto end;
- }
-
- ret = lttng_metadata_printf(registry,
- " tracer_patchlevel = %u;\n"
- " vpid = %d;\n"
- " procname = \"%s\";\n"
- " vpid_datetime = \"%s\";\n",
- app->version.patchlevel, (int) app->pid, app->name,
- datetime);
-
-end:
- return ret;
-}
-
/*
* Should be called with session registry mutex held.
*/
uint32_t major,
uint32_t minor)
{
- char uuid_s[LTTNG_UUID_STR_LEN],
- clock_uuid_s[LTTNG_UUID_STR_LEN];
- int ret = 0;
-
LTTNG_ASSERT(session);
- lttng_uuid_to_str(session->uuid, uuid_s);
-
- /* For crash ABI */
- ret = lttng_metadata_printf(session,
- "/* CTF %u.%u */\n\n",
- CTF_SPEC_MAJOR,
- CTF_SPEC_MINOR);
- if (ret) {
- goto end;
- }
-
- ret = lttng_metadata_printf(session,
- "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n"
- "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n"
- "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n"
- "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n"
- "typealias integer { size = %u; align = %u; signed = false; } := unsigned long;\n"
- "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
- "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n"
- "\n"
- "trace {\n"
- " major = %u;\n"
- " minor = %u;\n"
- " uuid = \"%s\";\n"
- " byte_order = %s;\n"
- " packet.header := struct {\n"
- " uint32_t magic;\n"
- " uint8_t uuid[16];\n"
- " uint32_t stream_id;\n"
- " uint64_t stream_instance_id;\n"
- " };\n"
- "};\n\n",
- session->uint8_t_alignment,
- session->uint16_t_alignment,
- session->uint32_t_alignment,
- session->uint64_t_alignment,
- session->bits_per_long,
- session->long_alignment,
- CTF_SPEC_MAJOR,
- CTF_SPEC_MINOR,
- uuid_s,
- session->byte_order == BIG_ENDIAN ? "be" : "le"
- );
- if (ret) {
- goto end;
- }
-
- ret = lttng_metadata_printf(session,
- "env {\n"
- " domain = \"ust\";\n"
- " tracer_name = \"lttng-ust\";\n"
- " tracer_major = %u;\n"
- " tracer_minor = %u;\n"
- " tracer_buffering_scheme = \"%s\";\n"
- " tracer_buffering_id = %u;\n"
- " architecture_bit_width = %u;\n",
- major,
- minor,
- app ? "pid" : "uid",
- app ? (int) app->pid : (int) session->tracing_uid,
- session->bits_per_long);
- if (ret) {
- goto end;
- }
-
- ret = print_metadata_session_information(session);
- if (ret) {
- goto end;
- }
-
- /*
- * If per-application registry, we can output extra information
- * about the application.
- */
- ret = print_metadata_app_information(session, app);
- if (ret) {
- goto end;
- }
-
- ret = lttng_metadata_printf(session,
- "};\n\n"
- );
- if (ret) {
- goto end;
- }
-
- ret = lttng_metadata_printf(session,
- "clock {\n"
- " name = \"%s\";\n",
- trace_clock_name()
- );
- if (ret) {
- goto end;
- }
-
- if (!trace_clock_uuid(clock_uuid_s)) {
- ret = lttng_metadata_printf(session,
- " uuid = \"%s\";\n",
- clock_uuid_s
- );
- if (ret) {
- goto end;
+ try {
+ json preamble = make_fragment("preamble");
+ preamble.update({
+ { "version", 2 },
+ });
+ lttng_metadata_print_fragment(*session, preamble);
+
+ json trace_class = make_fragment("trace-class");
+ trace_class.update({
+ { "packet-header-field-class",
+ make_packet_header_field_class(*session) },
+ { "uuid", make_uuid (session->uuid) }
+ });
+ lttng_metadata_print_fragment(*session, trace_class);
+
+ uint64_t clock_freq = trace_clock_freq();
+ json clock_class = make_fragment("clock-class");
+ clock_class.update({
+ { "name", trace_clock_name() },
+ { "description", trace_clock_description() },
+ { "frequency", clock_freq },
+ { "offset", make_clock_offset(measure_clock_offset(), clock_freq) },
+ });
+
+ char clock_uuid_str[LTTNG_UUID_STR_LEN];
+ int ret = trace_clock_uuid(clock_uuid_str);
+ if (ret == 0) {
+ uint8_t clock_uuid[LTTNG_UUID_LEN];
+ ret = lttng_uuid_from_str(clock_uuid_str, clock_uuid);
+ if (ret == 0) {
+ clock_class["uuid"] = make_uuid(clock_uuid);
+ } else {
+ // FIXME: warn?
+ }
+ } else {
+ // FIXME: warn?
}
- }
-
- ret = lttng_metadata_printf(session,
- " description = \"%s\";\n"
- " freq = %" PRIu64 "; /* Frequency, in Hz */\n"
- " /* clock value offset from Epoch is: offset * (1/freq) */\n"
- " offset = %" PRId64 ";\n"
- "};\n\n",
- trace_clock_description(),
- trace_clock_freq(),
- measure_clock_offset()
- );
- if (ret) {
- goto end;
- }
-
- ret = lttng_metadata_printf(session,
- "typealias integer {\n"
- " size = 27; align = 1; signed = false;\n"
- " map = clock.%s.value;\n"
- "} := uint27_clock_monotonic_t;\n"
- "\n"
- "typealias integer {\n"
- " size = 32; align = %u; signed = false;\n"
- " map = clock.%s.value;\n"
- "} := uint32_clock_monotonic_t;\n"
- "\n"
- "typealias integer {\n"
- " size = 64; align = %u; signed = false;\n"
- " map = clock.%s.value;\n"
- "} := uint64_clock_monotonic_t;\n\n",
- trace_clock_name(),
- session->uint32_t_alignment,
- trace_clock_name(),
- session->uint64_t_alignment,
- trace_clock_name()
- );
- if (ret) {
- goto end;
- }
- ret = _lttng_stream_packet_context_declare(session);
- if (ret) {
- goto end;
- }
+ lttng_metadata_print_fragment(*session, clock_class);
- ret = _lttng_event_header_declare(session);
- if (ret) {
- goto end;
+ return 0;
+ } catch (const std::exception &error) {
+ ERR("%s", error.what());
+ return -LTTNG_ERR_UNK;
+ } catch (...) {
+ return -LTTNG_ERR_UNK;
}
-
-end:
- return ret;
}