ctf plugin: add CTF metadata decoder API
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 24 Mar 2017 01:39:22 +0000 (21:39 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:40 +0000 (12:57 -0400)
The new plugins/ctf/common/metadata/decoder.h header exposes the CTF
metadata decoder API. This is a common API used by both the ctf.fs and
ctf.lttng-live component classes.

Once you create a CTF metadata decoder object with
ctf_metadata_decoder_create(), you can call
ctf_metadata_decoder_decode() as many times as needed to decode chunks
of metadata. Those chunks can be packetized or not, however the
resulting metadata text needs to be "complete", that is, zero or more
top-level TSDL blocks ("declarations"). If ctf_metadata_decoder_decode()
cannot decode because the metadata text is incomplete, the function
returns CTF_METADATA_DECODER_STATUS_INCOMPLETE. It is then the caller's
responsibility to keep the existing metadata and append more metadata
to it and then call ctf_metadata_decoder_decode() again with this,
until the function returns CTF_METADATA_DECODER_STATUS_OK or another
error.

At anytime you can get the CTF metadata decoder's associated CTF IR
trace object with ctf_metadata_decoder_get_trace(). The trace object is
initially empty: as you call ctf_metadata_decoder_decode(), the decoder
makes it grow by adding other CTF IR objects to it: stream classes,
event classes to new or existing stream classes, clock classes, etc.

The public ctf_metadata_decoder_is_packetized() and
ctf_metadata_decoder_packetized_file_stream_to_buf() functions exist
only for the `metadata-info` ctf.fs query for the moment.

Also in this patch:

* The identical btr/print.h and notif-iter/print.h is moved to
  metadata/print.h.
* A fix is added to the AST-to-CTF IR visitor to pop the current
  declaration scope at the end of visit_event_decl().

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
15 files changed:
plugins/ctf/common/Makefile.am
plugins/ctf/common/btr/Makefile.am
plugins/ctf/common/btr/btr.c
plugins/ctf/common/btr/print.h [deleted file]
plugins/ctf/common/metadata/Makefile.am
plugins/ctf/common/metadata/ast.h
plugins/ctf/common/metadata/decoder.c [new file with mode: 0644]
plugins/ctf/common/metadata/decoder.h [new file with mode: 0644]
plugins/ctf/common/metadata/visitor-generate-ir.c
plugins/ctf/common/notif-iter/Makefile.am
plugins/ctf/common/notif-iter/notif-iter.c
plugins/ctf/common/notif-iter/print.h [deleted file]
plugins/ctf/common/print.h [new file with mode: 0644]
plugins/ctf/fs/fs.c
plugins/ctf/fs/metadata.c

index 3c57f0a2e5840e41f62d3de813abe1e9dd7eeaa4..63d77fc94a3c01b95812e63d4329022e342002ae 100644 (file)
@@ -3,7 +3,7 @@ SUBDIRS = btr notif-iter metadata
 AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
 
 noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-common.la
-libbabeltrace_plugin_ctf_common_la_SOURCES = 
+libbabeltrace_plugin_ctf_common_la_SOURCES = print.h
 libbabeltrace_plugin_ctf_common_la_LIBADD =            \
        $(builddir)/btr/libctf-btr.la           \
        $(builddir)/metadata/libctf-parser.la   \
index 4ad2b0ee6d5f2298a1b3152ee273b7e88444db0d..4602514f0305cae4cdb7fe9387afafc9229f8e0d 100644 (file)
@@ -3,5 +3,4 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
 noinst_LTLIBRARIES = libctf-btr.la
 libctf_btr_la_SOURCES = \
        btr.c \
-       btr.h \
-       print.h
+       btr.h
index e7762a3dd08af0ae08510f17ad41ebf62728c611..7c48bd0826a848e6a03639e1ba53c0a3363315a2 100644 (file)
@@ -39,7 +39,7 @@
 
 #define PRINT_ERR_STREAM       btr->err_stream
 #define PRINT_PREFIX           "ctf-btr"
-#include "print.h"
+#include "../print.h"
 
 #define DIV8(_x)                       ((_x) >> 3)
 #define BYTES_TO_BITS(_x)              ((_x) * 8)
diff --git a/plugins/ctf/common/btr/print.h b/plugins/ctf/common/btr/print.h
deleted file mode 100644 (file)
index 22381dc..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef CTF_BTR_PRINT_H
-#define CTF_BTR_PRINT_H
-
-/*
- * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <babeltrace/babeltrace-internal.h>
-
-#define PERR(fmt, ...)                                                 \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Error: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PWARN(fmt, ...)                                                        \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Warning: " PRINT_PREFIX ": " fmt,      \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PDBG(fmt, ...)                                                 \
-       do {                                                            \
-               if (babeltrace_debug) {                                 \
-                       fprintf(stderr,                                 \
-                               "Debug: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#endif /* CTF_BTR_PRINT_H */
index a7a4631dbdb6f29cf3dc13487debac5f078ebc38..5ca0873a53b65b1414341ab08046c1ce9ce948dc 100644 (file)
@@ -20,7 +20,9 @@ libctf_ast_la_SOURCES = \
        objstack.h \
        parser.h \
        scanner.h \
-       scanner-symbols.h
+       scanner-symbols.h \
+       decoder.c \
+       decoder.h
 
 libctf_ast_la_LIBADD = $(top_builddir)/lib/libbabeltrace.la
 
index 232c2e75a945bc1a28ec5eec7b6a605d04b8ba02..684ea6b84861fe9355f321aa505592aad81cebf5 100644 (file)
@@ -22,6 +22,7 @@
 #include <glib.h>
 #include <babeltrace/list.h>
 #include <babeltrace/ctf-ir/trace.h>
+#include <babeltrace/babeltrace-internal.h>
 
 // the parameter name (of the reentrant 'yyparse' function)
 // data is a pointer to a 'SParserParam' structure
@@ -29,6 +30,9 @@
 
 struct ctf_node;
 struct ctf_parser;
+struct ctf_visitor_generate_ir;
+
+#define EINCOMPLETE    1000
 
 #define FOREACH_CTF_NODES(F) \
        F(NODE_UNKNOWN) \
@@ -303,19 +307,24 @@ struct ctf_ast {
 
 const char *node_type(struct ctf_node *node);
 
-struct ctf_trace;
+BT_HIDDEN
+struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd,
+               uint64_t clock_class_offset_ns);
+
+void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor);
 
 BT_HIDDEN
-int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
-               struct bt_ctf_trace **trace, uint64_t clock_offset_ns);
+struct bt_ctf_trace *ctf_visitor_generate_ir_get_trace(
+               struct ctf_visitor_generate_ir *visitor);
 
 BT_HIDDEN
-int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node);
+int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
+               struct ctf_node *node);
 
 BT_HIDDEN
-int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node);
+int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node);
 
 BT_HIDDEN
-int ctf_destroy_metadata(struct ctf_trace *trace);
+int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node);
 
 #endif /* _CTF_AST_H */
