Move CTF 1.8 metadata generation to its own file
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Thu, 9 Dec 2021 21:56:11 +0000 (16:56 -0500)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Fri, 15 Jul 2022 18:02:23 +0000 (14:02 -0400)
Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Change-Id: I6830503d5150f61d69661fe3dd195ed4ccda99b2

src/Kbuild
src/ctf1-8.c [new file with mode: 0644]
src/ctf1-8.h [new file with mode: 0644]
src/lttng-events.c

index 9c84f5d73ec501ff6001645bb333efca3ebaf6fe..4aba1cd7e9dc9de16483e926f1d11557925e6a1d 100644 (file)
@@ -49,6 +49,7 @@ lttng-tracer-objs := lib/msgpack/msgpack.o \
                      lttng-events.o lttng-abi.o lttng-string-utils.o \
                      lttng-probes.o lttng-context.o \
                      metadata-printer.o \
+                     ctf1-8.o \
                      lttng-context-pid.o lttng-context-procname.o \
                      lttng-context-prio.o lttng-context-nice.o \
                      lttng-context-vpid.o lttng-context-tid.o \
diff --git a/src/ctf1-8.c b/src/ctf1-8.c
new file mode 100644 (file)
index 0000000..23eee4d
--- /dev/null
@@ -0,0 +1,1120 @@
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * src/ctf1-8.c
+ *
+ * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ */
+
+#include <linux/dmi.h>
+#include <linux/utsname.h>
+#include <linux/ktime.h>
+#include <linux/timekeeping.h>
+
+#include <lttng/events.h>
+#include <lttng/events-internal.h>
+
+#include <wrapper/time.h>
+#include "metadata-printer.h"
+
+static
+int _lttng_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting, const char **prev_field_name_p);
+
+static
+int _lttng_type_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_type_common *type,
+               enum lttng_kernel_string_encoding parent_encoding,
+               size_t nesting);
+
+static
+int print_tabs(struct lttng_kernel_session *session, size_t nesting)
+{
+       size_t i;
+
+       for (i = 0; i < nesting; i++) {
+               int ret;
+
+               ret = lttng_metadata_printf(session, "  ");
+               if (ret) {
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static
+int lttng_field_name_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting)
+{
+       return lttng_metadata_printf(session, " _%s;\n", field->name);
+}
+
+static
+int _lttng_integer_type_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_type_integer *type,
+               enum lttng_kernel_string_encoding parent_encoding,
+               size_t nesting)
+{
+       int ret;
+
+       ret = print_tabs(session, nesting);
+       if (ret)
+               return ret;
+       ret = lttng_metadata_printf(session,
+               "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s }",
+               type->size,
+               type->alignment,
+               type->signedness,
+               (parent_encoding == lttng_kernel_string_encoding_none)
+                       ? "none"
+                       : (parent_encoding == lttng_kernel_string_encoding_UTF8)
+                               ? "UTF8"
+                               : "ASCII",
+               type->base,
+#if __BYTE_ORDER == __BIG_ENDIAN
+               type->reverse_byte_order ? " byte_order = le;" : ""
+#else
+               type->reverse_byte_order ? " byte_order = be;" : ""
+#endif
+       );
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_struct_type_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_type_struct *type,
+               size_t nesting)
+{
+       const char *prev_field_name = NULL;
+       int ret;
+       uint32_t i, nr_fields;
+       unsigned int alignment;
+
+       ret = print_tabs(session, nesting);
+       if (ret)
+               return ret;
+       ret = lttng_metadata_printf(session,
+               "struct {\n");
+       if (ret)
+               return ret;
+       nr_fields = type->nr_fields;
+       for (i = 0; i < nr_fields; i++) {
+               const struct lttng_kernel_event_field *iter_field;
+
+               iter_field = type->fields[i];
+               ret = _lttng_field_statedump(session, iter_field, nesting + 1, &prev_field_name);
+               if (ret)
+                       return ret;
+       }
+       ret = print_tabs(session, nesting);
+       if (ret)
+               return ret;
+       alignment = type->alignment;
+       if (alignment) {
+               ret = lttng_metadata_printf(session,
+                       "} align(%u)",
+                       alignment);
+       } else {
+               ret = lttng_metadata_printf(session,
+                       "}");
+       }
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_struct_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting)
+{
+       int ret;
+
+       ret = _lttng_struct_type_statedump(session,
+                       lttng_kernel_get_type_struct(field->type), nesting);
+       if (ret)
+               return ret;
+       return lttng_field_name_statedump(session, field, nesting);
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_variant_type_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_type_variant *type,
+               size_t nesting,
+               const char *prev_field_name)
+{
+       const char *tag_name;
+       int ret;
+       uint32_t i, nr_choices;
+
+       tag_name = type->tag_name;
+       if (!tag_name)
+               tag_name = prev_field_name;
+       if (!tag_name)
+               return -EINVAL;
+       /*
+        * CTF 1.8 does not allow expressing nonzero variant alignment in a nestable way.
+        */
+       if (type->alignment != 0)
+               return -EINVAL;
+       ret = print_tabs(session, nesting);
+       if (ret)
+               return ret;
+       ret = lttng_metadata_printf(session,
+               "variant <_%s> {\n",
+               tag_name);
+       if (ret)
+               return ret;
+       nr_choices = type->nr_choices;
+       for (i = 0; i < nr_choices; i++) {
+               const struct lttng_kernel_event_field *iter_field;
+
+               iter_field = type->choices[i];
+               ret = _lttng_field_statedump(session, iter_field, nesting + 1, NULL);
+               if (ret)
+                       return ret;
+       }
+       ret = print_tabs(session, nesting);
+       if (ret)
+               return ret;
+       ret = lttng_metadata_printf(session,
+               "}");
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_variant_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting,
+               const char *prev_field_name)
+{
+       int ret;
+
+       ret = _lttng_variant_type_statedump(session,
+                       lttng_kernel_get_type_variant(field->type), nesting,
+                       prev_field_name);
+       if (ret)
+               return ret;
+       return lttng_field_name_statedump(session, field, nesting);
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_array_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting)
+{
+       int ret;
+       const struct lttng_kernel_type_array *array_type;
+       const struct lttng_kernel_type_common *elem_type;
+
+       array_type = lttng_kernel_get_type_array(field->type);
+       WARN_ON_ONCE(!array_type);
+
+       if (array_type->alignment) {
+               ret = print_tabs(session, nesting);
+               if (ret)
+                       return ret;
+               ret = lttng_metadata_printf(session,
+               "struct { } align(%u) _%s_padding;\n",
+                               array_type->alignment * CHAR_BIT,
+                               field->name);
+               if (ret)
+                       return ret;
+       }
+       /*
+        * Nested compound types: Only array of structures and variants are
+        * currently supported.
+        */
+       elem_type = array_type->elem_type;
+       switch (elem_type->type) {
+       case lttng_kernel_type_integer:
+       case lttng_kernel_type_struct:
+       case lttng_kernel_type_variant:
+               ret = _lttng_type_statedump(session, elem_type,
+                               array_type->encoding, nesting);
+               if (ret)
+                       return ret;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       ret = lttng_metadata_printf(session,
+               " _%s[%u];\n",
+               field->name,
+               array_type->length);
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_sequence_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting,
+               const char *prev_field_name)
+{
+       int ret;
+       const char *length_name;
+       const struct lttng_kernel_type_sequence *sequence_type;
+       const struct lttng_kernel_type_common *elem_type;
+
+       sequence_type = lttng_kernel_get_type_sequence(field->type);
+       WARN_ON_ONCE(!sequence_type);
+
+       length_name = sequence_type->length_name;
+       if (!length_name)
+               length_name = prev_field_name;
+       if (!length_name)
+               return -EINVAL;
+
+       if (sequence_type->alignment) {
+               ret = print_tabs(session, nesting);
+               if (ret)
+                       return ret;
+               ret = lttng_metadata_printf(session,
+               "struct { } align(%u) _%s_padding;\n",
+                               sequence_type->alignment * CHAR_BIT,
+                               field->name);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Nested compound types: Only array of structures and variants are
+        * currently supported.
+        */
+       elem_type = sequence_type->elem_type;
+       switch (elem_type->type) {
+       case lttng_kernel_type_integer:
+       case lttng_kernel_type_struct:
+       case lttng_kernel_type_variant:
+               ret = _lttng_type_statedump(session, elem_type,
+                               sequence_type->encoding, nesting);
+               if (ret)
+                       return ret;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       ret = lttng_metadata_printf(session,
+               " _%s[ _%s ];\n",
+               field->name,
+               length_name);
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_enum_type_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_type_enum *type,
+               size_t nesting)
+{
+       const struct lttng_kernel_enum_desc *enum_desc;
+       const struct lttng_kernel_type_common *container_type;
+       int ret;
+       unsigned int i, nr_entries;
+
+       container_type = type->container_type;
+       if (container_type->type != lttng_kernel_type_integer) {
+               ret = -EINVAL;
+               goto end;
+       }
+       enum_desc = type->desc;
+       nr_entries = enum_desc->nr_entries;
+
+       ret = print_tabs(session, nesting);
+       if (ret)
+               goto end;
+       ret = lttng_metadata_printf(session, "enum : ");
+       if (ret)
+               goto end;
+       ret = _lttng_integer_type_statedump(session, lttng_kernel_get_type_integer(container_type),
+                       lttng_kernel_string_encoding_none, 0);
+       if (ret)
+               goto end;
+       ret = lttng_metadata_printf(session, " {\n");
+       if (ret)
+               goto end;
+       /* Dump all entries */
+       for (i = 0; i < nr_entries; i++) {
+               const struct lttng_kernel_enum_entry *entry = enum_desc->entries[i];
+               int j, len;
+
+               ret = print_tabs(session, nesting + 1);
+               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->options.is_auto) {
+                       ret = lttng_metadata_printf(session, ",\n");
+                       if (ret)
+                               goto end;
+               } else {
+                       ret = lttng_metadata_printf(session,
+                                       " = ");
+                       if (ret)
+                               goto end;
+                       if (entry->start.signedness)
+                               ret = lttng_metadata_printf(session,
+                                       "%lld", (long long) entry->start.value);
+                       else
+                               ret = lttng_metadata_printf(session,
+                                       "%llu", entry->start.value);
+                       if (ret)
+                               goto end;
+                       if (entry->start.signedness == entry->end.signedness &&
+                                       entry->start.value
+                                               == entry->end.value) {
+                               ret = lttng_metadata_printf(session,
+                                       ",\n");
+                       } else {
+                               if (entry->end.signedness) {
+                                       ret = lttng_metadata_printf(session,
+                                               " ... %lld,\n",
+                                               (long long) entry->end.value);
+                               } else {
+                                       ret = lttng_metadata_printf(session,
+                                               " ... %llu,\n",
+                                               entry->end.value);
+                               }
+                       }
+                       if (ret)
+                               goto end;
+               }
+       }
+       ret = print_tabs(session, nesting);
+       if (ret)
+               goto end;
+       ret = lttng_metadata_printf(session, "}");
+end:
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_enum_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting)
+{
+       int ret;
+       const struct lttng_kernel_type_enum *enum_type;
+
+       enum_type = lttng_kernel_get_type_enum(field->type);
+       WARN_ON_ONCE(!enum_type);
+       ret = _lttng_enum_type_statedump(session, enum_type, nesting);
+       if (ret)
+               return ret;
+       return lttng_field_name_statedump(session, field, nesting);
+}
+
+static
+int _lttng_integer_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting)
+{
+       int ret;
+
+       ret = _lttng_integer_type_statedump(session, lttng_kernel_get_type_integer(field->type),
+                       lttng_kernel_string_encoding_none, nesting);
+       if (ret)
+               return ret;
+       return lttng_field_name_statedump(session, field, nesting);
+}
+
+static
+int _lttng_string_type_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_type_string *type,
+               size_t nesting)
+{
+       int ret;
+
+       /* Default encoding is UTF8 */
+       ret = print_tabs(session, nesting);
+       if (ret)
+               return ret;
+       ret = lttng_metadata_printf(session,
+               "string%s",
+               type->encoding == lttng_kernel_string_encoding_ASCII ?
+                       " { encoding = ASCII; }" : "");
+       return ret;
+}
+
+static
+int _lttng_string_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting)
+{
+       const struct lttng_kernel_type_string *string_type;
+       int ret;
+
+       string_type = lttng_kernel_get_type_string(field->type);
+       WARN_ON_ONCE(!string_type);
+       ret = _lttng_string_type_statedump(session, string_type, nesting);
+       if (ret)
+               return ret;
+       return lttng_field_name_statedump(session, field, nesting);
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_type_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_type_common *type,
+               enum lttng_kernel_string_encoding parent_encoding,
+               size_t nesting)
+{
+       int ret = 0;
+
+       switch (type->type) {
+       case lttng_kernel_type_integer:
+               ret = _lttng_integer_type_statedump(session,
+                               lttng_kernel_get_type_integer(type),
+                               parent_encoding, nesting);
+               break;
+       case lttng_kernel_type_enum:
+               ret = _lttng_enum_type_statedump(session,
+                               lttng_kernel_get_type_enum(type),
+                               nesting);
+               break;
+       case lttng_kernel_type_string:
+               ret = _lttng_string_type_statedump(session,
+                               lttng_kernel_get_type_string(type),
+                               nesting);
+               break;
+       case lttng_kernel_type_struct:
+               ret = _lttng_struct_type_statedump(session,
+                               lttng_kernel_get_type_struct(type),
+                               nesting);
+               break;
+       case lttng_kernel_type_variant:
+               ret = _lttng_variant_type_statedump(session,
+                               lttng_kernel_get_type_variant(type),
+                               nesting, NULL);
+               break;
+
+       /* Nested arrays and sequences are not supported yet. */
+       case lttng_kernel_type_array:
+       case lttng_kernel_type_sequence:
+       default:
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_field_statedump(struct lttng_kernel_session *session,
+               const struct lttng_kernel_event_field *field,
+               size_t nesting,
+               const char **prev_field_name_p)
+{
+       const char *prev_field_name = NULL;
+       int ret = 0;
+
+       if (prev_field_name_p)
+               prev_field_name = *prev_field_name_p;
+       switch (field->type->type) {
+       case lttng_kernel_type_integer:
+               ret = _lttng_integer_field_statedump(session, field, nesting);
+               break;
+       case lttng_kernel_type_enum:
+               ret = _lttng_enum_field_statedump(session, field, nesting);
+               break;
+       case lttng_kernel_type_string:
+               ret = _lttng_string_field_statedump(session, field, nesting);
+               break;
+       case lttng_kernel_type_struct:
+               ret = _lttng_struct_field_statedump(session, field, nesting);
+               break;
+       case lttng_kernel_type_array:
+               ret = _lttng_array_field_statedump(session, field, nesting);
+               break;
+       case lttng_kernel_type_sequence:
+               ret = _lttng_sequence_field_statedump(session, field, nesting, prev_field_name);
+               break;
+       case lttng_kernel_type_variant:
+               ret = _lttng_variant_field_statedump(session, field, nesting, prev_field_name);
+               break;
+
+       default:
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+       if (prev_field_name_p)
+               *prev_field_name_p = field->name;
+       return ret;
+}
+
+static
+int _lttng_context_metadata_statedump(struct lttng_kernel_session *session,
+                                   struct lttng_kernel_ctx *ctx)
+{
+       const char *prev_field_name = NULL;
+       int ret = 0;
+       int i;
+
+       if (!ctx)
+               return 0;
+       for (i = 0; i < ctx->nr_fields; i++) {
+               const struct lttng_kernel_ctx_field *field = &ctx->fields[i];
+
+               ret = _lttng_field_statedump(session, field->event_field, 2, &prev_field_name);
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
+
+static
+int _lttng_fields_metadata_statedump(struct lttng_kernel_session *session,
+                                  struct lttng_kernel_event_recorder *event_recorder)
+{
+       const char *prev_field_name = NULL;
+       const struct lttng_kernel_event_desc *desc = event_recorder->priv->parent.desc;
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < desc->tp_class->nr_fields; i++) {
+               const struct lttng_kernel_event_field *field = desc->tp_class->fields[i];
+
+               ret = _lttng_field_statedump(session, field, 2, &prev_field_name);
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ * The entire event metadata is printed as a single atomic metadata
+ * transaction.
+ */
+int _lttng_event_recorder_metadata_statedump(struct lttng_kernel_event_common *event)
+{
+       struct lttng_kernel_event_recorder *event_recorder;
+       struct lttng_kernel_channel_buffer *chan;
+       struct lttng_kernel_session *session;
+       int ret = 0;
+
+       if (event->type != LTTNG_KERNEL_EVENT_TYPE_RECORDER)
+               return 0;
+       event_recorder = container_of(event, struct lttng_kernel_event_recorder, parent);
+       chan = event_recorder->chan;
+       session = chan->parent.session;
+
+       if (event_recorder->priv->metadata_dumped || !LTTNG_READ_ONCE(session->active))
+               return 0;
+       if (chan->priv->channel_type == METADATA_CHANNEL)
+               return 0;
+
+       lttng_metadata_begin(session);
+
+       ret = lttng_metadata_printf(session,
+               "event {\n"
+               "       name = \"%s\";\n"
+               "       id = %u;\n"
+               "       stream_id = %u;\n",
+               event_recorder->priv->parent.desc->event_name,
+               event_recorder->priv->id,
+               event_recorder->chan->priv->id);
+       if (ret)
+               goto end;
+
+       ret = lttng_metadata_printf(session,
+               "       fields := struct {\n"
+               );
+       if (ret)
+               goto end;
+
+       ret = _lttng_fields_metadata_statedump(session, event_recorder);
+       if (ret)
+               goto end;
+
+       /*
+        * LTTng space reservation can only reserve multiples of the
+        * byte size.
+        */
+       ret = lttng_metadata_printf(session,
+               "       };\n"
+               "};\n\n");
+       if (ret)
+               goto end;
+
+       event_recorder->priv->metadata_dumped = 1;
+end:
+       lttng_metadata_end(session);
+       return ret;
+
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ * The entire channel metadata is printed as a single atomic metadata
+ * transaction.
+ */
+static
+int lttng_channel_metadata_statedump(struct lttng_kernel_session *session,
+                                   struct lttng_kernel_channel_buffer *chan)
+{
+       int ret = 0;
+
+       if (chan->priv->metadata_dumped || !LTTNG_READ_ONCE(session->active))
+               return 0;
+
+       if (chan->priv->channel_type == METADATA_CHANNEL)
+               return 0;
+
+       lttng_metadata_begin(session);
+
+       WARN_ON_ONCE(!chan->priv->header_type);
+       ret = lttng_metadata_printf(session,
+               "stream {\n"
+               "       id = %u;\n"
+               "       event.header := %s;\n"
+               "       packet.context := struct packet_context;\n",
+               chan->priv->id,
+               chan->priv->header_type == 1 ? "struct event_header_compact" :
+                       "struct event_header_large");
+       if (ret)
+               goto end;
+
+       if (chan->priv->ctx) {
+               ret = lttng_metadata_printf(session,
+                       "       event.context := struct {\n");
+               if (ret)
+                       goto end;
+       }
+       ret = _lttng_context_metadata_statedump(session, chan->priv->ctx);
+       if (ret)
+               goto end;
+       if (chan->priv->ctx) {
+               ret = lttng_metadata_printf(session,
+                       "       };\n");
+               if (ret)
+                       goto end;
+       }
+
+       ret = lttng_metadata_printf(session,
+               "};\n\n");
+
+       chan->priv->metadata_dumped = 1;
+end:
+       lttng_metadata_end(session);
+       return ret;
+}
+
+/*
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_stream_packet_context_declare(struct lttng_kernel_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"
+               );
+}
+
+/*
+ * 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.
+ *
+ * Must be called with sessions_mutex held.
+ */
+static
+int _lttng_event_header_declare(struct lttng_kernel_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",
+       lttng_alignof(uint32_t) * CHAR_BIT,
+       lttng_alignof(uint16_t) * CHAR_BIT
+       );
+}
+
+ /*
+ * Approximation of NTP time of day to clock monotonic correlation,
+ * taken at start of trace.
+ * Yes, this is only an approximation. Yes, we can (and will) do better
+ * in future versions.
+ * This function may return a negative offset. It may happen if the
+ * system sets the REALTIME clock to 0 after boot.
+ *
+ * Use 64bit timespec on kernels that have it, this makes 32bit arch
+ * y2038 compliant.
+ */
+int64_t measure_clock_offset(void)
+{
+       uint64_t monotonic_avg, monotonic[2], realtime;
+       uint64_t tcf = trace_clock_freq();
+       int64_t offset;
+       unsigned long flags;
+#ifdef LTTNG_KERNEL_HAS_TIMESPEC64
+       struct timespec64 rts = { 0, 0 };
+#else
+       struct timespec rts = { 0, 0 };
+#endif
+
+       /* Disable interrupts to increase correlation precision. */
+       local_irq_save(flags);
+       monotonic[0] = trace_clock_read64();
+#ifdef LTTNG_KERNEL_HAS_TIMESPEC64
+       ktime_get_real_ts64(&rts);
+#else
+       getnstimeofday(&rts);
+#endif
+       monotonic[1] = trace_clock_read64();
+       local_irq_restore(flags);
+
+       monotonic_avg = (monotonic[0] + monotonic[1]) >> 1;
+       realtime = (uint64_t) rts.tv_sec * tcf;
+       if (tcf == NSEC_PER_SEC) {
+               realtime += rts.tv_nsec;
+       } else {
+               uint64_t n = rts.tv_nsec * tcf;
+
+               do_div(n, NSEC_PER_SEC);
+               realtime += n;
+       }
+       offset = (int64_t) realtime - monotonic_avg;
+       return offset;
+}
+
+static
+int print_escaped_ctf_string(struct lttng_kernel_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 */
+                       lttng_fallthrough;
+               default:
+                       ret = lttng_metadata_printf(session, "%c", cur);
+                       break;
+               }
+
+               if (ret)
+                       goto error;
+
+               cur = string[++i];
+       }
+error:
+       return ret;
+}
+
+static
+int print_metadata_escaped_field(struct lttng_kernel_session *session, const char *field,
+               const char *field_value)
+{
+       int ret;
+
+       ret = lttng_metadata_printf(session, "  %s = \"", field);
+       if (ret)
+               goto error;
+
+       ret = print_escaped_ctf_string(session, field_value);
+       if (ret)
+               goto error;
+
+       ret = lttng_metadata_printf(session, "\";\n");
+
+error:
+       return ret;
+}
+
+/*
+ * Output metadata into this session's metadata buffers.
+ * Must be called with sessions_mutex held.
+ */
+int _lttng_session_metadata_statedump(struct lttng_kernel_session *session)
+{
+       unsigned char *uuid_c = session->priv->uuid.b;
+       unsigned char uuid_s[37], clock_uuid_s[BOOT_ID_LEN];
+       const char *product_uuid;
+       struct lttng_kernel_channel_buffer_private *chan_priv;
+       struct lttng_kernel_event_recorder_private *event_recorder_priv;
+       int ret = 0;
+
+       if (!LTTNG_READ_ONCE(session->active))
+               return 0;
+
+       lttng_metadata_begin(session);
+
+       if (session->priv->metadata_dumped)
+               goto skip_session;
+
+       snprintf(uuid_s, sizeof(uuid_s),
+               "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+               uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3],
+               uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7],
+               uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11],
+               uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]);
+
+       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",
+               lttng_alignof(uint8_t) * CHAR_BIT,
+               lttng_alignof(uint16_t) * CHAR_BIT,
+               lttng_alignof(uint32_t) * CHAR_BIT,
+               lttng_alignof(uint64_t) * CHAR_BIT,
+               sizeof(unsigned long) * CHAR_BIT,
+               lttng_alignof(unsigned long) * CHAR_BIT,
+               CTF_SPEC_MAJOR,
+               CTF_SPEC_MINOR,
+               uuid_s,
+#if __BYTE_ORDER == __BIG_ENDIAN
+               "be"
+#else
+               "le"
+#endif
+               );
+       if (ret)
+               goto end;
+
+       ret = lttng_metadata_printf(session,
+               "env {\n"
+               "       hostname = \"%s\";\n"
+               "       domain = \"kernel\";\n"
+               "       sysname = \"%s\";\n"
+               "       kernel_release = \"%s\";\n"
+               "       kernel_version = \"%s\";\n"
+               "       tracer_name = \"lttng-modules\";\n"
+               "       tracer_major = %d;\n"
+               "       tracer_minor = %d;\n"
+               "       tracer_patchlevel = %d;\n"
+               "       trace_buffering_scheme = \"global\";\n",
+               current->nsproxy->uts_ns->name.nodename,
+               utsname()->sysname,
+               utsname()->release,
+               utsname()->version,
+               LTTNG_MODULES_MAJOR_VERSION,
+               LTTNG_MODULES_MINOR_VERSION,
+               LTTNG_MODULES_PATCHLEVEL_VERSION
+               );
+       if (ret)
+               goto end;
+
+       ret = print_metadata_escaped_field(session, "trace_name", session->priv->name);
+       if (ret)
+               goto end;
+       ret = print_metadata_escaped_field(session, "trace_creation_datetime",
+                       session->priv->creation_time);
+       if (ret)
+               goto end;
+
+       /* Add the product UUID to the 'env' section */
+       product_uuid = dmi_get_system_info(DMI_PRODUCT_UUID);
+       if (product_uuid) {
+               ret = lttng_metadata_printf(session,
+                               "       product_uuid = \"%s\";\n",
+                               product_uuid
+                               );
+               if (ret)
+                       goto end;
+       }
+
+       /* Close the 'env' section */
+       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;
+       }
+
+       ret = lttng_metadata_printf(session,
+               "       description = \"%s\";\n"
+               "       freq = %llu; /* Frequency, in Hz */\n"
+               "       /* clock value offset from Epoch is: offset * (1/freq) */\n"
+               "       offset = %lld;\n"
+               "};\n\n",
+               trace_clock_description(),
+               (unsigned long long) trace_clock_freq(),
+               (long long) 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(),
+               lttng_alignof(uint32_t) * CHAR_BIT,
+               trace_clock_name(),
+               lttng_alignof(uint64_t) * CHAR_BIT,
+               trace_clock_name()
+               );
+       if (ret)
+               goto end;
+
+       ret = _lttng_stream_packet_context_declare(session);
+       if (ret)
+               goto end;
+
+       ret = _lttng_event_header_declare(session);
+       if (ret)
+               goto end;
+
+skip_session:
+       list_for_each_entry(chan_priv, &session->priv->chan, node) {
+               ret = lttng_channel_metadata_statedump(session, chan_priv->pub);
+               if (ret)
+                       goto end;
+       }
+
+       list_for_each_entry(event_recorder_priv, &session->priv->events, parent.node) {
+               ret = _lttng_event_recorder_metadata_statedump(&event_recorder_priv->pub->parent);
+               if (ret)
+                       goto end;
+       }
+       session->priv->metadata_dumped = 1;
+end:
+       lttng_metadata_end(session);
+       return ret;
+}
diff --git a/src/ctf1-8.h b/src/ctf1-8.h
new file mode 100644 (file)
index 0000000..059ff08
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * src/ctf1-8.h
+ *
+ * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ */
+
+#ifndef _LTTNG_CTF1_8_H_
+#define _LTTNG_CTF1_8_H_
+
+#include <lttng/events.h>
+#include <lttng/events-internal.h>
+
+int _lttng_session_metadata_statedump(struct lttng_kernel_session *session);
+int _lttng_event_recorder_metadata_statedump(struct lttng_kernel_event_common *event);
+
+#endif /* _LTTNG_CTF1_8_H_ */
index 45832929842fa10997b2d0d348b1322a246d031d..a5ac2738e40fe97fd1efdf0c141d6aa005f48165 100644 (file)
@@ -56,6 +56,7 @@
 #endif
 
 #include "metadata-printer.h"
