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 \
noinst_LTLIBRARIES = libctf-btr.la
libctf_btr_la_SOURCES = \
btr.c \
- btr.h \
- print.h
+ btr.h
#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)
+++ /dev/null
-#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 */
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
#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
struct ctf_node;
struct ctf_parser;
+struct ctf_visitor_generate_ir;
+
+#define EINCOMPLETE 1000
#define FOREACH_CTF_NODES(F) \
F(NODE_UNKNOWN) \
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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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 */
/* 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__); \
};
/*
- * 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 */
/* 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];
GHashTable *stream_classes;
};
+/*
+ * Visitor (public).
+ */
+struct ctf_visitor_generate_ir { };
+
static
const char *loglevel_str [] = {
[ LOGLEVEL_EMERG ] = "TRACE_EMERG",
* @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;
}
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;
}
scope = parent_scope;
}
+ bt_put(ctx->trace);
g_hash_table_destroy(ctx->stream_classes);
g_free(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);
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;
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;
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);
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;
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;
}
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");
}
}
-
-
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) !=
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;
}
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) {
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;
}
goto error;
}
+ ctx->trace_bo = bo;
ret = bt_ctf_trace_set_native_byte_order(
ctx->trace, bo);
if (ret) {
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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);
}
}
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;
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:
}
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;
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;
}
}
static
-int add_stream_classes_to_trace(struct ctx *ctx)
+int move_ctx_stream_classes_to_trace(struct ctx *ctx)
{
int ret;
GHashTableIter iter;
}
}
+ 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:
{
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.
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");
}
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;
}
libctf_notif_iter_la_SOURCES = \
notif-iter.c \
- notif-iter.h \
- print.h
+ notif-iter.h
#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"
+++ /dev/null
-#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 */
--- /dev/null
+#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 */
#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"
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");
#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)
{
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;
}