diff --git a/plugins/ctf/common/metadata/decoder.c b/plugins/ctf/common/metadata/decoder.c
new file mode 100644 (file)
index 0000000..6dbd816
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <babeltrace/compat/uuid.h>
+#include <babeltrace/compat/memstream.h>
+#include <babeltrace/ctf-ir/trace.h>
+#include <glib.h>
+
+#include "ast.h"
+#include "decoder.h"
+#include "scanner.h"
+
+#define PRINT_ERR_STREAM       mdec->err_stream
+#define PRINT_PREFIX           "metadata-decoder"
+#include "../print.h"
+
+#define TSDL_MAGIC     0x75d11d57
+
+struct ctf_metadata_decoder {
+       struct ctf_visitor_generate_ir *visitor;
+       FILE *err_stream;
+       uint8_t uuid[16];
+       bool is_uuid_set;
+       int bo;
+};
+
+struct packet_header {
+       uint32_t magic;
+       uint8_t  uuid[16];
+       uint32_t checksum;
+       uint32_t content_size;
+       uint32_t packet_size;
+       uint8_t  compression_scheme;
+       uint8_t  encryption_scheme;
+       uint8_t  checksum_scheme;
+       uint8_t  major;
+       uint8_t  minor;
+} __attribute__((__packed__));
+
+BT_HIDDEN
+bool ctf_metadata_decoder_is_packetized(FILE *fp, int *byte_order)
+{
+       uint32_t magic;
+       size_t len;
+       int ret = 0;
+
+       len = fread(&magic, sizeof(magic), 1, fp);
+       if (len != 1) {
+               goto end;
+       }
+
+       if (byte_order) {
+               if (magic == TSDL_MAGIC) {
+                       ret = 1;
+                       *byte_order = BYTE_ORDER;
+               } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
+                       ret = 1;
+                       *byte_order = BYTE_ORDER == BIG_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN;
+               }
+       }
+
+end:
+       rewind(fp);
+
+       return ret;
+}
+
+static
+bool is_version_valid(unsigned int major, unsigned int minor)
+{
+       return major == 1 && minor == 8;
+}
+
+static
+int decode_packet(struct ctf_metadata_decoder *mdec, FILE *in_fp, FILE *out_fp,
+               int byte_order)
+{
+       struct packet_header header;
+       size_t readlen, writelen, toread;
+       uint8_t buf[512 + 1];   /* + 1 for debug-mode \0 */
+       int ret = 0;
+
+       readlen = fread(&header, sizeof(header), 1, in_fp);
+       if (feof(in_fp) != 0) {
+               goto end;
+       }
+       if (readlen < 1) {
+               goto error;
+       }
+
+       if (byte_order != BYTE_ORDER) {
+               header.magic = GUINT32_SWAP_LE_BE(header.magic);
+               header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
+               header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
+               header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
+       }
+
+       if (header.compression_scheme) {
+               PERR("Metadata packet compression not supported yet\n");
+               goto error;
+       }
+
+       if (header.encryption_scheme) {
+               PERR("Metadata packet encryption not supported yet\n");
+               goto error;
+       }
+
+       if (header.checksum || header.checksum_scheme) {
+               PERR("Metadata packet checksum verification not supported yet\n");
+               goto error;
+       }
+
+       if (!is_version_valid(header.major, header.minor)) {
+               PERR("Invalid metadata version: %u.%u\n", header.major,
+                       header.minor);
+               goto error;
+       }
+
+       /* Set expected trace UUID if not set; otherwise validate it */
+       if (mdec) {
+               if (!mdec->is_uuid_set) {
+                       memcpy(mdec->uuid, header.uuid, sizeof(header.uuid));
+                       mdec->is_uuid_set = true;
+               } else if (bt_uuid_compare(header.uuid, mdec->uuid)) {
+                       PERR("Metadata UUID mismatch between packets of the same stream\n");
+                       goto error;
+               }
+       }
+
+       if ((header.content_size / CHAR_BIT) < sizeof(header)) {
+               PERR("Bad metadata packet content size: %u\n",
+                       header.content_size);
+               goto error;
+       }
+
+       toread = header.content_size / CHAR_BIT - sizeof(header);
+
+       for (;;) {
+               readlen = fread(buf, sizeof(uint8_t),
+                       MIN(sizeof(buf) - 1, toread), in_fp);
+               if (ferror(in_fp)) {
+                       PERR("Cannot read metadata packet buffer (at position %ld)\n",
+                               ftell(in_fp));
+                       goto error;
+               }
+
+               writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
+               if (writelen < readlen || ferror(out_fp)) {
+                       PERR("Cannot write decoded metadata text to buffer\n");
+                       goto error;
+               }
+
+               toread -= readlen;
+               if (toread == 0) {
+                       int fseek_ret;
+
+                       /* Read leftover padding */
+                       toread = (header.packet_size - header.content_size) /
+                               CHAR_BIT;
+                       fseek_ret = fseek(in_fp, toread, SEEK_CUR);
+                       if (fseek_ret < 0) {
+                               PWARN("Missing padding at the end of the metadata file\n");
+                       }
+
+                       break;
+               }
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int ctf_metadata_decoder_packetized_file_stream_to_buf_with_mdec(
+               struct ctf_metadata_decoder *mdec, FILE *fp,
+               char **buf, int byte_order)
+{
+       FILE *out_fp;
+       size_t size;
+       int ret = 0;
+       int tret;
+       size_t packet_index = 0;
+
+       out_fp = bt_open_memstream(buf, &size);
+       if (out_fp == NULL) {
+               PERR("Cannot open memory stream: %s\n", strerror(errno));
+               goto error;
+       }
+
+       for (;;) {
+               if (feof(fp) != 0) {
+                       break;
+               }
+
+               tret = decode_packet(mdec, fp, out_fp, byte_order);
+               if (tret) {
+                       PERR("Cannot decode packet #%zu\n", packet_index);
+                       goto error;
+               }
+
+               packet_index++;
+       }
+
+       /* Make sure the whole string ends with a null character */
+       tret = fputc('\0', out_fp);
+       if (tret == EOF) {
+               PERR("Cannot append '\\0' to the decoded metadata buffer\n");
+               goto error;
+       }
+
+       /* Close stream, which also flushes the buffer */
+       ret = bt_close_memstream(buf, &size, out_fp);
+       if (ret < 0) {
+               PERR("Cannot close memory stream: %s\n", strerror(errno));
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+       if (out_fp) {
+               bt_close_memstream(buf, &size, out_fp);
+       }
+
+       if (*buf) {
+               free(*buf);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_metadata_decoder_packetized_file_stream_to_buf(
+               FILE *fp, char **buf, int byte_order)
+{
+       return ctf_metadata_decoder_packetized_file_stream_to_buf_with_mdec(
+               NULL, fp, buf, byte_order);
+}
+
+BT_HIDDEN
+struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err,
+               uint64_t clock_class_offset_ns)
+{
+       struct ctf_metadata_decoder *mdec =
+               g_new0(struct ctf_metadata_decoder, 1);
+
+       if (!mdec) {
+               goto end;
+       }
+
+       mdec->err_stream = err;
+       mdec->visitor = ctf_visitor_generate_ir_create(err,
+               clock_class_offset_ns);
+       if (!mdec->visitor) {
+               ctf_metadata_decoder_destroy(mdec);
+               mdec = NULL;
+               goto end;
+       }
+
+end:
+       return mdec;
+}
+
+BT_HIDDEN
+void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *mdec)
+{
+       if (!mdec) {
+               return;
+       }
+
+       ctf_visitor_generate_ir_destroy(mdec->visitor);
+       g_free(mdec);
+}
+
+BT_HIDDEN
+enum ctf_metadata_decoder_status ctf_metadata_decoder_decode(
+               struct ctf_metadata_decoder *mdec, FILE *fp)
+{
+       enum ctf_metadata_decoder_status status =
+               CTF_METADATA_DECODER_STATUS_OK;
+       int ret;
+       struct ctf_scanner *scanner = NULL;
+       char *buf = NULL;
+       bool close_fp = false;
+
+       assert(mdec);
+
+       if (ctf_metadata_decoder_is_packetized(fp, &mdec->bo)) {
+               PDBG("Metadata stream is packetized\n");
+               ret = ctf_metadata_decoder_packetized_file_stream_to_buf_with_mdec(
+                       mdec, fp, &buf, mdec->bo);
+               if (ret) {
+                       // log: details
+                       status = CTF_METADATA_DECODER_STATUS_ERROR;
+                       goto end;
+               }
+
+               /* Convert the real file pointer to a memory file pointer */
+               fp = bt_fmemopen(buf, strlen(buf), "rb");
+               close_fp = true;
+               if (!fp) {
+                       PERR("Cannot memory-open metadata buffer: %s\n",
+                               strerror(errno));
+                       status = CTF_METADATA_DECODER_STATUS_ERROR;
+                       goto end;
+               }
+       } else {
+               unsigned int major, minor;
+               ssize_t nr_items;
+               const long init_pos = ftell(fp);
+
+               PDBG("Metadata stream is plain text\n");
+
+               /* Check text-only metadata header and version */
+               nr_items = fscanf(fp, "/* CTF %10u.%10u", &major, &minor);
+               if (nr_items < 2) {
+                       PWARN("Ill-shapen or missing \"/* CTF major.minor\" header in plain text metadata file stream\n");
+               }
+
+               PDBG("Metadata version: %u.%u\n", major, minor);
+
+               if (!is_version_valid(major, minor)) {
+                       PERR("Invalid metadata version: %u.%u\n", major, minor);
+                       status = CTF_METADATA_DECODER_STATUS_INVAL_VERSION;
+                       goto end;
+               }
+
+               if (fseek(fp, init_pos, SEEK_SET)) {
+                       PERR("Cannot seek metadata file stream to initial position: %s\n",
+                               strerror(errno));
+                       status = CTF_METADATA_DECODER_STATUS_ERROR;
+                       goto end;
+               }
+       }
+
+       /* Allocate a scanner and append the metadata text content */
+       scanner = ctf_scanner_alloc();
+       if (!scanner) {
+               PERR("Cannot allocate a metadata lexical scanner\n");
+               status = CTF_METADATA_DECODER_STATUS_ERROR;
+               goto end;
+       }
+
+       assert(fp);
+       ret = ctf_scanner_append_ast(scanner, fp);
+       if (ret) {
+               PERR("Cannot create the metadata AST\n");
+               status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
+               goto end;
+       }
+
+       ret = ctf_visitor_semantic_check(stderr, 0, &scanner->ast->root);
+       if (ret) {
+               PERR("Metadata semantic validation failed\n");
+               status = CTF_METADATA_DECODER_STATUS_ERROR;
+               goto end;
+       }
+
+       ret = ctf_visitor_generate_ir_visit_node(mdec->visitor,
+               &scanner->ast->root);
+       switch (ret) {
+       case 0:
+               /* Success */
+               break;
+       case -EINCOMPLETE:
+               PDBG("While visiting AST: incomplete data\n");
+               status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
+               goto end;
+       default:
+               PERR("Cannot visit AST node to create CTF IR objects\n");
+               status = CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR;
+               goto end;
+       }
+
+end:
+       if (scanner) {
+               ctf_scanner_free(scanner);
+       }
+
+       if (fp && close_fp) {
+               if (fclose(fp)) {
+                       PERR("Cannot close metadata file stream\n");
+               }
+       }
+
+       if (buf) {
+               free(buf);
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+struct bt_ctf_trace *ctf_metadata_decoder_get_trace(
+               struct ctf_metadata_decoder *mdec)
+{
+       return ctf_visitor_generate_ir_get_trace(mdec->visitor);
+}
diff --git a/plugins/ctf/common/metadata/decoder.h b/plugins/ctf/common/metadata/decoder.h
new file mode 100644 (file)
index 0000000..dd60c21
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef _METADATA_DECODER_H
+#define _METADATA_DECODER_H
+
+/*
+ * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <stdint.h>
+
+struct bt_ctf_trace;
+
+/* A CTF metadata decoder object */
+struct ctf_metadata_decoder;
+
+/* CTF metadata decoder status */
+enum ctf_metadata_decoder_status {
+       CTF_METADATA_DECODER_STATUS_OK                  = 0,
+       CTF_METADATA_DECODER_STATUS_ERROR               = -1,
+       CTF_METADATA_DECODER_STATUS_INCOMPLETE          = -2,
+       CTF_METADATA_DECODER_STATUS_INVAL_VERSION       = -3,
+       CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR    = -4,
+};
+
+/*
+ * Creates a CTF metadata decoder with `err` as the error stream (can
+ * be `NULL` to disable error output). `clock_class_offset_ns` is an
+ * offset to apply to the decoded clock classes's offsets.
+ *
+ * Returns `NULL` on error.
+ */
+BT_HIDDEN
+struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err,
+               uint64_t clock_class_offset_ns);
+
+/*
+ * Destroys a CTF metadata decoder that you created with
+ * ctf_metadata_decoder_create().
+ */
+BT_HIDDEN
+void ctf_metadata_decoder_destroy(
+               struct ctf_metadata_decoder *metadata_decoder);
+
+/*
+ * Decodes a new chunk of CTF metadata.
+ *
+ * This function reads the metadata from the current position of `fp`
+ * until the end of this file stream. If it finds new information (new
+ * event class, new stream class, or new clock class), it appends this
+ * information to the decoder's trace object (as returned by
+ * ctf_metadata_get_trace()), or it creates this trace.
+ *
+ * The metadata can be packetized or not.
+ *
+ * The metadata chunk needs to be complete and scannable, that is,
+ * zero or more complete top-level blocks. If it's incomplete, this
+ * function returns `CTF_METADATA_DECODER_STATUS_INCOMPLETE`. If this
+ * function returns `CTF_METADATA_DECODER_STATUS_INCOMPLETE`, then you
+ * need to call it again with the same metadata and more to make it
+ * complete. For example:
+ *
+ *     First call:  event { name = hell
+ *     Second call: event { name = hello_world; ... };
+ *
+ * If the conversion from the metadata text to CTF IR objects fails,
+ * this function returns `CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR`.
+ *
+ * If everything goes as expected, this function returns
+ * `CTF_METADATA_DECODER_STATUS_OK`.
+ */
+BT_HIDDEN
+enum ctf_metadata_decoder_status ctf_metadata_decoder_decode(
+               struct ctf_metadata_decoder *metadata_decoder, FILE *fp);
+
+/*
+ * Returns a new reference to the current CTF IR trace object which is
+ * the result of the metadata decoding process.
+ *
+ * The trace object, once created, remains the same until you call
+ * ctf_metadata_decoder_destroy().
+ */
+BT_HIDDEN
+struct bt_ctf_trace *ctf_metadata_decoder_get_trace(
+               struct ctf_metadata_decoder *metadata_decoder);
+
+/*
+ * Checks whether or not a given metadata file stream is packetized, and
+ * if so, sets `*byte_order` to the byte order of the first packet.
+ */
+BT_HIDDEN
+bool ctf_metadata_decoder_is_packetized(FILE *fp, int *byte_order);
+
+/*
+ * Decodes a packetized metadata file stream to a NULL-terminated
+ * text buffer using the given byte order.
+ */
+BT_HIDDEN
+int ctf_metadata_decoder_packetized_file_stream_to_buf(
+               FILE *fp, char **buf, int byte_order);
+
+#endif /* _METADATA_DECODER_H */
index 3018fbcce16f5e060249f2e312b1e8335cff80dc..e3ca366fba4e26c5dca8cdca1329cb1747b12a97 100644 (file)
@@ -152,30 +152,35 @@ enum loglevel {
 /* Error printing wrappers */
 #define _PERROR(_fmt, ...)                                     \
        do {                                                    \
+               if (!ctx->efd) break;                           \
                fprintf(ctx->efd, "[error] %s: " _fmt "\n",     \
                        __func__, __VA_ARGS__);                 \
        } while (0)
 
 #define _PWARNING(_fmt, ...)                                   \
        do {                                                    \
+               if (!ctx->efd) break;                           \
                fprintf(ctx->efd, "[warning] %s: " _fmt "\n",   \
                        __func__, __VA_ARGS__);                 \
        } while (0)
 
 #define _FPERROR(_stream, _fmt, ...)                           \
        do {                                                    \
+               if (!_stream) break;                            \
                fprintf(_stream, "[error] %s: " _fmt "\n",      \
                        __func__, __VA_ARGS__);                 \
        } while (0)
 
 #define _FPWARNING(_stream, _fmt, ...)                         \
        do {                                                    \
+               if (!_stream) break;                            \
                fprintf(_stream, "[warning] %s: " _fmt "\n",    \
                        __func__, __VA_ARGS__);                 \
        } while (0)
 
 #define _PERROR_DUP_ATTR(_attr, _entity)                       \
        do {                                                    \
+               if (!ctx->efd) break;                           \
                fprintf(ctx->efd,                               \
                        "[error] %s: duplicate attribute \""    \
                        _attr "\" in " _entity "\n", __func__); \
@@ -199,10 +204,10 @@ struct ctx_decl_scope {
 };
 
 /*
- * Visitor context.
+ * Visitor context (private).
  */
 struct ctx {
-       /* Trace being filled (weak ref.) */
+       /* Trace being filled (owned by this) */
        struct bt_ctf_trace *trace;
 
        /* Error stream to use during visit */
@@ -214,7 +219,11 @@ struct ctx {
        /* 1 if trace declaration is visited */
        int is_trace_visited;
 
+       /* Offset (ns) to apply to clock classes on creation */
+       uint64_t clock_class_offset_ns;
+
        /* Trace attributes */
+       enum bt_ctf_byte_order trace_bo;
        uint64_t trace_major;
        uint64_t trace_minor;
        unsigned char trace_uuid[BABELTRACE_UUID_LEN];
@@ -227,6 +236,11 @@ struct ctx {
        GHashTable *stream_classes;
 };
 
+/*
+ * Visitor (public).
+ */
+struct ctf_visitor_generate_ir { };
+
 static
 const char *loglevel_str [] = {
        [ LOGLEVEL_EMERG ] = "TRACE_EMERG",
@@ -562,12 +576,13 @@ int ctx_decl_scope_register_variant(struct ctx_decl_scope *scope,
  * @returns    New visitor context, or NULL on error
  */
 static
-struct ctx *ctx_create(struct bt_ctf_trace *trace, FILE *efd)
+struct ctx *ctx_create(struct bt_ctf_trace *trace, FILE *efd,
+               uint64_t clock_class_offset_ns)
 {
        struct ctx *ctx = NULL;
        struct ctx_decl_scope *scope = NULL;
 
-       ctx = g_new(struct ctx, 1);
+       ctx = g_new0(struct ctx, 1);
        if (!ctx) {
                goto error;
        }
@@ -587,14 +602,13 @@ struct ctx *ctx_create(struct bt_ctf_trace *trace, FILE *efd)
        ctx->trace = trace;
        ctx->efd = efd;
        ctx->current_scope = scope;
-       ctx->is_trace_visited = FALSE;
-
+       ctx->trace_bo = BT_CTF_BYTE_ORDER_NATIVE;
+       ctx->clock_class_offset_ns = clock_class_offset_ns;
        return ctx;
 
 error:
        g_free(ctx);
        ctx_decl_scope_destroy(scope);
-
        return NULL;
 }
 
@@ -624,6 +638,7 @@ void ctx_destroy(struct ctx *ctx)
                scope = parent_scope;
        }
 
+       bt_put(ctx->trace);
        g_hash_table_destroy(ctx->stream_classes);
        g_free(ctx);
 
@@ -2505,7 +2520,7 @@ int visit_integer_decl(struct ctx *ctx,
                                        goto error;
                                }
 
-                               _PWARNING("invalid \"map\" attribute in integer declaration: unknown clock: \"%s\"",
+                               _PWARNING("invalid \"map\" attribute in integer declaration: unknown clock class: \"%s\"",
                                        s_right);
                                _SET(&set, _INTEGER_MAP_SET);
                                g_free(s_right);
@@ -2515,7 +2530,7 @@ int visit_integer_decl(struct ctx *ctx,
                        mapped_clock = bt_ctf_trace_get_clock_class_by_name(
                                ctx->trace, clock_name);
                        if (!mapped_clock) {
-                               _PERROR("invalid \"map\" attribute in integer declaration: cannot find clock \"%s\"",
+                               _PERROR("invalid \"map\" attribute in integer declaration: cannot find clock class \"%s\"",
                                        clock_name);
                                ret = -EINVAL;
                                goto error;
@@ -3333,8 +3348,9 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
        char *event_name = NULL;
        struct bt_ctf_event_class *event_class = NULL;
        struct bt_ctf_event_class *eevent_class;
-       struct bt_ctf_stream_class *stream_class;
+       struct bt_ctf_stream_class *stream_class = NULL;
        struct bt_list_head *decl_list = &node->u.event.declaration_list;
+       bool pop_scope = false;
 
        if (node->visited) {
                goto end;
@@ -3359,13 +3375,14 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
                goto error;
        }
 
-
        ret = ctx_push_scope(ctx);
        if (ret) {
                _PERROR("%s", "cannot push scope");
                goto error;
        }
 
+       pop_scope = true;
+
        bt_list_for_each_entry(iter, decl_list, siblings) {
                ret = visit_event_decl_entry(ctx, iter, event_class,
                        &stream_id, &set);
@@ -3377,11 +3394,17 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
        if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) {
                GList *keys = NULL;
                struct bt_ctf_stream_class *new_stream_class;
+               size_t stream_class_count =
+                       g_hash_table_size(ctx->stream_classes) +
+                       bt_ctf_trace_get_stream_class_count(ctx->trace);
 
-               /* Allow missing stream_id if there is only a single stream */
-               switch (g_hash_table_size(ctx->stream_classes)) {
+               /*
+                * Allow missing stream_id if there is only a single
+                * stream class.
+                */
+               switch (stream_class_count) {
                case 0:
-                       /* Create stream if there's none */
+                       /* Create implicit stream class if there's none */
                        new_stream_class = create_reset_stream_class(ctx);
                        if (!new_stream_class) {
                                ret = -EINVAL;
@@ -3390,7 +3413,7 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
 
                        ret = bt_ctf_stream_class_set_id(new_stream_class, 0);
                        if (ret) {
-                               _PERROR("%s", "cannot set stream's ID");
+                               _PERROR("%s", "cannot set stream class's ID");
                                BT_PUT(new_stream_class);
                                goto error;
                        }
@@ -3401,14 +3424,23 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
                        g_hash_table_insert(ctx->stream_classes,
                                (gpointer) stream_id, new_stream_class);
                        new_stream_class = NULL;
-
                        break;
                case 1:
-                       /* Single stream: get its ID */
-                       keys = g_hash_table_get_keys(ctx->stream_classes);
-                       stream_id = (int64_t) keys->data;
-                       g_list_free(keys);
-                       keys = NULL;
+                       /* Single stream class: get its ID */
+                       if (g_hash_table_size(ctx->stream_classes) == 1) {
+                               keys = g_hash_table_get_keys(ctx->stream_classes);
+                               stream_id = (int64_t) keys->data;
+                               g_list_free(keys);
+                       } else {
+                               assert(bt_ctf_trace_get_stream_class_count(
+                                       ctx->trace) == 1);
+                               stream_class = bt_ctf_trace_get_stream_class(
+                                       ctx->trace, 0);
+                               assert(stream_class);
+                               stream_id = bt_ctf_stream_class_get_id(
+                                       stream_class);
+                               BT_PUT(stream_class);
+                       }
                        break;
                default:
                        _PERROR("%s", "missing \"stream_id\" attribute in event declaration");
@@ -3417,20 +3449,25 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
                }
        }
 
-
-
        assert(stream_id >= 0);
 
-       /* We have the stream ID now; borrow the stream class if found */
+       /* We have the stream ID now; get the stream class if found */
        stream_class = g_hash_table_lookup(ctx->stream_classes,
                (gpointer) stream_id);
+       bt_get(stream_class);
        if (!stream_class) {
-               _PERROR("cannot find stream class with ID %" PRId64,
+               stream_class = bt_ctf_trace_get_stream_class_by_id(ctx->trace,
                        stream_id);
-               ret = -EINVAL;
-               goto error;
+               if (!stream_class) {
+                       _PERROR("cannot find stream class with ID %" PRId64,
+                               stream_id);
+                       ret = -EINVAL;
+                       goto error;
+               }
        }
 
+       assert(stream_class);
+
        if (!_IS_SET(&set, _EVENT_ID_SET)) {
                /* Allow only one event without ID per stream */
                if (bt_ctf_stream_class_get_event_class_count(stream_class) !=
@@ -3469,32 +3506,31 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
                event_name);
        if (eevent_class) {
                BT_PUT(eevent_class);
-               eevent_class = NULL;
                _PERROR("%s",
                        "duplicate event with name \"%s\" in same stream");
                ret = -EEXIST;
                goto error;
        }
 
-       g_free(event_name);
        ret = bt_ctf_stream_class_add_event_class(stream_class, event_class);
        BT_PUT(event_class);
-       event_class = NULL;
-
        if (ret) {
                _PERROR("%s", "cannot add event class to stream class");
                goto error;
        }
 
-end:
-       return 0;
+       goto end;
 
 error:
-       g_free(event_name);
-       BT_PUT(event_class);
+       bt_put(event_class);
 
-       /* stream_class is borrowed; it still belongs to the hash table */
+end:
+       if (pop_scope) {
+               ctx_pop_scope(ctx);
+       }
 
+       g_free(event_name);
+       bt_put(stream_class);
        return ret;
 }
 
@@ -3683,6 +3719,7 @@ int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
        int ret = 0;
        struct ctf_node *iter;
        struct bt_ctf_stream_class *stream_class = NULL;
+       struct bt_ctf_stream_class *existing_stream_class = NULL;
        struct bt_list_head *decl_list = &node->u.stream.declaration_list;
 
        if (node->visited) {
@@ -3761,17 +3798,35 @@ int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
                goto error;
        }
 
+       /*
+        * Make sure that this stream class's ID is currently unique in
+        * the trace.
+        */
+       if (g_hash_table_lookup(ctx->stream_classes, (gpointer) id)) {
+               _PERROR("a stream class with ID: %" PRId64 " already exists in the trace", id);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       existing_stream_class = bt_ctf_trace_get_stream_class_by_id(ctx->trace,
+               id);
+       if (existing_stream_class) {
+               _PERROR("a stream class with ID: %" PRId64 " already exists in the trace", id);
+               ret = -EINVAL;
+               goto error;
+       }
+
        /* Move reference to visitor's context */
        g_hash_table_insert(ctx->stream_classes, (gpointer) (int64_t) id,
                stream_class);
        stream_class = NULL;
-
-end:
-       return 0;
+       goto end;
 
 error:
-       BT_PUT(stream_class);
+       bt_put(stream_class);
 
+end:
+       bt_put(existing_stream_class);
        return ret;
 }
 
@@ -4123,6 +4178,7 @@ int set_trace_byte_order(struct ctx *ctx, struct ctf_node *trace_node)
                                        goto error;
                                }
 
+                               ctx->trace_bo = bo;
                                ret = bt_ctf_trace_set_native_byte_order(
                                        ctx->trace, bo);
                                if (ret) {
@@ -4173,7 +4229,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                char *right;
 
                if (_IS_SET(set, _CLOCK_NAME_SET)) {
-                       _PERROR_DUP_ATTR("name", "clock declaration");
+                       _PERROR_DUP_ATTR("name", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
@@ -4181,14 +4237,14 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                right = concatenate_unary_strings(
                        &entry_node->u.ctf_expression.right);
                if (!right) {
-                       _PERROR("%s", "unexpected unary expression for clock declaration's \"name\" attribute");
+                       _PERROR("%s", "unexpected unary expression for clock class declaration's \"name\" attribute");
                        ret = -EINVAL;
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_name(clock, right);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's name");
+                       _PERROR("%s", "cannot set clock class's name");
                        g_free(right);
                        goto error;
                }
@@ -4199,20 +4255,20 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                unsigned char uuid[BABELTRACE_UUID_LEN];
 
                if (_IS_SET(set, _CLOCK_UUID_SET)) {
-                       _PERROR_DUP_ATTR("uuid", "clock declaration");
+                       _PERROR_DUP_ATTR("uuid", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
 
                ret = get_unary_uuid(&entry_node->u.ctf_expression.right, uuid);
                if (ret) {
-                       _PERROR("%s", "invalid clock UUID");
+                       _PERROR("%s", "invalid clock class UUID");
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_uuid(clock, uuid);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's UUID");
+                       _PERROR("%s", "cannot set clock class's UUID");
                        goto error;
                }
 
@@ -4221,7 +4277,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                char *right;
 
                if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
-                       _PERROR_DUP_ATTR("description", "clock declaration");
+                       _PERROR_DUP_ATTR("description", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
@@ -4229,14 +4285,14 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                right = concatenate_unary_strings(
                        &entry_node->u.ctf_expression.right);
                if (!right) {
-                       _PERROR("%s", "unexpected unary expression for clock's \"description\" attribute");
+                       _PERROR("%s", "unexpected unary expression for clock class's \"description\" attribute");
                        ret = -EINVAL;
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_description(clock, right);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's description");
+                       _PERROR("%s", "cannot set clock class's description");
                        g_free(right);
                        goto error;
                }
@@ -4247,7 +4303,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                uint64_t freq;
 
                if (_IS_SET(set, _CLOCK_FREQ_SET)) {
-                       _PERROR_DUP_ATTR("freq", "clock declaration");
+                       _PERROR_DUP_ATTR("freq", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
@@ -4255,14 +4311,14 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                ret = get_unary_unsigned(
                        &entry_node->u.ctf_expression.right, &freq);
                if (ret) {
-                       _PERROR("%s", "unexpected unary expression for clock declaration's \"freq\" attribute");
+                       _PERROR("%s", "unexpected unary expression for clock class declaration's \"freq\" attribute");
                        ret = -EINVAL;
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_frequency(clock, freq);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's frequency");
+                       _PERROR("%s", "cannot set clock class's frequency");
                        goto error;
                }
 
@@ -4271,7 +4327,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                uint64_t precision;
 
                if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
-                       _PERROR_DUP_ATTR("precision", "clock declaration");
+                       _PERROR_DUP_ATTR("precision", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
@@ -4279,14 +4335,14 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                ret = get_unary_unsigned(
                        &entry_node->u.ctf_expression.right, &precision);
                if (ret) {
-                       _PERROR("%s", "unexpected unary expression for clock declaration's \"precision\" attribute");
+                       _PERROR("%s", "unexpected unary expression for clock class declaration's \"precision\" attribute");
                        ret = -EINVAL;
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_precision(clock, precision);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's precision");
+                       _PERROR("%s", "cannot set clock class's precision");
                        goto error;
                }
 
@@ -4295,7 +4351,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                uint64_t offset_s;
 
                if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
-                       _PERROR_DUP_ATTR("offset_s", "clock declaration");
+                       _PERROR_DUP_ATTR("offset_s", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
@@ -4303,14 +4359,14 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                ret = get_unary_unsigned(
                        &entry_node->u.ctf_expression.right, &offset_s);
                if (ret) {
-                       _PERROR("%s", "unexpected unary expression for clock declaration's \"offset_s\" attribute");
+                       _PERROR("%s", "unexpected unary expression for clock class declaration's \"offset_s\" attribute");
                        ret = -EINVAL;
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_offset_s(clock, offset_s);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's offset in seconds");
+                       _PERROR("%s", "cannot set clock class's offset in seconds");
                        goto error;
                }
 
@@ -4319,7 +4375,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                uint64_t offset;
 
                if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
-                       _PERROR_DUP_ATTR("offset", "clock declaration");
+                       _PERROR_DUP_ATTR("offset", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
@@ -4327,14 +4383,14 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                ret = get_unary_unsigned(
                        &entry_node->u.ctf_expression.right, &offset);
                if (ret) {
-                       _PERROR("%s", "unexpected unary expression for clock declaration's \"offset\" attribute");
+                       _PERROR("%s", "unexpected unary expression for clock class declaration's \"offset\" attribute");
                        ret = -EINVAL;
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_offset_cycles(clock, offset);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's offset in cycles");
+                       _PERROR("%s", "cannot set clock class's offset in cycles");
                        goto error;
                }
 
@@ -4343,7 +4399,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                struct ctf_node *right;
 
                if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
-                       _PERROR_DUP_ATTR("absolute", "clock declaration");
+                       _PERROR_DUP_ATTR("absolute", "clock class declaration");
                        ret = -EPERM;
                        goto error;
                }
@@ -4353,20 +4409,20 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                        struct ctf_node, siblings);
                ret = get_boolean(ctx->efd, right);
                if (ret < 0) {
-                       _PERROR("%s", "unexpected unary expression for clock declaration's \"absolute\" attribute");
+                       _PERROR("%s", "unexpected unary expression for clock class declaration's \"absolute\" attribute");
                        ret = -EINVAL;
                        goto error;
                }
 
                ret = bt_ctf_clock_class_set_is_absolute(clock, ret);
                if (ret) {
-                       _PERROR("%s", "cannot set clock's absolute option");
+                       _PERROR("%s", "cannot set clock class's absolute option");
                        goto error;
                }
 
                _SET(set, _CLOCK_ABSOLUTE_SET);
        } else {
-               _PWARNING("unknown attribute \"%s\" in clock declaration",
+               _PWARNING("unknown attribute \"%s\" in clock class declaration",
                        left);
        }
 
@@ -4397,8 +4453,7 @@ uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns)
 }
 
 static
-int apply_clock_offset(struct ctx *ctx, struct bt_ctf_clock_class *clock,
-               uint64_t clock_offset_ns)
+int apply_clock_class_offset(struct ctx *ctx, struct bt_ctf_clock_class *clock)
 {
        int ret;
        uint64_t freq;
@@ -4406,20 +4461,19 @@ int apply_clock_offset(struct ctx *ctx, struct bt_ctf_clock_class *clock,
 
        freq = bt_ctf_clock_class_get_frequency(clock);
        if (freq == -1ULL) {
-               _PERROR("%s", "No clock frequency");
+               _PERROR("%s", "cannot get clock class frequency");
                ret = -1;
                goto end;
        }
 
        ret = bt_ctf_clock_class_get_offset_cycles(clock, &offset_cycles);
        if (ret) {
-               _PERROR("%s", "Getting offset cycles");
+               _PERROR("%s", "cannot get offset in cycles");
                ret = -1;
                goto end;
        }
 
-       offset_cycles += cycles_from_ns(freq, clock_offset_ns);
-
+       offset_cycles += cycles_from_ns(freq, ctx->clock_class_offset_ns);
        ret = bt_ctf_clock_class_set_offset_cycles(clock, offset_cycles);
 
 end:
@@ -4427,8 +4481,7 @@ end:
 }
 
 static
-int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node,
-               uint64_t clock_offset_ns)
+int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
 {
        int ret = 0;
        int set = 0;
@@ -4457,26 +4510,26 @@ int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node,
 
        if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
                _PERROR("%s",
-                       "missing \"name\" attribute in clock declaration");
+                       "missing \"name\" attribute in clock class declaration");
                ret = -EPERM;
                goto error;
        }
 
        if (bt_ctf_trace_get_clock_class_count(ctx->trace) != 0) {
-               _PERROR("%s", "only CTF traces with a single clock declaration are supported as of this version");
+               _PERROR("%s", "only CTF traces with a single clock class declaration are supported as of this version");
                ret = -EINVAL;
                goto error;
        }
 
-       ret = apply_clock_offset(ctx, clock, clock_offset_ns);
+       ret = apply_clock_class_offset(ctx, clock);
        if (ret) {
-               _PERROR("%s", "cannot apply clock offset ");
+               _PERROR("%s", "cannot apply clock class offset ");
                goto error;
        }
 
        ret = bt_ctf_trace_add_clock_class(ctx->trace, clock);
        if (ret) {
-               _PERROR("%s", "cannot add clock to trace");
+               _PERROR("%s", "cannot add clock class to trace");
                goto error;
        }
 
@@ -4542,7 +4595,7 @@ end:
 }
 
 static
-int add_stream_classes_to_trace(struct ctx *ctx)
+int move_ctx_stream_classes_to_trace(struct ctx *ctx)
 {
        int ret;
        GHashTableIter iter;
@@ -4561,41 +4614,79 @@ int add_stream_classes_to_trace(struct ctx *ctx)
                }
        }
 
+       g_hash_table_remove_all(ctx->stream_classes);
+
 end:
        return ret;
 }
 
-int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
-       struct bt_ctf_trace **trace, uint64_t clock_offset_ns)
+BT_HIDDEN
+struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd,
+               uint64_t clock_class_offset_ns)
 {
-       int ret = 0;
+       int ret;
        struct ctx *ctx = NULL;
+       struct bt_ctf_trace *trace;
 
-       printf_verbose("CTF visitor: AST -> CTF IR...\n");
-
-       *trace = bt_ctf_trace_create();
-       if (!*trace) {
+       trace = bt_ctf_trace_create();
+       if (!trace) {
                _FPERROR(efd, "%s", "cannot create trace");
-               ret = -ENOMEM;
                goto error;
        }
 
        /* Set packet header to NULL to override the default one */
-       ret = bt_ctf_trace_set_packet_header_type(*trace, NULL);
+       ret = bt_ctf_trace_set_packet_header_type(trace, NULL);
        if (ret) {
-               _FPERROR(efd,
-                       "%s",
+               _FPERROR(efd, "%s",
                        "cannot set initial, empty packet header structure");
                goto error;
        }
 
-       ctx = ctx_create(*trace, efd);
+       /* Create visitor's context */
+       ctx = ctx_create(trace, efd, clock_class_offset_ns);
        if (!ctx) {
                _FPERROR(efd, "%s", "cannot create visitor context");
-               ret = -ENOMEM;
                goto error;
        }
 
+       trace = NULL;
+       goto end;
+
+error:
+       ctx_destroy(ctx);
+       ctx = NULL;
+
+end:
+       bt_put(trace);
+       return (void *) ctx;
+}
+
+BT_HIDDEN
+void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor)
+{
+       ctx_destroy((void *) visitor);
+}
+
+BT_HIDDEN
+struct bt_ctf_trace *ctf_visitor_generate_ir_get_trace(
+               struct ctf_visitor_generate_ir *visitor)
+{
+       struct ctx *ctx = (void *) visitor;
+
+       assert(ctx);
+       assert(ctx->trace);
+       return bt_get(ctx->trace);
+}
+
+BT_HIDDEN
+int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
+               struct ctf_node *node)
+{
+       int ret = 0;
+       struct ctx *ctx = (void *) visitor;
+
+       printf_verbose("CTF visitor: AST -> CTF IR...\n");
+
        switch (node->type) {
        case NODE_ROOT:
        {
@@ -4604,44 +4695,57 @@ int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
                int found_callsite = FALSE;
 
                /*
-                * Find trace declaration's byte order first (for early
-                * type aliases).
+                * The first thing we need is the native byte order of
+                * the trace block, because early type aliases can have
+                * a `byte_order` attribute set to `native`. If we don't
+                * have the native byte order yet, and we don't have any
+                * trace block yet, then fail with EINCOMPLETE.
                 */
-               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
-                       if (got_trace_decl) {
-                               _PERROR("%s", "duplicate trace declaration");
-                               goto error;
-                       }
+               if (ctx->trace_bo == BT_CTF_BYTE_ORDER_NATIVE) {
+                       bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+                               if (got_trace_decl) {
+                                       _PERROR("%s", "duplicate trace declaration");
+                                       ret = -1;
+                                       goto end;
+                               }
 
-                       ret = set_trace_byte_order(ctx, iter);
-                       if (ret) {
-                               _PERROR("cannot set trace's byte order (%d)",
-                                       ret);
-                               goto error;
+                               ret = set_trace_byte_order(ctx, iter);
+                               if (ret) {
+                                       _PERROR("cannot set trace's native byte order (%d)",
+                                               ret);
+                                       goto end;
+                               }
+
+                               got_trace_decl = TRUE;
                        }
 
-                       got_trace_decl = TRUE;
+                       if (!got_trace_decl) {
+                               ret = -EINCOMPLETE;
+                               goto end;
+                       }
                }
 
-               if (!got_trace_decl) {
-                       _PERROR("no trace declaration found (%d)", ret);
-                       ret = -EPERM;
-                       goto error;
-               }
+               assert(ctx->trace_bo == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
+                       ctx->trace_bo == BT_CTF_BYTE_ORDER_BIG_ENDIAN);
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
 
                /*
                 * Visit clocks first since any early integer can be mapped
                 * to one.
                 */
                bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
-                       ret = visit_clock_decl(ctx, iter, clock_offset_ns);
+                       ret = visit_clock_decl(ctx, iter);
                        if (ret) {
-                               _PERROR("error while visiting clock declaration (%d)",
+                               _PERROR("error while visiting clock class declaration (%d)",
                                        ret);
-                               goto error;
+                               goto end;
                        }
                }
 
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
                /*
                 * Visit root declarations next, as they can be used by any
                 * following entity.
@@ -4652,16 +4756,22 @@ int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
                        if (ret) {
                                _PERROR("error while visiting root declaration (%d)",
                                        ret);
-                               goto error;
+                               goto end;
                        }
                }
 
-               /* Callsite are not supported */
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
+               /* Callsite blocks are not supported */
                bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
                        found_callsite = TRUE;
                        break;
                }
 
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
                if (found_callsite) {
                        _PWARNING("%s", "\"callsite\" blocks are not supported as of this version");
                }
@@ -4672,59 +4782,62 @@ int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
                        if (ret) {
                                _PERROR("error while visiting environment block (%d)",
                                        ret);
-                               goto error;
+                               goto end;
                        }
                }
 
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
                /* Trace */
                bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
                        ret = visit_trace_decl(ctx, iter);
                        if (ret) {
                                _PERROR("%s", "error while visiting trace declaration");
-                               goto error;
+                               goto end;
                        }
                }
 
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
                /* Streams */
                bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
                        ret = visit_stream_decl(ctx, iter);
                        if (ret) {
                                _PERROR("%s", "error while visiting stream declaration");
-                               goto error;
+                               goto end;
                        }
                }
 
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
                /* Events */
                bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
                        ret = visit_event_decl(ctx, iter);
                        if (ret) {
                                _PERROR("%s", "error while visiting event declaration");
-                               goto error;
+                               goto end;
                        }
                }
+
+               assert(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
                break;
        }
-       case NODE_UNKNOWN:
        default:
-               _PERROR("unknown node type: %d", (int) node->type);
+               _PERROR("cannot decode node type: %d", (int) node->type);
                ret = -EINVAL;
-               goto error;
+               goto end;
        }
 
-       /* Add stream classes to trace now */
-       ret = add_stream_classes_to_trace(ctx);
+       /* Move decoded stream classes to trace, if any */
+       ret = move_ctx_stream_classes_to_trace(ctx);
        if (ret) {
-               _PERROR("%s", "cannot add stream classes to trace");
+               _PERROR("%s", "cannot move stream classes to trace");
        }
 
-       ctx_destroy(ctx);
-       printf_verbose("done!\n");
-
-       return ret;
-
-error:
-       ctx_destroy(ctx);
-       BT_PUT(*trace);
-
+end:
        return ret;
 }
index 2c9752afe86bb7761d3ecfebdaac46cac1638197..b19d5635495bde492599967ca63de02c75c1a0be 100644 (file)
@@ -5,5 +5,4 @@ noinst_LTLIBRARIES = libctf-notif-iter.la
 
 libctf_notif_iter_la_SOURCES = \
        notif-iter.c \
-       notif-iter.h \
-       print.h
+       notif-iter.h
index 5b27899c90da191712c6cfb1c493fa1e85849a71..e2e9efd2673f9d21271a37cc4f5bdf76a8ed18fc 100644 (file)
@@ -47,7 +47,7 @@
 
 #define PRINT_ERR_STREAM       notit->err_stream
 #define PRINT_PREFIX           "ctf-notif-iter"
-#include "print.h"
+#include "../print.h"
 
 #include "notif-iter.h"
 #include "../btr/btr.h"
diff --git a/plugins/ctf/common/notif-iter/print.h b/plugins/ctf/common/notif-iter/print.h
deleted file mode 100644 (file)
index bb5c62a..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef CTF_NOTIF_ITER_PRINT_H
-#define CTF_NOTIF_ITER_PRINT_H
-
-/*
- * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <babeltrace/babeltrace-internal.h>
-
-#define PERR(fmt, ...)                                                 \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Error: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PWARN(fmt, ...)                                                        \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Warning: " PRINT_PREFIX ": " fmt,      \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PDBG(fmt, ...)                                                 \
-       do {                                                            \
-               if (babeltrace_debug) {                                 \
-                       fprintf(stderr,                                 \
-                               "Debug: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#endif /* CTF_NOTIF_ITER_PRINT_H */
diff --git a/plugins/ctf/common/print.h b/plugins/ctf/common/print.h
new file mode 100644 (file)
index 0000000..22381dc
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef CTF_BTR_PRINT_H
+#define CTF_BTR_PRINT_H
+
+/*
+ * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <babeltrace/babeltrace-internal.h>
+
+#define PERR(fmt, ...)                                                 \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "Error: " PRINT_PREFIX ": " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PWARN(fmt, ...)                                                        \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "Warning: " PRINT_PREFIX ": " fmt,      \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PDBG(fmt, ...)                                                 \
+       do {                                                            \
+               if (babeltrace_debug) {                                 \
+                       fprintf(stderr,                                 \
+                               "Debug: " PRINT_PREFIX ": " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#endif /* CTF_BTR_PRINT_H */
index ece7ff97cbe1e0a9fdfa19ee18c286134d7beda4..6ea15530a31fd6d3bfcc96917e37f1c72dcb6e8c 100644 (file)
@@ -43,6 +43,7 @@
 #include "metadata.h"
 #include "data-stream.h"
 #include "file.h"
+#include "../common/metadata/decoder.h"
 
 #define PRINT_ERR_STREAM       ctf_fs->error_fp
 #define PRINT_PREFIX           "ctf-fs"
@@ -548,11 +549,12 @@ struct bt_value *ctf_fs_query(struct bt_component_class *comp_class,
                        goto error;
                }
 
-               is_packetized = ctf_metadata_is_packetized(metadata_fp, &bo);
+               is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp,
+                       &bo);
 
                if (is_packetized) {
-                       ret = ctf_metadata_packetized_file_to_buf(NULL,
-                               metadata_fp, (uint8_t **) &metadata_text, bo);
+                       ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
+                               metadata_fp, &metadata_text, bo);
                        if (ret) {
                                fprintf(stderr,
                                        "Cannot decode packetized metadata file\n");
index 5c64113c3b5d7eef3f3b9e2b478ae8151ecbd427..a728abbfba6d1b50eaa13e8724798644ec7f78d6 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdbool.h>
+#include <assert.h>
 #include <glib.h>
 #include <babeltrace/compat/uuid.h>
 #include <babeltrace/compat/memstream.h>
 #include "fs.h"
 #include "file.h"
 #include "metadata.h"
-#include "../common/metadata/ast.h"
-#include "../common/metadata/scanner.h"
-
-#define TSDL_MAGIC     0x75d11d57
+#include "../common/metadata/decoder.h"
 
 #define NSEC_PER_SEC 1000000000LL
 
-struct packet_header {
-       uint32_t magic;
-       uint8_t  uuid[16];
-       uint32_t checksum;
-       uint32_t content_size;
-       uint32_t packet_size;
-       uint8_t  compression_scheme;
-       uint8_t  encryption_scheme;
-       uint8_t  checksum_scheme;
-       uint8_t  major;
-       uint8_t  minor;
-} __attribute__((__packed__));
-
 BT_HIDDEN
 FILE *ctf_fs_metadata_open_file(const char *trace_path)
 {
@@ -115,318 +100,40 @@ end:
        return file;
 }
 
-BT_HIDDEN
-bool ctf_metadata_is_packetized(FILE *fp, int *byte_order)
-{
-       uint32_t magic;
-       size_t len;
-       int ret = 0;
-
-       len = fread(&magic, sizeof(magic), 1, fp);
-       if (len != 1) {
-               goto end;
-       }
-
-       if (byte_order) {
-               if (magic == TSDL_MAGIC) {
-                       ret = 1;
-                       *byte_order = BYTE_ORDER;
-               } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
-                       ret = 1;
-                       *byte_order = BYTE_ORDER == BIG_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN;
-               }
-       }
-
-end:
-       rewind(fp);
-
-       return ret;
-}
-
-static
-bool is_version_valid(unsigned int major, unsigned int minor)
-{
-       return major == 1 && minor == 8;
-}
-
-static
-int decode_packet(struct ctf_fs_component *ctf_fs, FILE *in_fp, FILE *out_fp,
-               int byte_order)
-{
-       struct packet_header header;
-       size_t readlen, writelen, toread;
-       uint8_t buf[512 + 1];   /* + 1 for debug-mode \0 */
-       int ret = 0;
-
-       readlen = fread(&header, sizeof(header), 1, in_fp);
-       if (feof(in_fp) != 0) {
-               goto end;
-       }
-       if (readlen < 1) {
-               goto error;
-       }
-
-       if (byte_order != BYTE_ORDER) {
-               header.magic = GUINT32_SWAP_LE_BE(header.magic);
-               header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
-               header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
-               header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
-       }
-
-       if (header.compression_scheme) {
-               PERR("Metadata packet compression not supported yet\n");
-               goto error;
-       }
-
-       if (header.encryption_scheme) {
-               PERR("Metadata packet encryption not supported yet\n");
-               goto error;
-       }
-
-       if (header.checksum || header.checksum_scheme) {
-               PERR("Metadata packet checksum verification not supported yet\n");
-               goto error;
-       }
-
-       if (!is_version_valid(header.major, header.minor)) {
-               PERR("Invalid metadata version: %u.%u\n", header.major,
-                       header.minor);
-               goto error;
-       }
-
-       /* Set expected trace UUID if not set; otherwise validate it */
-       if (ctf_fs) {
-               if (!ctf_fs->metadata->is_uuid_set) {
-                       memcpy(ctf_fs->metadata->uuid, header.uuid, sizeof(header.uuid));
-                       ctf_fs->metadata->is_uuid_set = true;
-               } else if (bt_uuid_compare(header.uuid, ctf_fs->metadata->uuid)) {
-                       PERR("Metadata UUID mismatch between packets of the same file\n");
-                       goto error;
-               }
-       }
-
-       if ((header.content_size / CHAR_BIT) < sizeof(header)) {
-               PERR("Bad metadata packet content size: %u\n",
-                       header.content_size);
-               goto error;
-       }
-
-       toread = header.content_size / CHAR_BIT - sizeof(header);
-
-       for (;;) {
-               readlen = fread(buf, sizeof(uint8_t),
-                       MIN(sizeof(buf) - 1, toread), in_fp);
-               if (ferror(in_fp)) {
-                       PERR("Cannot read metadata packet buffer (at position %ld)\n",
-                               ftell(in_fp));
-                       goto error;
-               }
-
-               writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
-               if (writelen < readlen || ferror(out_fp)) {
-                       PERR("Cannot write decoded metadata text to buffer\n");
-                       goto error;
-               }
-
-               toread -= readlen;
-               if (toread == 0) {
-                       int fseek_ret;
-
-                       /* Read leftover padding */
-                       toread = (header.packet_size - header.content_size) /
-                               CHAR_BIT;
-                       fseek_ret = fseek(in_fp, toread, SEEK_CUR);
-                       if (fseek_ret < 0) {
-                               PWARN("Missing padding at the end of the metadata file\n");
-                       }
-
-                       break;
-               }
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_metadata_packetized_file_to_buf(struct ctf_fs_component *ctf_fs,
-               FILE *fp, uint8_t **buf, int byte_order)
-{
-       FILE *out_fp;
-       size_t size;
-       int ret = 0;
-       int tret;
-       size_t packet_index = 0;
-
-       out_fp = babeltrace_open_memstream((char **) buf, &size);
-       if (out_fp == NULL) {
-               PERR("Cannot open memory stream: %s\n", strerror(errno));
-               goto error;
-       }
-
-       for (;;) {
-               if (feof(fp) != 0) {
-                       break;
-               }
-
-               tret = decode_packet(ctf_fs, fp, out_fp, byte_order);
-               if (tret) {
-                       PERR("Cannot decode packet #%zu\n", packet_index);
-                       goto error;
-               }
-
-               packet_index++;
-       }
-
-       /* Make sure the whole string ends with a null character */
-       tret = fputc('\0', out_fp);
-       if (tret == EOF) {
-               PERR("Cannot append '\\0' to the decoded metadata buffer\n");
-               goto error;
-       }
-
-       /* Close stream, which also flushes the buffer */
-       ret = babeltrace_close_memstream((char **) buf, &size, out_fp);
-       if (ret < 0) {
-               PERR("Cannot close memory stream: %s\n", strerror(errno));
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-       if (out_fp) {
-               babeltrace_close_memstream((char **) buf, &size, out_fp);
-       }
-
-       if (*buf) {
-               free(*buf);
-       }
-
-end:
-       return ret;
-}
-
 int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs)
 {
        int ret = 0;
-       struct ctf_fs_file *file = get_file(ctf_fs, ctf_fs->trace_path->str);
-       struct ctf_scanner *scanner = NULL;
-       uint8_t *buf = NULL;
-       char *cbuf;
+       struct ctf_fs_file *file = NULL;
+       struct ctf_metadata_decoder *metadata_decoder = NULL;
 
+       file = get_file(ctf_fs, ctf_fs->trace_path->str);
        if (!file) {
                PERR("Cannot create metadata file object\n");
-               goto error;
-       }
-
-       if (babeltrace_debug) {
-               // yydebug = 1;
-       }
-
-       if (ctf_metadata_is_packetized(file->fp, &ctf_fs->metadata->bo)) {
-               PDBG("Metadata file \"%s\" is packetized\n", file->path->str);
-               ret = ctf_metadata_packetized_file_to_buf(ctf_fs, file->fp,
-                       &buf, ctf_fs->metadata->bo);
-               if (ret) {
-                       // log: details
-                       goto error;
-               }
-
-               cbuf = (char *) buf;
-               ctf_fs->metadata->text = (char *) cbuf;
-
-               /* Convert the real file pointer to a memory file pointer */
-               ret = fclose(file->fp);
-               file->fp = NULL;
-               if (ret) {
-                       PERR("Cannot close file \"%s\": %s\n", file->path->str,
-                               strerror(errno));
-                       goto error;
-               }
-
-               file->fp = babeltrace_fmemopen(cbuf, strlen(cbuf), "rb");
-               if (!file->fp) {
-                       PERR("Cannot memory-open metadata buffer: %s\n",
-                               strerror(errno));
-                       goto error;
-               }
-       } else {
-               unsigned int major, minor;
-               ssize_t nr_items;
-
-               PDBG("Metadata file \"%s\" is plain text\n", file->path->str);
-
-               /* Check text-only metadata header and version */
-               nr_items = fscanf(file->fp, "/* CTF %10u.%10u", &major, &minor);
-               if (nr_items < 2) {
-                       PWARN("Ill-shapen or missing \"/* CTF major.minor\" header in plain text metadata file\n");
-               }
-               PDBG("Metadata version: %u.%u\n", major, minor);
-
-               if (!is_version_valid(major, minor)) {
-                       PERR("Invalid metadata version: %u.%u\n", major, minor);
-                       goto error;
-               }
-
-               rewind(file->fp);
-       }
-
-       /* Allocate a scanner and append the metadata text content */
-       scanner = ctf_scanner_alloc();
-       if (!scanner) {
-               PERR("Cannot allocate a metadata lexical scanner\n");
-               goto error;
-       }
-
-       ret = ctf_scanner_append_ast(scanner, file->fp);
-       if (ret) {
-               PERR("Cannot create the metadata AST\n");
-               goto error;
-       }
-
-       ret = ctf_visitor_semantic_check(stderr, 0, &scanner->ast->root);
-       if (ret) {
-               PERR("Metadata semantic validation failed\n");
-               goto error;
+               goto end;
        }
 
-       ret = ctf_visitor_generate_ir(ctf_fs->error_fp, &scanner->ast->root,
-               &ctf_fs->metadata->trace,
+       metadata_decoder = ctf_metadata_decoder_create(ctf_fs->error_fp,
                ctf_fs->options.clock_offset * NSEC_PER_SEC +
                ctf_fs->options.clock_offset_ns);
-       if (ret) {
-               PERR("Cannot create trace object from metadata AST\n");
-               goto error;
+       if (!metadata_decoder) {
+               PERR("Cannot create metadata decoder object\n");
+               goto end;
        }
 
-       goto end;
-
-error:
-       if (ctf_fs->metadata->text) {
-               free(ctf_fs->metadata->text);
-               ctf_fs->metadata->text = NULL;
+       ret = ctf_metadata_decoder_decode(metadata_decoder, file->fp);
+       if (ret) {
+               PERR("Cannot decode metadata file\n");
+               goto end;
        }
 
+       ctf_fs->metadata->trace = ctf_metadata_decoder_get_trace(
+               metadata_decoder);
+       assert(ctf_fs->metadata->trace);
        ret = -1;
 
 end:
-       if (file) {
-               ctf_fs_file_destroy(file);
-       }
-
-       if (scanner) {
-               ctf_scanner_free(scanner);
-       }
-
+       ctf_fs_file_destroy(file);
+       ctf_metadata_decoder_destroy(metadata_decoder);
        return ret;
 }
 
This page took 0.053743 seconds and 4 git commands to generate.