+#include "ctf1-8.h"
 
 #define METADATA_CACHE_DEFAULT_SIZE 4096
 
@@ -81,20 +82,7 @@ static void _lttng_event_destroy(struct lttng_kernel_event_common *event);
 static void _lttng_channel_destroy(struct lttng_kernel_channel_buffer *chan);
 static void _lttng_event_unregister(struct lttng_kernel_event_common *event);
 static
-int _lttng_event_recorder_metadata_statedump(struct lttng_kernel_event_common *event);
-static
-int _lttng_session_metadata_statedump(struct lttng_kernel_session *session);
-static
 void _lttng_metadata_channel_hangup(struct lttng_metadata_stream *stream);
-static
-int _lttng_type_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_type_common *type,
-               enum lttng_kernel_string_encoding parent_encoding,
-               size_t nesting);
-static
-int _lttng_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting, const char **prev_field_name_p);
 
 void synchronize_trace(void)
 {
@@ -2799,1100 +2787,6 @@ end:
        return ret;
 }
 
-static
-int print_tabs(struct lttng_kernel_session *session, size_t nesting)
-{
-       size_t i;
-
-       for (i = 0; i < nesting; i++) {
-               int ret;
-
-               ret = lttng_metadata_printf(session, "  ");
-               if (ret) {
-                       return ret;
-               }
-       }
-       return 0;
-}
-
-static
-int lttng_field_name_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting)
-{
-       return lttng_metadata_printf(session, " _%s;\n", field->name);
-}
-
-static
-int _lttng_integer_type_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_type_integer *type,
-               enum lttng_kernel_string_encoding parent_encoding,
-               size_t nesting)
-{
-       int ret;
-
-       ret = print_tabs(session, nesting);
-       if (ret)
-               return ret;
-       ret = lttng_metadata_printf(session,
-               "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s }",
-               type->size,
-               type->alignment,
-               type->signedness,
-               (parent_encoding == lttng_kernel_string_encoding_none)
-                       ? "none"
-                       : (parent_encoding == lttng_kernel_string_encoding_UTF8)
-                               ? "UTF8"
-                               : "ASCII",
-               type->base,
-#if __BYTE_ORDER == __BIG_ENDIAN
-               type->reverse_byte_order ? " byte_order = le;" : ""
-#else
-               type->reverse_byte_order ? " byte_order = be;" : ""
-#endif
-       );
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_struct_type_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_type_struct *type,
-               size_t nesting)
-{
-       const char *prev_field_name = NULL;
-       int ret;
-       uint32_t i, nr_fields;
-       unsigned int alignment;
-
-       ret = print_tabs(session, nesting);
-       if (ret)
-               return ret;
-       ret = lttng_metadata_printf(session,
-               "struct {\n");
-       if (ret)
-               return ret;
-       nr_fields = type->nr_fields;
-       for (i = 0; i < nr_fields; i++) {
-               const struct lttng_kernel_event_field *iter_field;
-
-               iter_field = type->fields[i];
-               ret = _lttng_field_statedump(session, iter_field, nesting + 1, &prev_field_name);
-               if (ret)
-                       return ret;
-       }
-       ret = print_tabs(session, nesting);
-       if (ret)
-               return ret;
-       alignment = type->alignment;
-       if (alignment) {
-               ret = lttng_metadata_printf(session,
-                       "} align(%u)",
-                       alignment);
-       } else {
-               ret = lttng_metadata_printf(session,
-                       "}");
-       }
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_struct_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting)
-{
-       int ret;
-
-       ret = _lttng_struct_type_statedump(session,
-                       lttng_kernel_get_type_struct(field->type), nesting);
-       if (ret)
-               return ret;
-       return lttng_field_name_statedump(session, field, nesting);
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_variant_type_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_type_variant *type,
-               size_t nesting,
-               const char *prev_field_name)
-{
-       const char *tag_name;
-       int ret;
-       uint32_t i, nr_choices;
-
-       tag_name = type->tag_name;
-       if (!tag_name)
-               tag_name = prev_field_name;
-       if (!tag_name)
-               return -EINVAL;
-       /*
-        * CTF 1.8 does not allow expressing nonzero variant alignment in a nestable way.
-        */
-       if (type->alignment != 0)
-               return -EINVAL;
-       ret = print_tabs(session, nesting);
-       if (ret)
-               return ret;
-       ret = lttng_metadata_printf(session,
-               "variant <_%s> {\n",
-               tag_name);
-       if (ret)
-               return ret;
-       nr_choices = type->nr_choices;
-       for (i = 0; i < nr_choices; i++) {
-               const struct lttng_kernel_event_field *iter_field;
-
-               iter_field = type->choices[i];
-               ret = _lttng_field_statedump(session, iter_field, nesting + 1, NULL);
-               if (ret)
-                       return ret;
-       }
-       ret = print_tabs(session, nesting);
-       if (ret)
-               return ret;
-       ret = lttng_metadata_printf(session,
-               "}");
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_variant_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting,
-               const char *prev_field_name)
-{
-       int ret;
-
-       ret = _lttng_variant_type_statedump(session,
-                       lttng_kernel_get_type_variant(field->type), nesting,
-                       prev_field_name);
-       if (ret)
-               return ret;
-       return lttng_field_name_statedump(session, field, nesting);
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_array_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting)
-{
-       int ret;
-       const struct lttng_kernel_type_array *array_type;
-       const struct lttng_kernel_type_common *elem_type;
-
-       array_type = lttng_kernel_get_type_array(field->type);
-       WARN_ON_ONCE(!array_type);
-
-       if (array_type->alignment) {
-               ret = print_tabs(session, nesting);
-               if (ret)
-                       return ret;
-               ret = lttng_metadata_printf(session,
-               "struct { } align(%u) _%s_padding;\n",
-                               array_type->alignment * CHAR_BIT,
-                               field->name);
-               if (ret)
-                       return ret;
-       }
-       /*
-        * Nested compound types: Only array of structures and variants are
-        * currently supported.
-        */
-       elem_type = array_type->elem_type;
-       switch (elem_type->type) {
-       case lttng_kernel_type_integer:
-       case lttng_kernel_type_struct:
-       case lttng_kernel_type_variant:
-               ret = _lttng_type_statedump(session, elem_type,
-                               array_type->encoding, nesting);
-               if (ret)
-                       return ret;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       ret = lttng_metadata_printf(session,
-               " _%s[%u];\n",
-               field->name,
-               array_type->length);
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_sequence_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting,
-               const char *prev_field_name)
-{
-       int ret;
-       const char *length_name;
-       const struct lttng_kernel_type_sequence *sequence_type;
-       const struct lttng_kernel_type_common *elem_type;
-
-       sequence_type = lttng_kernel_get_type_sequence(field->type);
-       WARN_ON_ONCE(!sequence_type);
-
-       length_name = sequence_type->length_name;
-       if (!length_name)
-               length_name = prev_field_name;
-       if (!length_name)
-               return -EINVAL;
-
-       if (sequence_type->alignment) {
-               ret = print_tabs(session, nesting);
-               if (ret)
-                       return ret;
-               ret = lttng_metadata_printf(session,
-               "struct { } align(%u) _%s_padding;\n",
-                               sequence_type->alignment * CHAR_BIT,
-                               field->name);
-               if (ret)
-                       return ret;
-       }
-
-       /*
-        * Nested compound types: Only array of structures and variants are
-        * currently supported.
-        */
-       elem_type = sequence_type->elem_type;
-       switch (elem_type->type) {
-       case lttng_kernel_type_integer:
-       case lttng_kernel_type_struct:
-       case lttng_kernel_type_variant:
-               ret = _lttng_type_statedump(session, elem_type,
-                               sequence_type->encoding, nesting);
-               if (ret)
-                       return ret;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       ret = lttng_metadata_printf(session,
-               " _%s[ _%s ];\n",
-               field->name,
-               length_name);
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_enum_type_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_type_enum *type,
-               size_t nesting)
-{
-       const struct lttng_kernel_enum_desc *enum_desc;
-       const struct lttng_kernel_type_common *container_type;
-       int ret;
-       unsigned int i, nr_entries;
-
-       container_type = type->container_type;
-       if (container_type->type != lttng_kernel_type_integer) {
-               ret = -EINVAL;
-               goto end;
-       }
-       enum_desc = type->desc;
-       nr_entries = enum_desc->nr_entries;
-
-       ret = print_tabs(session, nesting);
-       if (ret)
-               goto end;
-       ret = lttng_metadata_printf(session, "enum : ");
-       if (ret)
-               goto end;
-       ret = _lttng_integer_type_statedump(session, lttng_kernel_get_type_integer(container_type),
-                       lttng_kernel_string_encoding_none, 0);
-       if (ret)
-               goto end;
-       ret = lttng_metadata_printf(session, " {\n");
-       if (ret)
-               goto end;
-       /* Dump all entries */
-       for (i = 0; i < nr_entries; i++) {
-               const struct lttng_kernel_enum_entry *entry = enum_desc->entries[i];
-               int j, len;
-
-               ret = print_tabs(session, nesting + 1);
-               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->options.is_auto) {
-                       ret = lttng_metadata_printf(session, ",\n");
-                       if (ret)
-                               goto end;
-               } else {
-                       ret = lttng_metadata_printf(session,
-                                       " = ");
-                       if (ret)
-                               goto end;
-                       if (entry->start.signedness)
-                               ret = lttng_metadata_printf(session,
-                                       "%lld", (long long) entry->start.value);
-                       else
-                               ret = lttng_metadata_printf(session,
-                                       "%llu", entry->start.value);
-                       if (ret)
-                               goto end;
-                       if (entry->start.signedness == entry->end.signedness &&
-                                       entry->start.value
-                                               == entry->end.value) {
-                               ret = lttng_metadata_printf(session,
-                                       ",\n");
-                       } else {
-                               if (entry->end.signedness) {
-                                       ret = lttng_metadata_printf(session,
-                                               " ... %lld,\n",
-                                               (long long) entry->end.value);
-                               } else {
-                                       ret = lttng_metadata_printf(session,
-                                               " ... %llu,\n",
-                                               entry->end.value);
-                               }
-                       }
-                       if (ret)
-                               goto end;
-               }
-       }
-       ret = print_tabs(session, nesting);
-       if (ret)
-               goto end;
-       ret = lttng_metadata_printf(session, "}");
-end:
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_enum_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting)
-{
-       int ret;
-       const struct lttng_kernel_type_enum *enum_type;
-
-       enum_type = lttng_kernel_get_type_enum(field->type);
-       WARN_ON_ONCE(!enum_type);
-       ret = _lttng_enum_type_statedump(session, enum_type, nesting);
-       if (ret)
-               return ret;
-       return lttng_field_name_statedump(session, field, nesting);
-}
-
-static
-int _lttng_integer_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting)
-{
-       int ret;
-
-       ret = _lttng_integer_type_statedump(session, lttng_kernel_get_type_integer(field->type),
-                       lttng_kernel_string_encoding_none, nesting);
-       if (ret)
-               return ret;
-       return lttng_field_name_statedump(session, field, nesting);
-}
-
-static
-int _lttng_string_type_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_type_string *type,
-               size_t nesting)
-{
-       int ret;
-
-       /* Default encoding is UTF8 */
-       ret = print_tabs(session, nesting);
-       if (ret)
-               return ret;
-       ret = lttng_metadata_printf(session,
-               "string%s",
-               type->encoding == lttng_kernel_string_encoding_ASCII ?
-                       " { encoding = ASCII; }" : "");
-       return ret;
-}
-
-static
-int _lttng_string_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting)
-{
-       const struct lttng_kernel_type_string *string_type;
-       int ret;
-
-       string_type = lttng_kernel_get_type_string(field->type);
-       WARN_ON_ONCE(!string_type);
-       ret = _lttng_string_type_statedump(session, string_type, nesting);
-       if (ret)
-               return ret;
-       return lttng_field_name_statedump(session, field, nesting);
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_type_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_type_common *type,
-               enum lttng_kernel_string_encoding parent_encoding,
-               size_t nesting)
-{
-       int ret = 0;
-
-       switch (type->type) {
-       case lttng_kernel_type_integer:
-               ret = _lttng_integer_type_statedump(session,
-                               lttng_kernel_get_type_integer(type),
-                               parent_encoding, nesting);
-               break;
-       case lttng_kernel_type_enum:
-               ret = _lttng_enum_type_statedump(session,
-                               lttng_kernel_get_type_enum(type),
-                               nesting);
-               break;
-       case lttng_kernel_type_string:
-               ret = _lttng_string_type_statedump(session,
-                               lttng_kernel_get_type_string(type),
-                               nesting);
-               break;
-       case lttng_kernel_type_struct:
-               ret = _lttng_struct_type_statedump(session,
-                               lttng_kernel_get_type_struct(type),
-                               nesting);
-               break;
-       case lttng_kernel_type_variant:
-               ret = _lttng_variant_type_statedump(session,
-                               lttng_kernel_get_type_variant(type),
-                               nesting, NULL);
-               break;
-
-       /* Nested arrays and sequences are not supported yet. */
-       case lttng_kernel_type_array:
-       case lttng_kernel_type_sequence:
-       default:
-               WARN_ON_ONCE(1);
-               return -EINVAL;
-       }
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_field_statedump(struct lttng_kernel_session *session,
-               const struct lttng_kernel_event_field *field,
-               size_t nesting,
-               const char **prev_field_name_p)
-{
-       const char *prev_field_name = NULL;
-       int ret = 0;
-
-       if (prev_field_name_p)
-               prev_field_name = *prev_field_name_p;
-       switch (field->type->type) {
-       case lttng_kernel_type_integer:
-               ret = _lttng_integer_field_statedump(session, field, nesting);
-               break;
-       case lttng_kernel_type_enum:
-               ret = _lttng_enum_field_statedump(session, field, nesting);
-               break;
-       case lttng_kernel_type_string:
-               ret = _lttng_string_field_statedump(session, field, nesting);
-               break;
-       case lttng_kernel_type_struct:
-               ret = _lttng_struct_field_statedump(session, field, nesting);
-               break;
-       case lttng_kernel_type_array:
-               ret = _lttng_array_field_statedump(session, field, nesting);
-               break;
-       case lttng_kernel_type_sequence:
-               ret = _lttng_sequence_field_statedump(session, field, nesting, prev_field_name);
-               break;
-       case lttng_kernel_type_variant:
-               ret = _lttng_variant_field_statedump(session, field, nesting, prev_field_name);
-               break;
-
-       default:
-               WARN_ON_ONCE(1);
-               return -EINVAL;
-       }
-       if (prev_field_name_p)
-               *prev_field_name_p = field->name;
-       return ret;
-}
-
-static
-int _lttng_context_metadata_statedump(struct lttng_kernel_session *session,
-                                   struct lttng_kernel_ctx *ctx)
-{
-       const char *prev_field_name = NULL;
-       int ret = 0;
-       int i;
-
-       if (!ctx)
-               return 0;
-       for (i = 0; i < ctx->nr_fields; i++) {
-               const struct lttng_kernel_ctx_field *field = &ctx->fields[i];
-
-               ret = _lttng_field_statedump(session, field->event_field, 2, &prev_field_name);
-               if (ret)
-                       return ret;
-       }
-       return ret;
-}
-
-static
-int _lttng_fields_metadata_statedump(struct lttng_kernel_session *session,
-                                  struct lttng_kernel_event_recorder *event_recorder)
-{
-       const char *prev_field_name = NULL;
-       const struct lttng_kernel_event_desc *desc = event_recorder->priv->parent.desc;
-       int ret = 0;
-       int i;
-
-       for (i = 0; i < desc->tp_class->nr_fields; i++) {
-               const struct lttng_kernel_event_field *field = desc->tp_class->fields[i];
-
-               ret = _lttng_field_statedump(session, field, 2, &prev_field_name);
-               if (ret)
-                       return ret;
-       }
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- * The entire event metadata is printed as a single atomic metadata
- * transaction.
- */
-static
-int _lttng_event_recorder_metadata_statedump(struct lttng_kernel_event_common *event)
-{
-       struct lttng_kernel_event_recorder *event_recorder;
-       struct lttng_kernel_channel_buffer *chan;
-       struct lttng_kernel_session *session;
-       int ret = 0;
-
-       if (event->type != LTTNG_KERNEL_EVENT_TYPE_RECORDER)
-               return 0;
-       event_recorder = container_of(event, struct lttng_kernel_event_recorder, parent);
-       chan = event_recorder->chan;
-       session = chan->parent.session;
-
-       if (event_recorder->priv->metadata_dumped || !LTTNG_READ_ONCE(session->active))
-               return 0;
-       if (chan->priv->channel_type == METADATA_CHANNEL)
-               return 0;
-
-       lttng_metadata_begin(session);
-
-       ret = lttng_metadata_printf(session,
-               "event {\n"
-               "       name = \"%s\";\n"
-               "       id = %u;\n"
-               "       stream_id = %u;\n",
-               event_recorder->priv->parent.desc->event_name,
-               event_recorder->priv->id,
-               event_recorder->chan->priv->id);
-       if (ret)
-               goto end;
-
-       ret = lttng_metadata_printf(session,
-               "       fields := struct {\n"
-               );
-       if (ret)
-               goto end;
-
-       ret = _lttng_fields_metadata_statedump(session, event_recorder);
-       if (ret)
-               goto end;
-
-       /*
-        * LTTng space reservation can only reserve multiples of the
-        * byte size.
-        */
-       ret = lttng_metadata_printf(session,
-               "       };\n"
-               "};\n\n");
-       if (ret)
-               goto end;
-
-       event_recorder->priv->metadata_dumped = 1;
-end:
-       lttng_metadata_end(session);
-       return ret;
-
-}
-
-/*
- * Must be called with sessions_mutex held.
- * The entire channel metadata is printed as a single atomic metadata
- * transaction.
- */
-static
-int _lttng_channel_metadata_statedump(struct lttng_kernel_session *session,
-                                   struct lttng_kernel_channel_buffer *chan)
-{
-       int ret = 0;
-
-       if (chan->priv->metadata_dumped || !LTTNG_READ_ONCE(session->active))
-               return 0;
-
-       if (chan->priv->channel_type == METADATA_CHANNEL)
-               return 0;
-
-       lttng_metadata_begin(session);
-
-       WARN_ON_ONCE(!chan->priv->header_type);
-       ret = lttng_metadata_printf(session,
-               "stream {\n"
-               "       id = %u;\n"
-               "       event.header := %s;\n"
-               "       packet.context := struct packet_context;\n",
-               chan->priv->id,
-               chan->priv->header_type == 1 ? "struct event_header_compact" :
-                       "struct event_header_large");
-       if (ret)
-               goto end;
-
-       if (chan->priv->ctx) {
-               ret = lttng_metadata_printf(session,
-                       "       event.context := struct {\n");
-               if (ret)
-                       goto end;
-       }
-       ret = _lttng_context_metadata_statedump(session, chan->priv->ctx);
-       if (ret)
-               goto end;
-       if (chan->priv->ctx) {
-               ret = lttng_metadata_printf(session,
-                       "       };\n");
-               if (ret)
-                       goto end;
-       }
-
-       ret = lttng_metadata_printf(session,
-               "};\n\n");
-
-       chan->priv->metadata_dumped = 1;
-end:
-       lttng_metadata_end(session);
-       return ret;
-}
-
-/*
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_stream_packet_context_declare(struct lttng_kernel_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"
-               );
-}
-
-/*
- * 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.
- *
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_event_header_declare(struct lttng_kernel_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",
-       lttng_alignof(uint32_t) * CHAR_BIT,
-       lttng_alignof(uint16_t) * CHAR_BIT
-       );
-}
-
- /*
- * Approximation of NTP time of day to clock monotonic correlation,
- * taken at start of trace.
- * Yes, this is only an approximation. Yes, we can (and will) do better
- * in future versions.
- * This function may return a negative offset. It may happen if the
- * system sets the REALTIME clock to 0 after boot.
- *
- * Use 64bit timespec on kernels that have it, this makes 32bit arch
- * y2038 compliant.
- */
-static
-int64_t measure_clock_offset(void)
-{
-       uint64_t monotonic_avg, monotonic[2], realtime;
-       uint64_t tcf = trace_clock_freq();
-       int64_t offset;
-       unsigned long flags;
-#ifdef LTTNG_KERNEL_HAS_TIMESPEC64
-       struct timespec64 rts = { 0, 0 };
-#else
-       struct timespec rts = { 0, 0 };
-#endif
-
-       /* Disable interrupts to increase correlation precision. */
-       local_irq_save(flags);
-       monotonic[0] = trace_clock_read64();
-#ifdef LTTNG_KERNEL_HAS_TIMESPEC64
-       ktime_get_real_ts64(&rts);
-#else
-       getnstimeofday(&rts);
-#endif
-       monotonic[1] = trace_clock_read64();
-       local_irq_restore(flags);
-
-       monotonic_avg = (monotonic[0] + monotonic[1]) >> 1;
-       realtime = (uint64_t) rts.tv_sec * tcf;
-       if (tcf == NSEC_PER_SEC) {
-               realtime += rts.tv_nsec;
-       } else {
-               uint64_t n = rts.tv_nsec * tcf;
-
-               do_div(n, NSEC_PER_SEC);
-               realtime += n;
-       }
-       offset = (int64_t) realtime - monotonic_avg;
-       return offset;
-}
-
-static
-int print_escaped_ctf_string(struct lttng_kernel_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 */
-                       lttng_fallthrough;
-               default:
-                       ret = lttng_metadata_printf(session, "%c", cur);
-                       break;
-               }
-
-               if (ret)
-                       goto error;
-
-               cur = string[++i];
-       }
-error:
-       return ret;
-}
-
-static
-int print_metadata_escaped_field(struct lttng_kernel_session *session, const char *field,
-               const char *field_value)
-{
-       int ret;
-
-       ret = lttng_metadata_printf(session, "  %s = \"", field);
-       if (ret)
-               goto error;
-
-       ret = print_escaped_ctf_string(session, field_value);
-       if (ret)
-               goto error;
-
-       ret = lttng_metadata_printf(session, "\";\n");
-
-error:
-       return ret;
-}
-
-/*
- * Output metadata into this session's metadata buffers.
- * Must be called with sessions_mutex held.
- */
-static
-int _lttng_session_metadata_statedump(struct lttng_kernel_session *session)
-{
-       unsigned char *uuid_c = session->priv->uuid.b;
-       unsigned char uuid_s[37], clock_uuid_s[BOOT_ID_LEN];
-       const char *product_uuid;
-       struct lttng_kernel_channel_buffer_private *chan_priv;
-       struct lttng_kernel_event_recorder_private *event_recorder_priv;
-       int ret = 0;
-
-       if (!LTTNG_READ_ONCE(session->active))
-               return 0;
-
-       lttng_metadata_begin(session);
-
-       if (session->priv->metadata_dumped)
-               goto skip_session;
-
-       snprintf(uuid_s, sizeof(uuid_s),
-               "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-               uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3],
-               uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7],
-               uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11],
-               uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]);
-
-       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",
-               lttng_alignof(uint8_t) * CHAR_BIT,
-               lttng_alignof(uint16_t) * CHAR_BIT,
-               lttng_alignof(uint32_t) * CHAR_BIT,
-               lttng_alignof(uint64_t) * CHAR_BIT,
-               sizeof(unsigned long) * CHAR_BIT,
-               lttng_alignof(unsigned long) * CHAR_BIT,
-               CTF_SPEC_MAJOR,
-               CTF_SPEC_MINOR,
-               uuid_s,
-#if __BYTE_ORDER == __BIG_ENDIAN
-               "be"
-#else
-               "le"
-#endif
-               );
-       if (ret)
-               goto end;
-
-       ret = lttng_metadata_printf(session,
-               "env {\n"
-               "       hostname = \"%s\";\n"
-               "       domain = \"kernel\";\n"
-               "       sysname = \"%s\";\n"
-               "       kernel_release = \"%s\";\n"
-               "       kernel_version = \"%s\";\n"
-               "       tracer_name = \"lttng-modules\";\n"
-               "       tracer_major = %d;\n"
-               "       tracer_minor = %d;\n"
-               "       tracer_patchlevel = %d;\n"
-               "       trace_buffering_scheme = \"global\";\n",
-               current->nsproxy->uts_ns->name.nodename,
-               utsname()->sysname,
-               utsname()->release,
-               utsname()->version,
-               LTTNG_MODULES_MAJOR_VERSION,
-               LTTNG_MODULES_MINOR_VERSION,
-               LTTNG_MODULES_PATCHLEVEL_VERSION
-               );
-       if (ret)
-               goto end;
-
-       ret = print_metadata_escaped_field(session, "trace_name", session->priv->name);
-       if (ret)
-               goto end;
-       ret = print_metadata_escaped_field(session, "trace_creation_datetime",
-                       session->priv->creation_time);
-       if (ret)
-               goto end;
-
-       /* Add the product UUID to the 'env' section */
-       product_uuid = dmi_get_system_info(DMI_PRODUCT_UUID);
-       if (product_uuid) {
-               ret = lttng_metadata_printf(session,
-                               "       product_uuid = \"%s\";\n",
-                               product_uuid
-                               );
-               if (ret)
-                       goto end;
-       }
-
-       /* Close the 'env' section */
-       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;
-       }
-
-       ret = lttng_metadata_printf(session,
-               "       description = \"%s\";\n"
-               "       freq = %llu; /* Frequency, in Hz */\n"
-               "       /* clock value offset from Epoch is: offset * (1/freq) */\n"
-               "       offset = %lld;\n"
-               "};\n\n",
-               trace_clock_description(),
-               (unsigned long long) trace_clock_freq(),
-               (long long) 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(),
-               lttng_alignof(uint32_t) * CHAR_BIT,
-               trace_clock_name(),
-               lttng_alignof(uint64_t) * CHAR_BIT,
-               trace_clock_name()
-               );
-       if (ret)
-               goto end;
-
-       ret = _lttng_stream_packet_context_declare(session);
-       if (ret)
-               goto end;
-
-       ret = _lttng_event_header_declare(session);
-       if (ret)
-               goto end;
-
-skip_session:
-       list_for_each_entry(chan_priv, &session->priv->chan, node) {
-               ret = _lttng_channel_metadata_statedump(session, chan_priv->pub);
-               if (ret)
-                       goto end;
-       }
-
-       list_for_each_entry(event_recorder_priv, &session->priv->events, parent.node) {
-               ret = _lttng_event_recorder_metadata_statedump(&event_recorder_priv->pub->parent);
-               if (ret)
-                       goto end;
-       }
-       session->priv->metadata_dumped = 1;
-end:
-       lttng_metadata_end(session);
-       return ret;
-}
-
 /**
  * lttng_transport_register - LTT transport registration
  * @transport: transport structure
This page took 0.049472 seconds and 5 git commands to generate.