From: Philippe Proulx Date: Mon, 11 Dec 2023 17:54:03 +0000 (-0500) Subject: src/plugins/ctf/common: restructure subtree X-Git-Url: https://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=5656cea5531432357cf7ca2a0be14adae5a1e3d3 src/plugins/ctf/common: restructure subtree This patch restructures the `src/plugins/ctf/common` subtree as such: `src`: Everything common to source component classes. `src/metadata/tsdl`: TSDL-specific code. As of this patch, everything which was part of `src/plugins/ctf/common/metadata` is moved here, but some code will be shared with CTF 2 sources eventually and move back to `src/plugins/ctf/common/src/metadata`. `print.hpp` isn't needed anymore. This new structure will make it easier to add common `ctf` plugin code for both source and sink component classes, as well as to add code specific to CTF 2 and common to both CTF 1 and CTF 2. Signed-off-by: Philippe Proulx Change-Id: I4246d6ba37ff26efa5d4b7b4be2ec8600d3207e4 Reviewed-on: https://review.lttng.org/c/babeltrace/+/7839 Reviewed-on: https://review.lttng.org/c/babeltrace/+/12190 CI-Build: Simon Marchi Tested-by: jenkins --- diff --git a/.gitignore b/.gitignore index c63fcaf0..2267bc7b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,10 +28,10 @@ *.bkp *.trs .dirstamp -/src/plugins/ctf/common/metadata/lexer.cpp -/src/plugins/ctf/common/metadata/parser.cpp -/src/plugins/ctf/common/metadata/parser.hpp -/src/plugins/ctf/common/metadata/parser.output +/src/plugins/ctf/common/src/metadata/tsdl/lexer.cpp +/src/plugins/ctf/common/src/metadata/tsdl/parser.cpp +/src/plugins/ctf/common/src/metadata/tsdl/parser.hpp +/src/plugins/ctf/common/src/metadata/tsdl/parser.output /src/bindings/python/bt2/bt2.egg-info /src/bindings/python/bt2/dist /src/cli/babeltrace2 diff --git a/src/Makefile.am b/src/Makefile.am index 2d18268c..b8eebe9f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -243,14 +243,14 @@ AM_YFLAGS = \ -t -d -v -Wno-yacc plugins_ctf_common_metadata_libctf_parser_la_SOURCES = \ - plugins/ctf/common/metadata/lexer.lpp \ - plugins/ctf/common/metadata/parser.ypp \ - plugins/ctf/common/metadata/objstack.cpp + plugins/ctf/common/src/metadata/tsdl/lexer.lpp \ + plugins/ctf/common/src/metadata/tsdl/parser.ypp \ + plugins/ctf/common/src/metadata/tsdl/objstack.cpp # scanner-symbols.h is included to prefix generated yy_* symbols with bt_. plugins_ctf_common_metadata_libctf_parser_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ - -include $(srcdir)/plugins/ctf/common/metadata/scanner-symbols.hpp + -include $(srcdir)/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp # This library contains (mostly) generated code, silence some warnings that it # produces. @@ -262,52 +262,52 @@ plugins_ctf_common_metadata_libctf_parser_la_CXXFLAGS = \ -Wno-unused-parameter plugins_ctf_common_metadata_libctf_ast_la_SOURCES = \ - plugins/ctf/common/metadata/visitor-generate-ir.cpp \ - plugins/ctf/common/metadata/visitor-semantic-validator.cpp \ - plugins/ctf/common/metadata/visitor-parent-links.cpp \ - plugins/ctf/common/metadata/ast.hpp \ - plugins/ctf/common/metadata/objstack.hpp \ - plugins/ctf/common/metadata/parser.hpp \ - plugins/ctf/common/metadata/parser-wrap.hpp \ - plugins/ctf/common/metadata/scanner.hpp \ - plugins/ctf/common/metadata/scanner-symbols.hpp \ - plugins/ctf/common/metadata/decoder.cpp \ - plugins/ctf/common/metadata/decoder.hpp \ - plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp \ - plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp \ - plugins/ctf/common/metadata/logging.cpp \ - plugins/ctf/common/metadata/logging.hpp \ - plugins/ctf/common/metadata/ctf-meta.hpp \ - plugins/ctf/common/metadata/ctf-meta-visitors.hpp \ - plugins/ctf/common/metadata/ctf-meta-validate.cpp \ - plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp \ - plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp \ - plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp \ - plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp \ - plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp \ - plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp \ - plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp \ - plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp \ - plugins/ctf/common/metadata/ctf-meta-translate.cpp \ - plugins/ctf/common/metadata/ctf-meta-resolve.cpp \ - plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp \ - plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp + plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp \ + plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp \ + plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp \ + plugins/ctf/common/src/metadata/tsdl/ast.hpp \ + plugins/ctf/common/src/metadata/tsdl/objstack.hpp \ + plugins/ctf/common/src/metadata/tsdl/parser.hpp \ + plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp \ + plugins/ctf/common/src/metadata/tsdl/scanner.hpp \ + plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp \ + plugins/ctf/common/src/metadata/tsdl/decoder.cpp \ + plugins/ctf/common/src/metadata/tsdl/decoder.hpp \ + plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp \ + plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp \ + plugins/ctf/common/src/metadata/tsdl/logging.cpp \ + plugins/ctf/common/src/metadata/tsdl/logging.hpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp \ + plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp if BABELTRACE_BUILD_WITH_MINGW plugins_ctf_common_metadata_libctf_ast_la_LIBADD = -lintl -liconv -lole32 endif BUILT_SOURCES += \ - plugins/ctf/common/metadata/parser.hpp + plugins/ctf/common/src/metadata/tsdl/parser.hpp ALL_LOCAL = if HAVE_BISON # We have bison: we can clean the generated parser files CLEANFILES += \ - plugins/ctf/common/metadata/parser.cpp \ - plugins/ctf/common/metadata/parser.hpp \ - plugins/ctf/common/metadata/parser.output + plugins/ctf/common/src/metadata/tsdl/parser.cpp \ + plugins/ctf/common/src/metadata/tsdl/parser.hpp \ + plugins/ctf/common/src/metadata/tsdl/parser.output else # HAVE_BISON # Create target used to stop the build if we want to build the parser, # but we don't have the necessary tool to do so @@ -648,11 +648,10 @@ endif # ctf plugin plugins_ctf_babeltrace_plugin_ctf_la_SOURCES = \ - plugins/ctf/common/bfcr/bfcr.cpp \ - plugins/ctf/common/bfcr/bfcr.hpp \ - plugins/ctf/common/msg-iter/msg-iter.cpp \ - plugins/ctf/common/msg-iter/msg-iter.hpp \ - plugins/ctf/common/print.hpp \ + plugins/ctf/common/src/bfcr/bfcr.cpp \ + plugins/ctf/common/src/bfcr/bfcr.hpp \ + plugins/ctf/common/src/msg-iter/msg-iter.cpp \ + plugins/ctf/common/src/msg-iter/msg-iter.hpp \ plugins/ctf/fs-sink/fs-sink.cpp \ plugins/ctf/fs-sink/fs-sink-ctf-meta.hpp \ plugins/ctf/fs-sink/fs-sink.hpp \ diff --git a/src/plugins/ctf/common/bfcr/bfcr.cpp b/src/plugins/ctf/common/bfcr/bfcr.cpp deleted file mode 100644 index f59f65d0..00000000 --- a/src/plugins/ctf/common/bfcr/bfcr.cpp +++ /dev/null @@ -1,1264 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015-2016 Philippe Proulx - * - * Babeltrace - CTF binary field class reader (BFCR) - */ - -#include -#include -#include -#include -#include - -#include - -#define BT_COMP_LOG_SELF_COMP (bfcr->self_comp) -#define BT_LOG_OUTPUT_LEVEL (bfcr->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/BFCR" -#include "logging/comp-logging.h" - -#include "common/align.h" -#include "common/assert.h" -#include "common/common.h" -#include "compat/bitfield.h" - -#include "../metadata/ctf-meta.hpp" -#include "bfcr.hpp" - -#define DIV8(_x) ((_x) >> 3) -#define BYTES_TO_BITS(_x) ((_x) *8) -#define BITS_TO_BYTES_FLOOR(_x) DIV8(_x) -#define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7) -#define IN_BYTE_OFFSET(_at) ((_at) &7) - -/* A visit stack entry */ -struct stack_entry -{ - /* - * Current class of base field, one of: - * - * * Structure - * * Array - * * Sequence - * * Variant - */ - struct ctf_field_class *base_class; - - /* Length of base field (always 1 for a variant class) */ - int64_t base_len; - - /* Index of next field to read */ - int64_t index; -}; - -/* Visit stack */ -struct stack -{ - struct bt_bfcr *bfcr; - - /* Entries (struct stack_entry) */ - GArray *entries; - - /* Number of active entries */ - size_t size; -}; - -/* Reading states */ -enum bfcr_state -{ - BFCR_STATE_NEXT_FIELD, - BFCR_STATE_ALIGN_BASIC, - BFCR_STATE_ALIGN_COMPOUND, - BFCR_STATE_READ_BASIC_BEGIN, - BFCR_STATE_READ_BASIC_CONTINUE, - BFCR_STATE_DONE, -}; - -/* Binary class reader */ -struct bt_bfcr -{ - bt_logging_level log_level; - - /* Weak */ - bt_self_component *self_comp; - - /* BFCR stack */ - struct stack *stack; - - /* Current basic field class */ - struct ctf_field_class *cur_basic_field_class; - - /* Current state */ - enum bfcr_state state; - - /* - * Last basic field class's byte order. - * - * This is used to detect errors since two contiguous basic - * classes for which the common boundary is not the boundary of - * a byte cannot have different byte orders. - * - * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last - * basic field class was a string class. - */ - enum ctf_byte_order last_bo; - - /* Current byte order (copied to last_bo after a successful read) */ - enum ctf_byte_order cur_bo; - - /* Stitch buffer infos */ - struct - { - /* Stitch buffer */ - uint8_t buf[16]; - - /* Offset, within stitch buffer, of first bit */ - size_t offset; - - /* Length (bits) of data in stitch buffer from offset */ - size_t at; - } stitch; - - /* User buffer infos */ - struct - { - /* Address */ - const uint8_t *addr; - - /* Offset of data from address (bits) */ - size_t offset; - - /* Current position from offset (bits) */ - size_t at; - - /* Offset of offset within whole packet (bits) */ - size_t packet_offset; - - /* Data size in buffer (bits) */ - size_t sz; - - /* Buffer size (bytes) */ - size_t buf_sz; - } buf; - - /* User stuff */ - struct - { - /* Callback functions */ - struct bt_bfcr_cbs cbs; - - /* Private data */ - void *data; - } user; -}; - -static inline const char *bfcr_state_string(enum bfcr_state state) -{ - switch (state) { - case BFCR_STATE_NEXT_FIELD: - return "NEXT_FIELD"; - case BFCR_STATE_ALIGN_BASIC: - return "ALIGN_BASIC"; - case BFCR_STATE_ALIGN_COMPOUND: - return "ALIGN_COMPOUND"; - case BFCR_STATE_READ_BASIC_BEGIN: - return "READ_BASIC_BEGIN"; - case BFCR_STATE_READ_BASIC_CONTINUE: - return "READ_BASIC_CONTINUE"; - case BFCR_STATE_DONE: - return "DONE"; - } - - bt_common_abort(); -} - -static struct stack *stack_new(struct bt_bfcr *bfcr) -{ - struct stack *stack = NULL; - - stack = g_new0(struct stack, 1); - if (!stack) { - BT_COMP_LOGE_STR("Failed to allocate one stack."); - goto error; - } - - stack->bfcr = bfcr; - stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry)); - if (!stack->entries) { - BT_COMP_LOGE_STR("Failed to allocate a GArray."); - goto error; - } - - BT_COMP_LOGD("Created stack: addr=%p", stack); - return stack; - -error: - g_free(stack); - return NULL; -} - -static void stack_destroy(struct stack *stack) -{ - struct bt_bfcr *bfcr; - - if (!stack) { - return; - } - - bfcr = stack->bfcr; - BT_COMP_LOGD("Destroying stack: addr=%p", stack); - - if (stack->entries) { - g_array_free(stack->entries, TRUE); - } - - g_free(stack); -} - -static int stack_push(struct stack *stack, struct ctf_field_class *base_class, size_t base_len) -{ - struct stack_entry *entry; - struct bt_bfcr *bfcr; - - BT_ASSERT_DBG(stack); - BT_ASSERT_DBG(base_class); - bfcr = stack->bfcr; - BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, " - "fc-addr=%p, fc-type=%d, base-length=%zu, " - "stack-size-before=%zu, stack-size-after=%zu", - stack, base_class, base_class->type, base_len, stack->size, stack->size + 1); - - if (stack->entries->len == stack->size) { - g_array_set_size(stack->entries, stack->size + 1); - } - - entry = &bt_g_array_index(stack->entries, struct stack_entry, stack->size); - entry->base_class = base_class; - entry->base_len = base_len; - entry->index = 0; - stack->size++; - return 0; -} - -static inline int64_t get_compound_field_class_length(struct bt_bfcr *bfcr, - struct ctf_field_class *fc) -{ - int64_t length; - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - length = (int64_t) struct_fc->members->len; - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - /* Variant field classes always "contain" a single class */ - length = 1; - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - { - struct ctf_field_class_array *array_fc = ctf_field_class_as_array(fc); - - length = (int64_t) array_fc->length; - break; - } - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - length = bfcr->user.cbs.query.get_sequence_length(fc, bfcr->user.data); - break; - default: - bt_common_abort(); - } - - return length; -} - -static int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class) -{ - int ret; - int64_t length = get_compound_field_class_length(bfcr, base_class); - - if (length < 0) { - BT_COMP_LOGW("Cannot get compound field class's field count: " - "bfcr-addr=%p, fc-addr=%p, fc-type=%d", - bfcr, base_class, base_class->type); - ret = BT_BFCR_STATUS_ERROR; - goto end; - } - - ret = stack_push(bfcr->stack, base_class, (size_t) length); - -end: - return ret; -} - -static inline unsigned int stack_size(struct stack *stack) -{ - BT_ASSERT_DBG(stack); - return stack->size; -} - -static void stack_pop(struct stack *stack) -{ - struct bt_bfcr *bfcr; - - BT_ASSERT_DBG(stack); - BT_ASSERT_DBG(stack_size(stack)); - bfcr = stack->bfcr; - BT_COMP_LOGT("Popping from stack: " - "stack-addr=%p, stack-size-before=%u, stack-size-after=%u", - stack, stack->entries->len, stack->entries->len - 1); - stack->size--; -} - -static inline bool stack_empty(struct stack *stack) -{ - return stack_size(stack) == 0; -} - -static void stack_clear(struct stack *stack) -{ - BT_ASSERT_DBG(stack); - stack->size = 0; -} - -static inline struct stack_entry *stack_top(struct stack *stack) -{ - BT_ASSERT_DBG(stack); - BT_ASSERT_DBG(stack_size(stack)); - return &bt_g_array_index(stack->entries, struct stack_entry, stack->size - 1); -} - -static inline size_t available_bits(struct bt_bfcr *bfcr) -{ - return bfcr->buf.sz - bfcr->buf.at; -} - -static inline void consume_bits(struct bt_bfcr *bfcr, size_t incr) -{ - BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu", bfcr, - bfcr->buf.at, bfcr->buf.at + incr); - bfcr->buf.at += incr; -} - -static inline bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz) -{ - return available_bits(bfcr) >= sz; -} - -static inline bool at_least_one_bit_left(struct bt_bfcr *bfcr) -{ - return has_enough_bits(bfcr, 1); -} - -static inline size_t packet_at(struct bt_bfcr *bfcr) -{ - return bfcr->buf.packet_offset + bfcr->buf.at; -} - -static inline size_t buf_at_from_addr(struct bt_bfcr *bfcr) -{ - /* - * Considering this: - * - * ====== offset ===== (17) - * - * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - * ^ - * addr (0) ==== at ==== (12) - * - * We want this: - * - * =============================== (29) - */ - return bfcr->buf.offset + bfcr->buf.at; -} - -static void stitch_reset(struct bt_bfcr *bfcr) -{ - bfcr->stitch.offset = 0; - bfcr->stitch.at = 0; -} - -static inline size_t stitch_at_from_addr(struct bt_bfcr *bfcr) -{ - return bfcr->stitch.offset + bfcr->stitch.at; -} - -static void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz) -{ - size_t stitch_byte_at; - size_t buf_byte_at; - size_t nb_bytes; - - if (sz == 0) { - return; - } - - stitch_byte_at = BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr)); - buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr)); - nb_bytes = BITS_TO_BYTES_CEIL(sz); - BT_ASSERT(nb_bytes > 0); - BT_ASSERT(bfcr->buf.addr); - memcpy(&bfcr->stitch.buf[stitch_byte_at], &bfcr->buf.addr[buf_byte_at], nb_bytes); - bfcr->stitch.at += sz; - consume_bits(bfcr, sz); -} - -static void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr) -{ - stitch_append_from_buf(bfcr, available_bits(bfcr)); -} - -static void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr) -{ - stitch_reset(bfcr); - bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr)); - stitch_append_from_remaining_buf(bfcr); -} - -static inline void read_unsigned_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at, - unsigned int field_size, enum ctf_byte_order bo, - uint64_t *v) -{ - switch (bo) { - case CTF_BYTE_ORDER_BIG: - bt_bitfield_read_be(buf, uint8_t, at, field_size, v); - break; - case CTF_BYTE_ORDER_LITTLE: - bt_bitfield_read_le(buf, uint8_t, at, field_size, v); - break; - default: - bt_common_abort(); - } - - BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, " - "bo=%d, val=%" PRIu64, - at, field_size, bo, *v); -} - -static inline void read_signed_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at, - unsigned int field_size, enum ctf_byte_order bo, int64_t *v) -{ - switch (bo) { - case CTF_BYTE_ORDER_BIG: - bt_bitfield_read_be(buf, uint8_t, at, field_size, v); - break; - case CTF_BYTE_ORDER_LITTLE: - bt_bitfield_read_le(buf, uint8_t, at, field_size, v); - break; - default: - bt_common_abort(); - } - - BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, " - "bo=%d, val=%" PRId64, - at, field_size, bo, *v); -} - -typedef enum bt_bfcr_status (*read_basic_and_call_cb_t)(struct bt_bfcr *, const uint8_t *, size_t); - -static inline enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr, - enum ctf_byte_order next_bo) -{ - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - - /* Always valid when at a byte boundary */ - if (packet_at(bfcr) % 8 == 0) { - goto end; - } - - /* Always valid if last byte order is unknown */ - if (bfcr->last_bo == CTF_BYTE_ORDER_UNKNOWN) { - goto end; - } - - /* Always valid if next byte order is unknown */ - if (next_bo == CTF_BYTE_ORDER_UNKNOWN) { - goto end; - } - - /* Make sure last byte order is compatible with the next byte order */ - switch (bfcr->last_bo) { - case CTF_BYTE_ORDER_BIG: - if (next_bo != CTF_BYTE_ORDER_BIG) { - status = BT_BFCR_STATUS_ERROR; - } - break; - case CTF_BYTE_ORDER_LITTLE: - if (next_bo != CTF_BYTE_ORDER_LITTLE) { - status = BT_BFCR_STATUS_ERROR; - } - break; - default: - status = BT_BFCR_STATUS_ERROR; - } - -end: - if (status < 0) { - BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: " - "bfcr-addr=%p, last-bo=%d, next-bo=%d", - bfcr, bfcr->last_bo, next_bo); - } - - return status; -} - -static enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr, const uint8_t *buf, - size_t at) -{ - double dblval; - unsigned int field_size; - enum ctf_byte_order bo; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - ctf_field_class_float *fc = ctf_field_class_as_float(bfcr->cur_basic_field_class); - - BT_ASSERT_DBG(fc); - field_size = fc->base.size; - bo = fc->base.byte_order; - bfcr->cur_bo = bo; - - switch (field_size) { - case 32: - { - uint64_t v; - union - { - uint32_t u; - float f; - } f32; - - read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v); - f32.u = (uint32_t) v; - dblval = (double) f32.f; - break; - } - case 64: - { - union - { - uint64_t u; - double d; - } f64; - - read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &f64.u); - dblval = f64.d; - break; - } - default: - /* Only 32-bit and 64-bit fields are supported currently */ - bt_common_abort(); - } - - BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f", bfcr, at, dblval); - - if (bfcr->user.cbs.classes.floating_point) { - BT_COMP_LOGT("Calling user function (floating point number)."); - status = bfcr->user.cbs.classes.floating_point(dblval, bfcr->cur_basic_field_class, - bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, - bt_bfcr_status_string(status)); - } - } - - return status; -} - -static inline enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr, - const uint8_t *buf, size_t at) -{ - unsigned int field_size; - enum ctf_byte_order bo; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - ctf_field_class_int *fc = ctf_field_class_as_int(bfcr->cur_basic_field_class); - - field_size = fc->base.size; - bo = fc->base.byte_order; - - /* - * Update current byte order now because we could be reading - * the integer value of an enumeration class, and thus we know - * here the actual supporting integer class's byte order. - */ - bfcr->cur_bo = bo; - - if (fc->is_signed) { - int64_t v; - - read_signed_bitfield(bfcr, buf, at, field_size, bo, &v); - - if (bfcr->user.cbs.classes.signed_int) { - BT_COMP_LOGT("Calling user function (signed integer)."); - status = - bfcr->user.cbs.classes.signed_int(v, bfcr->cur_basic_field_class, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: " - "bfcr-addr=%p, status=%s", - bfcr, bt_bfcr_status_string(status)); - } - } - } else { - uint64_t v; - - read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v); - - if (bfcr->user.cbs.classes.unsigned_int) { - BT_COMP_LOGT("Calling user function (unsigned integer)."); - status = bfcr->user.cbs.classes.unsigned_int(v, bfcr->cur_basic_field_class, - bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: " - "bfcr-addr=%p, status=%s", - bfcr, bt_bfcr_status_string(status)); - } - } - } - - return status; -} - -static inline enum bt_bfcr_status -read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr, - read_basic_and_call_cb_t read_basic_and_call_cb) -{ - size_t available; - size_t needed_bits; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class); - - if (!at_least_one_bit_left(bfcr)) { - BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr); - status = BT_BFCR_STATUS_EOF; - goto end; - } - - available = available_bits(bfcr); - needed_bits = fc->size - bfcr->stitch.at; - BT_COMP_LOGT("Continuing basic field decoding: " - "bfcr-addr=%p, field-size=%u, needed-size=%zu, " - "available-size=%zu", - bfcr, fc->size, needed_bits, available); - if (needed_bits <= available) { - /* We have all the bits; append to stitch, then decode */ - stitch_append_from_buf(bfcr, needed_bits); - status = read_basic_and_call_cb(bfcr, bfcr->stitch.buf, bfcr->stitch.offset); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("Cannot read basic field: " - "bfcr-addr=%p, fc-addr=%p, status=%s", - bfcr, bfcr->cur_basic_field_class, bt_bfcr_status_string(status)); - goto end; - } - - if (stack_empty(bfcr->stack)) { - /* Root is a basic class */ - bfcr->state = BFCR_STATE_DONE; - } else { - /* Go to next field */ - stack_top(bfcr->stack)->index++; - bfcr->state = BFCR_STATE_NEXT_FIELD; - bfcr->last_bo = bfcr->cur_bo; - } - goto end; - } - - /* We are here; it means we don't have enough data to decode this */ - BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer."); - stitch_append_from_remaining_buf(bfcr); - status = BT_BFCR_STATUS_EOF; - -end: - return status; -} - -static inline enum bt_bfcr_status -read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr, - read_basic_and_call_cb_t read_basic_and_call_cb) -{ - size_t available; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class); - - if (!at_least_one_bit_left(bfcr)) { - BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr); - status = BT_BFCR_STATUS_EOF; - goto end; - } - - status = validate_contiguous_bo(bfcr, fc->byte_order); - if (status != BT_BFCR_STATUS_OK) { - /* validate_contiguous_bo() logs errors */ - goto end; - } - - available = available_bits(bfcr); - - if (fc->size <= available) { - /* We have all the bits; decode and set now */ - BT_ASSERT_DBG(bfcr->buf.addr); - status = read_basic_and_call_cb(bfcr, bfcr->buf.addr, buf_at_from_addr(bfcr)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("Cannot read basic field: " - "bfcr-addr=%p, fc-addr=%p, status=%s", - bfcr, bfcr->cur_basic_field_class, bt_bfcr_status_string(status)); - goto end; - } - - consume_bits(bfcr, fc->size); - - if (stack_empty(bfcr->stack)) { - /* Root is a basic class */ - bfcr->state = BFCR_STATE_DONE; - } else { - /* Go to next field */ - stack_top(bfcr->stack)->index++; - bfcr->state = BFCR_STATE_NEXT_FIELD; - bfcr->last_bo = bfcr->cur_bo; - } - - goto end; - } - - /* We are here; it means we don't have enough data to decode this */ - BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer."); - stitch_set_from_remaining_buf(bfcr); - bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE; - status = BT_BFCR_STATUS_EOF; - -end: - return status; -} - -static inline enum bt_bfcr_status read_basic_int_class_and_call_begin(struct bt_bfcr *bfcr) -{ - return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb); -} - -static inline enum bt_bfcr_status read_basic_int_class_and_call_continue(struct bt_bfcr *bfcr) -{ - return read_bit_array_class_and_call_continue(bfcr, read_basic_int_and_call_cb); -} - -static inline enum bt_bfcr_status read_basic_float_class_and_call_begin(struct bt_bfcr *bfcr) -{ - return read_bit_array_class_and_call_begin(bfcr, read_basic_float_and_call_cb); -} - -static inline enum bt_bfcr_status read_basic_float_class_and_call_continue(struct bt_bfcr *bfcr) -{ - return read_bit_array_class_and_call_continue(bfcr, read_basic_float_and_call_cb); -} - -static inline enum bt_bfcr_status read_basic_string_class_and_call(struct bt_bfcr *bfcr, bool begin) -{ - size_t buf_at_bytes; - const uint8_t *result; - size_t available_bytes; - const uint8_t *first_chr; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - - if (!at_least_one_bit_left(bfcr)) { - BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr); - status = BT_BFCR_STATUS_EOF; - goto end; - } - - BT_ASSERT_DBG(buf_at_from_addr(bfcr) % 8 == 0); - available_bytes = BITS_TO_BYTES_FLOOR(available_bits(bfcr)); - buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr)); - BT_ASSERT_DBG(bfcr->buf.addr); - first_chr = &bfcr->buf.addr[buf_at_bytes]; - result = (const uint8_t *) memchr(first_chr, '\0', available_bytes); - - if (begin && bfcr->user.cbs.classes.string_begin) { - BT_COMP_LOGT("Calling user function (string, beginning)."); - status = bfcr->user.cbs.classes.string_begin(bfcr->cur_basic_field_class, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, - bt_bfcr_status_string(status)); - goto end; - } - } - - if (!result) { - /* No null character yet */ - if (bfcr->user.cbs.classes.string) { - BT_COMP_LOGT("Calling user function (substring)."); - status = bfcr->user.cbs.classes.string((const char *) first_chr, available_bytes, - bfcr->cur_basic_field_class, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: " - "bfcr-addr=%p, status=%s", - bfcr, bt_bfcr_status_string(status)); - goto end; - } - } - - consume_bits(bfcr, BYTES_TO_BITS(available_bytes)); - bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE; - status = BT_BFCR_STATUS_EOF; - } else { - /* Found the null character */ - size_t result_len = (size_t) (result - first_chr); - - if (bfcr->user.cbs.classes.string && result_len) { - BT_COMP_LOGT("Calling user function (substring)."); - status = bfcr->user.cbs.classes.string((const char *) first_chr, result_len, - bfcr->cur_basic_field_class, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: " - "bfcr-addr=%p, status=%s", - bfcr, bt_bfcr_status_string(status)); - goto end; - } - } - - if (bfcr->user.cbs.classes.string_end) { - BT_COMP_LOGT("Calling user function (string, end)."); - status = - bfcr->user.cbs.classes.string_end(bfcr->cur_basic_field_class, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: " - "bfcr-addr=%p, status=%s", - bfcr, bt_bfcr_status_string(status)); - goto end; - } - } - - consume_bits(bfcr, BYTES_TO_BITS(result_len + 1)); - - if (stack_empty(bfcr->stack)) { - /* Root is a basic class */ - bfcr->state = BFCR_STATE_DONE; - } else { - /* Go to next field */ - stack_top(bfcr->stack)->index++; - bfcr->state = BFCR_STATE_NEXT_FIELD; - bfcr->last_bo = bfcr->cur_bo; - } - } - -end: - return status; -} - -static inline enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr) -{ - enum bt_bfcr_status status; - - BT_ASSERT_DBG(bfcr->cur_basic_field_class); - - switch (bfcr->cur_basic_field_class->type) { - case CTF_FIELD_CLASS_TYPE_INT: - case CTF_FIELD_CLASS_TYPE_ENUM: - status = read_basic_int_class_and_call_begin(bfcr); - break; - case CTF_FIELD_CLASS_TYPE_FLOAT: - status = read_basic_float_class_and_call_begin(bfcr); - break; - case CTF_FIELD_CLASS_TYPE_STRING: - status = read_basic_string_class_and_call(bfcr, true); - break; - default: - bt_common_abort(); - } - - return status; -} - -static inline enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr) -{ - enum bt_bfcr_status status; - - BT_ASSERT_DBG(bfcr->cur_basic_field_class); - - switch (bfcr->cur_basic_field_class->type) { - case CTF_FIELD_CLASS_TYPE_INT: - case CTF_FIELD_CLASS_TYPE_ENUM: - status = read_basic_int_class_and_call_continue(bfcr); - break; - case CTF_FIELD_CLASS_TYPE_FLOAT: - status = read_basic_float_class_and_call_continue(bfcr); - break; - case CTF_FIELD_CLASS_TYPE_STRING: - status = read_basic_string_class_and_call(bfcr, false); - break; - default: - bt_common_abort(); - } - - return status; -} - -static inline size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align) -{ - size_t aligned_packet_at; - - aligned_packet_at = BT_ALIGN(packet_at(bfcr), align); - return aligned_packet_at - packet_at(bfcr); -} - -static inline enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr, - struct ctf_field_class *field_class, - enum bfcr_state next_state) -{ - unsigned int field_alignment; - size_t skip_bits; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - - /* Get field's alignment */ - field_alignment = field_class->alignment; - - /* - * 0 means "undefined" for variants; what we really want is 1 - * (always aligned) - */ - BT_ASSERT_DBG(field_alignment >= 1); - - /* Compute how many bits we need to skip */ - skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment); - - /* Nothing to skip? aligned */ - if (skip_bits == 0) { - bfcr->state = next_state; - goto end; - } - - /* Make sure there's at least one bit left */ - if (!at_least_one_bit_left(bfcr)) { - status = BT_BFCR_STATUS_EOF; - goto end; - } - - /* Consume as many bits as possible in what's left */ - consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits)); - - /* Are we done now? */ - skip_bits = bits_to_skip_to_align_to(bfcr, field_alignment); - if (skip_bits == 0) { - /* Yes: go to next state */ - bfcr->state = next_state; - goto end; - } else { - /* No: need more data */ - BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr); - status = BT_BFCR_STATUS_EOF; - } - -end: - return status; -} - -static inline enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr) -{ - int ret; - struct stack_entry *top; - struct ctf_field_class *next_field_class = NULL; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - - if (stack_empty(bfcr->stack)) { - goto end; - } - - top = stack_top(bfcr->stack); - - /* Are we done with this base class? */ - while (top->index == top->base_len) { - if (bfcr->user.cbs.classes.compound_end) { - BT_COMP_LOGT("Calling user function (compound, end)."); - status = bfcr->user.cbs.classes.compound_end(top->base_class, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, - bt_bfcr_status_string(status)); - goto end; - } - } - - stack_pop(bfcr->stack); - - /* Are we done with the root class? */ - if (stack_empty(bfcr->stack)) { - bfcr->state = BFCR_STATE_DONE; - goto end; - } - - top = stack_top(bfcr->stack); - top->index++; - } - - /* Get next field's class */ - switch (top->base_class->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - next_field_class = ctf_field_class_struct_borrow_member_by_index( - ctf_field_class_as_struct(top->base_class), (uint64_t) top->index) - ->fc; - break; - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(top->base_class); - - next_field_class = array_fc->elem_fc; - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - /* Variant classes are dynamic: the user should know! */ - next_field_class = bfcr->user.cbs.query.borrow_variant_selected_field_class( - top->base_class, bfcr->user.data); - break; - default: - break; - } - - if (!next_field_class) { - BT_COMP_LOGW("Cannot get the field class of the next field: " - "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, " - "index=%" PRId64, - bfcr, top->base_class, top->base_class->type, top->index); - status = BT_BFCR_STATUS_ERROR; - goto end; - } - - if (next_field_class->is_compound) { - if (bfcr->user.cbs.classes.compound_begin) { - BT_COMP_LOGT("Calling user function (compound, begin)."); - status = bfcr->user.cbs.classes.compound_begin(next_field_class, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); - if (status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, - bt_bfcr_status_string(status)); - goto end; - } - } - - ret = stack_push_with_len(bfcr, next_field_class); - if (ret) { - /* stack_push_with_len() logs errors */ - status = BT_BFCR_STATUS_ERROR; - goto end; - } - - /* Next state: align a compound class */ - bfcr->state = BFCR_STATE_ALIGN_COMPOUND; - } else { - /* Replace current basic field class */ - BT_COMP_LOGT("Replacing current basic field class: " - "bfcr-addr=%p, cur-basic-fc-addr=%p, " - "next-basic-fc-addr=%p", - bfcr, bfcr->cur_basic_field_class, next_field_class); - bfcr->cur_basic_field_class = next_field_class; - - /* Next state: align a basic class */ - bfcr->state = BFCR_STATE_ALIGN_BASIC; - } - -end: - return status; -} - -static inline enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr) -{ - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - - BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s", bfcr, bfcr_state_string(bfcr->state)); - - switch (bfcr->state) { - case BFCR_STATE_NEXT_FIELD: - status = next_field_state(bfcr); - break; - case BFCR_STATE_ALIGN_BASIC: - status = align_class_state(bfcr, bfcr->cur_basic_field_class, BFCR_STATE_READ_BASIC_BEGIN); - break; - case BFCR_STATE_ALIGN_COMPOUND: - status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class, BFCR_STATE_NEXT_FIELD); - break; - case BFCR_STATE_READ_BASIC_BEGIN: - status = read_basic_begin_state(bfcr); - break; - case BFCR_STATE_READ_BASIC_CONTINUE: - status = read_basic_continue_state(bfcr); - break; - case BFCR_STATE_DONE: - break; - } - - BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s", bfcr, bt_bfcr_status_string(status)); - return status; -} - -struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, bt_logging_level log_level, - bt_self_component *self_comp) -{ - struct bt_bfcr *bfcr; - - BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp, - "Creating binary field class reader (BFCR)."); - bfcr = g_new0(struct bt_bfcr, 1); - if (!bfcr) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, - "Failed to allocate one binary class reader."); - goto end; - } - - bfcr->log_level = log_level; - bfcr->self_comp = self_comp; - bfcr->stack = stack_new(bfcr); - if (!bfcr->stack) { - BT_COMP_LOGE_STR("Cannot create BFCR's stack."); - bt_bfcr_destroy(bfcr); - bfcr = NULL; - goto end; - } - - bfcr->state = BFCR_STATE_NEXT_FIELD; - bfcr->user.cbs = cbs; - bfcr->user.data = data; - BT_COMP_LOGD("Created BFCR: addr=%p", bfcr); - -end: - return bfcr; -} - -void bt_bfcr_destroy(struct bt_bfcr *bfcr) -{ - if (bfcr->stack) { - stack_destroy(bfcr->stack); - } - - BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr); - g_free(bfcr); -} - -static void reset(struct bt_bfcr *bfcr) -{ - BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr); - stack_clear(bfcr->stack); - stitch_reset(bfcr); - bfcr->buf.addr = NULL; - bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN; -} - -static void update_packet_offset(struct bt_bfcr *bfcr) -{ - BT_COMP_LOGT("Updating packet offset for next call: " - "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu", - bfcr, bfcr->buf.packet_offset, bfcr->buf.packet_offset + bfcr->buf.at); - bfcr->buf.packet_offset += bfcr->buf.at; -} - -size_t bt_bfcr_start(struct bt_bfcr *bfcr, struct ctf_field_class *cls, const uint8_t *buf, - size_t offset, size_t packet_offset, size_t sz, enum bt_bfcr_status *status) -{ - BT_ASSERT_DBG(bfcr); - BT_ASSERT_DBG(BYTES_TO_BITS(sz) >= offset); - reset(bfcr); - bfcr->buf.addr = buf; - bfcr->buf.offset = offset; - bfcr->buf.at = 0; - bfcr->buf.packet_offset = packet_offset; - bfcr->buf.buf_sz = sz; - bfcr->buf.sz = BYTES_TO_BITS(sz) - offset; - *status = BT_BFCR_STATUS_OK; - - BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, " - "buf-addr=%p, buf-size=%zu, offset=%zu, " - "packet-offset=%zu", - bfcr, cls, buf, sz, offset, packet_offset); - - /* Set root class */ - if (cls->is_compound) { - /* Compound class: push on visit stack */ - int stack_ret; - - if (bfcr->user.cbs.classes.compound_begin) { - BT_COMP_LOGT("Calling user function (compound, begin)."); - *status = bfcr->user.cbs.classes.compound_begin(cls, bfcr->user.data); - BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(*status)); - if (*status != BT_BFCR_STATUS_OK) { - BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, - bt_bfcr_status_string(*status)); - goto end; - } - } - - stack_ret = stack_push_with_len(bfcr, cls); - if (stack_ret) { - /* stack_push_with_len() logs errors */ - *status = BT_BFCR_STATUS_ERROR; - goto end; - } - - bfcr->state = BFCR_STATE_ALIGN_COMPOUND; - } else { - /* Basic class: set as current basic class */ - bfcr->cur_basic_field_class = cls; - bfcr->state = BFCR_STATE_ALIGN_BASIC; - } - - /* Run the machine! */ - BT_COMP_LOGT_STR("Running the state machine."); - - while (true) { - *status = handle_state(bfcr); - if (*status != BT_BFCR_STATUS_OK || bfcr->state == BFCR_STATE_DONE) { - break; - } - } - - /* Update packet offset for next time */ - update_packet_offset(bfcr); - -end: - return bfcr->buf.at; -} - -size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz, - enum bt_bfcr_status *status) -{ - BT_ASSERT_DBG(bfcr); - BT_ASSERT_DBG(buf); - BT_ASSERT_DBG(sz > 0); - bfcr->buf.addr = buf; - bfcr->buf.offset = 0; - bfcr->buf.at = 0; - bfcr->buf.buf_sz = sz; - bfcr->buf.sz = BYTES_TO_BITS(sz); - *status = BT_BFCR_STATUS_OK; - - BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu", bfcr, buf, sz); - - /* Continue running the machine */ - BT_COMP_LOGT_STR("Running the state machine."); - - while (true) { - *status = handle_state(bfcr); - if (*status != BT_BFCR_STATUS_OK || bfcr->state == BFCR_STATE_DONE) { - break; - } - } - - /* Update packet offset for next time */ - update_packet_offset(bfcr); - return bfcr->buf.at; -} - -void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb) -{ - BT_ASSERT_DBG(bfcr); - BT_ASSERT_DBG(cb); - bfcr->user.cbs.classes.unsigned_int = cb; -} diff --git a/src/plugins/ctf/common/bfcr/bfcr.hpp b/src/plugins/ctf/common/bfcr/bfcr.hpp deleted file mode 100644 index f2fe8796..00000000 --- a/src/plugins/ctf/common/bfcr/bfcr.hpp +++ /dev/null @@ -1,346 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015-2016 Philippe Proulx - * - * Babeltrace - CTF binary field class reader (BFCR) - */ - -#ifndef CTF_BFCR_H -#define CTF_BFCR_H - -#include -#include - -#include - -#include "common/common.h" - -/** - * @file bfcr.h - * - * Event-driven CTF binary field class reader (BFCR). - * - * This is a common, internal API used by CTF source plugins. It allows - * a binary CTF IR field class to be decoded from user-provided buffers. - * As the class is decoded (and, possibly, its nested classes), - * registered user callback functions are called. - * - * This API is only concerned with reading one CTF class at a time from - * one or more buffer of bytes. It does not know CTF dynamic scopes, - * events, or streams. Sequence lengths and selected variant classes are - * requested to the user when needed. - */ - -/** - * Binary class reader API status codes. - */ -enum bt_bfcr_status -{ - /** Out of memory. */ - BT_BFCR_STATUS_ENOMEM = -5, - /** - * The binary stream reader reached the end of the user-provided - * buffer, but data is still needed to finish decoding the - * requested class. - * - * The user needs to call bt_bfcr_continue() as long as - * #BT_BFCR_STATUS_EOF is returned to complete the decoding - * process of a given class. - */ - BT_BFCR_STATUS_EOF = 1, - - /** Invalid argument. */ - BT_BFCR_STATUS_INVAL = -3, - - /** General error. */ - BT_BFCR_STATUS_ERROR = -1, - - /** Everything okay. */ - BT_BFCR_STATUS_OK = 0, -}; - -typedef enum bt_bfcr_status (*bt_bfcr_unsigned_int_cb_func)(uint64_t, struct ctf_field_class *, - void *); - -/* - * Field class reader user callback functions. - */ -struct bt_bfcr_cbs -{ - /** - * Field class callback functions. - * - * This CTF binary class reader is event-driven. The following - * functions are called during the decoding process, either when - * a compound class begins/ends, or when a basic class is - * completely decoded (along with its value). - * - * Each function also receives the CTF field class associated - * with the call, and user data (registered to the class reader - * calling them). - * - * Actual trace IR fields are \em not created here; this would - * be the responsibility of a class reader's user (the provider - * of those callback functions). - * - * All the class callback functions return one of the following - * values: - * - * - #BT_BFCR_STATUS_OK: Everything is okay; - * continue the decoding process. - * - #BT_BFCR_STATUS_ERROR: General error (reported - * to class reader's user). - * - * Any member of this structure may be set to \c NULL, should - * a specific message be not needed. - */ - struct - { - /** - * Called when a signed integer class is completely - * decoded. This could also be the supporting signed - * integer class of an enumeration class (\p class will - * indicate this). - * - * @param value Signed integer value - * @param class Integer or enumeration class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - enum bt_bfcr_status (*signed_int)(int64_t value, struct ctf_field_class *cls, void *data); - - /** - * Called when an unsigned integer class is completely - * decoded. This could also be the supporting signed - * integer class of an enumeration class (\p class will - * indicate this). - * - * @param value Unsigned integer value - * @param class Integer or enumeration class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - bt_bfcr_unsigned_int_cb_func unsigned_int; - - /** - * Called when a floating point number class is - * completely decoded. - * - * @param value Floating point number value - * @param class Floating point number class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - enum bt_bfcr_status (*floating_point)(double value, struct ctf_field_class *cls, - void *data); - - /** - * Called when a string class begins. - * - * All the following user callback function calls will - * be made to bt_bfcr_cbs::classes::string(), each of - * them providing one substring of the complete string - * class's value. - * - * @param class Beginning string class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - enum bt_bfcr_status (*string_begin)(struct ctf_field_class *cls, void *data); - - /** - * Called when a string class's substring is decoded - * (between a call to bt_bfcr_cbs::classes::string_begin() - * and a call to bt_bfcr_cbs::classes::string_end()). - * - * @param value String value (\em not null-terminated) - * @param len String value length - * @param class String class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - enum bt_bfcr_status (*string)(const char *value, size_t len, struct ctf_field_class *cls, - void *data); - - /** - * Called when a string class ends. - * - * @param class Ending string class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - enum bt_bfcr_status (*string_end)(struct ctf_field_class *cls, void *data); - - /** - * Called when a compound class begins. - * - * All the following class callback function calls will - * signal sequential elements of this compound class, - * until the next corresponding - * bt_bfcr_cbs::classes::compound_end() is called. - * - * If \p class is a variant class, then only one class - * callback function call will follow before the call to - * bt_bfcr_cbs::classes::compound_end(). This single - * call indicates the selected class of this variant - * class. - * - * @param class Beginning compound class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - enum bt_bfcr_status (*compound_begin)(struct ctf_field_class *cls, void *data); - - /** - * Called when a compound class ends. - * - * @param class Ending compound class - * @param data User data - * @returns #BT_BFCR_STATUS_OK or - * #BT_BFCR_STATUS_ERROR - */ - enum bt_bfcr_status (*compound_end)(struct ctf_field_class *cls, void *data); - } classes; - - /** - * Query callback functions are used when the class reader needs - * dynamic information, i.e. a sequence class's current length - * or a variant class's current selected class. - * - * Both functions need to be set unless it is known that no - * sequences or variants will have to be decoded. - */ - struct - { - /** - * Called to query the current length of a given sequence - * class. - * - * @param class Sequence class - * @param data User data - * @returns Sequence length or - * #BT_BFCR_STATUS_ERROR on error - */ - int64_t (*get_sequence_length)(struct ctf_field_class *cls, void *data); - - /** - * Called to query the current selected class of a given - * variant class. - * - * @param class Variant class - * @param data User data - * @returns Current selected class (owned by - * this) or \c NULL on error - */ - struct ctf_field_class *(*borrow_variant_selected_field_class)(struct ctf_field_class *cls, - void *data); - } query; -}; - -/** - * Creates a CTF binary class reader. - * - * @param cbs User callback functions - * @param data User data (passed to user callback functions) - * @returns New binary class reader on success, or \c NULL on error - */ -struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, bt_logging_level log_level, - bt_self_component *self_comp); - -/** - * Destroys a CTF binary class reader, freeing all internal resources. - * - * @param bfcr Binary class reader - */ -void bt_bfcr_destroy(struct bt_bfcr *bfcr); - -/** - * Decodes a given CTF class from a buffer of bytes. - * - * The number of \em bits consumed by this function is returned. - * - * The \p status output parameter is where a status is written, amongst - * the following: - * - * - #BT_BFCR_STATUS_OK: Decoding is done. - * - #BT_BFCR_STATUS_EOF: The end of the buffer was reached, - * but more data is needed to finish the decoding process of the - * requested class. The user needs to call bt_bfcr_continue() - * as long as #BT_BFCR_STATUS_EOF is returned to complete the - * decoding process of the original class. - * - #BT_BFCR_STATUS_INVAL: Invalid argument. - * - #BT_BFCR_STATUS_ERROR: General error. - * - * Calling this function resets the class reader's internal state. If - * #BT_BFCR_STATUS_EOF is returned, bt_bfcr_continue() needs to - * be called next, \em not bt_bfcr_decode(). - * - * @param bfcr Binary class reader - * @param class Field class to decode - * @param buf Buffer - * @param offset Offset of first bit from \p buf (bits) - * @param packet_offset Offset of \p offset within the CTF - * binary packet containing \p class (bits) - * @param sz Size of buffer in bytes (from \p buf) - * @param status Returned status (see description above) - * @returns Number of consumed bits - */ -size_t bt_bfcr_start(struct bt_bfcr *bfcr, struct ctf_field_class *cls, const uint8_t *buf, - size_t offset, size_t packet_offset, size_t sz, enum bt_bfcr_status *status); - -/** - * Continues the decoding process a given CTF class. - * - * The number of bits consumed by this function is returned. - * - * The \p status output parameter is where a status is placed, amongst - * the following: - * - * - #BT_BFCR_STATUS_OK: decoding is done. - * - #BT_BFCR_STATUS_EOF: the end of the buffer was reached, - * but more data is needed to finish the decoding process of the - * requested class. The user needs to call bt_bfcr_continue() - * as long as #BT_BFCR_STATUS_EOF is returned to complete the - * decoding process of the original class. - * - #BT_BFCR_STATUS_INVAL: invalid argument. - * - #BT_BFCR_STATUS_ERROR: general error. - * - * @param bfcr Binary class reader - * @param buf Buffer - * @param sz Size of buffer in bytes (from \p offset) - * @param status Returned status (see description above) - * @returns Number of consumed bits - */ -size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz, - enum bt_bfcr_status *status); - -void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb); - -static inline const char *bt_bfcr_status_string(enum bt_bfcr_status status) -{ - switch (status) { - case BT_BFCR_STATUS_ENOMEM: - return "ENOMEM"; - case BT_BFCR_STATUS_EOF: - return "EOF"; - case BT_BFCR_STATUS_INVAL: - return "INVAL"; - case BT_BFCR_STATUS_ERROR: - return "ERROR"; - case BT_BFCR_STATUS_OK: - return "OK"; - } - - bt_common_abort(); -} - -#endif /* CTF_BFCR_H */ diff --git a/src/plugins/ctf/common/metadata/ast.hpp b/src/plugins/ctf/common/metadata/ast.hpp deleted file mode 100644 index a6a7e9f7..00000000 --- a/src/plugins/ctf/common/metadata/ast.hpp +++ /dev/null @@ -1,458 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011-2012 Mathieu Desnoyers - */ - -#ifndef _CTF_AST_H -#define _CTF_AST_H - -#include -#include -#include - -#include - -#include "common/assert.h" -#include "common/list.h" - -#include "ctf-meta.hpp" -#include "decoder.hpp" - -// the parameter name (of the reentrant 'yyparse' function) -// data is a pointer to a 'SParserParam' structure -//#define YYPARSE_PARAM scanner - -struct ctf_node; -struct ctf_parser; -struct ctf_visitor_generate_ir; - -#define EINCOMPLETE 1000 - -#define FOREACH_CTF_NODES(F) \ - F(NODE_UNKNOWN) \ - F(NODE_ROOT) \ - F(NODE_ERROR) \ - F(NODE_EVENT) \ - F(NODE_STREAM) \ - F(NODE_ENV) \ - F(NODE_TRACE) \ - F(NODE_CLOCK) \ - F(NODE_CALLSITE) \ - F(NODE_CTF_EXPRESSION) \ - F(NODE_UNARY_EXPRESSION) \ - F(NODE_TYPEDEF) \ - F(NODE_TYPEALIAS_TARGET) \ - F(NODE_TYPEALIAS_ALIAS) \ - F(NODE_TYPEALIAS) \ - F(NODE_TYPE_SPECIFIER) \ - F(NODE_TYPE_SPECIFIER_LIST) \ - F(NODE_POINTER) \ - F(NODE_TYPE_DECLARATOR) \ - F(NODE_FLOATING_POINT) \ - F(NODE_INTEGER) \ - F(NODE_STRING) \ - F(NODE_ENUMERATOR) \ - F(NODE_ENUM) \ - F(NODE_STRUCT_OR_VARIANT_DECLARATION) \ - F(NODE_VARIANT) \ - F(NODE_STRUCT) - -enum node_type -{ -#define ENTRY(S) S, - FOREACH_CTF_NODES(ENTRY) -#undef ENTRY -}; - -enum ctf_unary -{ - UNARY_UNKNOWN = 0, - UNARY_STRING, - UNARY_SIGNED_CONSTANT, - UNARY_UNSIGNED_CONSTANT, - UNARY_SBRAC, -}; - -enum ctf_unary_link -{ - UNARY_LINK_UNKNOWN = 0, - UNARY_DOTLINK, - UNARY_ARROWLINK, - UNARY_DOTDOTDOT, -}; - -enum ctf_typedec -{ - TYPEDEC_UNKNOWN = 0, - TYPEDEC_ID, /* identifier */ - TYPEDEC_NESTED, /* (), array or sequence */ -}; - -enum ctf_typespec -{ - TYPESPEC_UNKNOWN = 0, - TYPESPEC_VOID, - TYPESPEC_CHAR, - TYPESPEC_SHORT, - TYPESPEC_INT, - TYPESPEC_LONG, - TYPESPEC_FLOAT, - TYPESPEC_DOUBLE, - TYPESPEC_SIGNED, - TYPESPEC_UNSIGNED, - TYPESPEC_BOOL, - TYPESPEC_COMPLEX, - TYPESPEC_IMAGINARY, - TYPESPEC_CONST, - TYPESPEC_ID_TYPE, - TYPESPEC_FLOATING_POINT, - TYPESPEC_INTEGER, - TYPESPEC_STRING, - TYPESPEC_STRUCT, - TYPESPEC_VARIANT, - TYPESPEC_ENUM, -}; - -struct ctf_node -{ - /* - * Parent node is only set on demand by specific visitor. - */ - struct ctf_node *parent; - struct bt_list_head siblings; - struct bt_list_head tmp_head; - unsigned int lineno; - /* - * We mark nodes visited in the generate-ir phase (last - * phase). We only mark the 1-depth level nodes as visited - * (never the root node, and not their sub-nodes). This allows - * skipping already visited nodes when doing incremental - * metadata append. - */ - int visited; - - enum node_type type; - union - { - struct - { - } unknown; - struct - { - /* - * Children nodes are ctf_expression, field_class_def, - * field_class_alias and field_class_specifier_list. - */ - struct bt_list_head declaration_list; - struct bt_list_head trace; - struct bt_list_head env; - struct bt_list_head stream; - struct bt_list_head event; - struct bt_list_head clock; - struct bt_list_head callsite; - } root; - struct - { - /* - * Children nodes are ctf_expression, field_class_def, - * field_class_alias and field_class_specifier_list. - */ - struct bt_list_head declaration_list; - } event; - struct - { - /* - * Children nodes are ctf_expression, field_class_def, - * field_class_alias and field_class_specifier_list. - */ - struct bt_list_head declaration_list; - } stream; - struct - { - /* - * Children nodes are ctf_expression, field_class_def, - * field_class_alias and field_class_specifier_list. - */ - struct bt_list_head declaration_list; - } env; - struct - { - /* - * Children nodes are ctf_expression, field_class_def, - * field_class_alias and field_class_specifier_list. - */ - struct bt_list_head declaration_list; - } trace; - struct - { - /* - * Children nodes are ctf_expression, field_class_def, - * field_class_alias and field_class_specifier_list. - */ - struct bt_list_head declaration_list; - } clock; - struct - { - /* - * Children nodes are ctf_expression, field_class_def, - * field_class_alias and field_class_specifier_list. - */ - struct bt_list_head declaration_list; - } callsite; - struct - { - struct bt_list_head left; /* Should be string */ - struct bt_list_head right; /* Unary exp. or type */ - } ctf_expression; - struct - { - ctf_unary type; - union - { - /* - * string for identifier, id_type, keywords, - * string literals and character constants. - */ - char *string; - int64_t signed_constant; - uint64_t unsigned_constant; - struct ctf_node *sbrac_exp; - } u; - ctf_unary_link link; - } unary_expression; - struct - { - struct ctf_node *field_class_specifier_list; - struct bt_list_head field_class_declarators; - } field_class_def; - /* new type is "alias", existing type "target" */ - struct - { - struct ctf_node *field_class_specifier_list; - struct bt_list_head field_class_declarators; - } field_class_alias_target; - struct - { - struct ctf_node *field_class_specifier_list; - struct bt_list_head field_class_declarators; - } field_class_alias_name; - struct - { - struct ctf_node *target; - struct ctf_node *alias; - } field_class_alias; - struct - { - ctf_typespec type; - /* For struct, variant and enum */ - struct ctf_node *node; - const char *id_type; - } field_class_specifier; - struct - { - /* list of field_class_specifier */ - struct bt_list_head head; - } field_class_specifier_list; - struct - { - unsigned int const_qualifier; - } pointer; - struct - { - struct bt_list_head pointers; - ctf_typedec type; - union - { - char *id; - struct - { - /* typedec has no pointer list */ - struct ctf_node *field_class_declarator; - /* - * unary expression (value) or - * field_class_specifier_list. - */ - struct bt_list_head length; - /* for abstract type declarator */ - unsigned int abstract_array; - } nested; - } u; - struct ctf_node *bitfield_len; - } field_class_declarator; - struct - { - /* Children nodes are ctf_expression. */ - struct bt_list_head expressions; - } floating_point; - struct - { - /* Children nodes are ctf_expression. */ - struct bt_list_head expressions; - } integer; - struct - { - /* Children nodes are ctf_expression. */ - struct bt_list_head expressions; - } string; - struct - { - char *id; - /* - * Range list or single value node. Contains unary - * expressions. - */ - struct bt_list_head values; - } enumerator; - struct - { - char *enum_id; - /* - * Either NULL, or points to unary expression or - * field_class_specifier_list. - */ - struct ctf_node *container_field_class; - struct bt_list_head enumerator_list; - int has_body; - } _enum; - struct - { - struct ctf_node *field_class_specifier_list; - struct bt_list_head field_class_declarators; - } struct_or_variant_declaration; - struct - { - char *name; - char *choice; - /* - * list of field_class_def, field_class_alias and - * declarations - */ - struct bt_list_head declaration_list; - int has_body; - } variant; - struct - { - char *name; - /* - * list of field_class_def, field_class_alias and - * declarations - */ - struct bt_list_head declaration_list; - int has_body; - struct bt_list_head min_align; /* align() attribute */ - } _struct; - } u; -}; - -struct ctf_ast -{ - struct ctf_node root; -}; - -const char *node_type(struct ctf_node *node); - -struct meta_log_config; - -struct ctf_visitor_generate_ir * -ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *config); - -void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor); - -bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *visitor); - -struct ctf_trace_class * -ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *visitor); - -int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor, - struct ctf_node *node); - -int ctf_visitor_semantic_check(int depth, struct ctf_node *node, struct meta_log_config *log_cfg); - -int ctf_visitor_parent_links(int depth, struct ctf_node *node, struct meta_log_config *log_cfg); - -static inline char *ctf_ast_concatenate_unary_strings(struct bt_list_head *head) -{ - int i = 0; - GString *str; - struct ctf_node *node; - - str = g_string_new(NULL); - BT_ASSERT(str); - - bt_list_for_each_entry (node, head, siblings) { - char *src_string; - - if (node->type != NODE_UNARY_EXPRESSION || node->u.unary_expression.type != UNARY_STRING || - !((node->u.unary_expression.link != UNARY_LINK_UNKNOWN) ^ (i == 0))) { - goto error; - } - - switch (node->u.unary_expression.link) { - case UNARY_DOTLINK: - g_string_append(str, "."); - break; - case UNARY_ARROWLINK: - g_string_append(str, "->"); - break; - case UNARY_DOTDOTDOT: - g_string_append(str, "..."); - break; - default: - break; - } - - src_string = node->u.unary_expression.u.string; - g_string_append(str, src_string); - i++; - } - - /* Destroys the container, returns the underlying string */ - return g_string_free(str, FALSE); - -error: - /* This always returns NULL */ - return g_string_free(str, TRUE); -} - -#ifndef BT_COMP_LOG_CUR_LVL -# define BT_AST_LOG_LEVEL_UNUSED_ATTR __attribute__((unused)) -#else -# define BT_AST_LOG_LEVEL_UNUSED_ATTR -#endif - -static inline int ctf_ast_get_unary_uuid(struct bt_list_head *head, bt_uuid_t uuid, - int log_level BT_AST_LOG_LEVEL_UNUSED_ATTR, - bt_self_component *self_comp BT_AST_LOG_LEVEL_UNUSED_ATTR) -{ - int i = 0; - int ret = 0; - struct ctf_node *node; - - bt_list_for_each_entry (node, head, siblings) { - int uexpr_type = node->u.unary_expression.type; - int uexpr_link = node->u.unary_expression.link; - const char *src_string; - - if (node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_STRING || - uexpr_link != UNARY_LINK_UNKNOWN || i != 0) { - ret = -EINVAL; - goto end; - } - - src_string = node->u.unary_expression.u.string; - ret = bt_uuid_from_str(src_string, uuid); - if (ret) { -#ifdef BT_COMP_LOG_CUR_LVL - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, - "Cannot parse UUID: uuid=\"%s\"", src_string); -#endif - goto end; - } - } - -end: - return ret; -} - -#endif /* _CTF_AST_H */ diff --git a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp b/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp deleted file mode 100644 index ef178c53..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Philippe Proulx - */ - -#include - -#include "common/assert.h" - -#include "ctf-meta-configure-ir-trace.hpp" -#include "plugins/ctf/common/metadata/ctf-meta.hpp" - -int ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, bt_trace *ir_trace) -{ - int ret = 0; - uint64_t i; - - BT_ASSERT(tc); - BT_ASSERT(ir_trace); - - if (tc->is_uuid_set) { - bt_trace_set_uuid(ir_trace, tc->uuid); - } - - for (i = 0; i < tc->env_entries->len; i++) { - struct ctf_trace_class_env_entry *env_entry = - ctf_trace_class_borrow_env_entry_by_index(tc, i); - - switch (env_entry->type) { - case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT: - ret = bt_trace_set_environment_entry_integer(ir_trace, env_entry->name->str, - env_entry->value.i); - break; - case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR: - ret = bt_trace_set_environment_entry_string(ir_trace, env_entry->name->str, - env_entry->value.str->str); - break; - default: - bt_common_abort(); - } - - if (ret) { - goto end; - } - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp b/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp deleted file mode 100644 index f94f19e6..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Philippe Proulx - */ - -#ifndef _CTF_META_CONFIGURE_IR_TRACE_H -#define _CTF_META_CONFIGURE_IR_TRACE_H - -#include - -int ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, bt_trace *ir_trace); - -#endif /* _CTF_META_CONFIGURE_IR_TRACE_H */ diff --git a/src/plugins/ctf/common/metadata/ctf-meta-resolve.cpp b/src/plugins/ctf/common/metadata/ctf-meta-resolve.cpp deleted file mode 100644 index 1f7ffe57..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-resolve.cpp +++ /dev/null @@ -1,1261 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2018 Philippe Proulx - * Copyright 2015 Jérémie Galarneau - */ - -#include -#include -#include -#include - -#include - -#define BT_COMP_LOG_SELF_COMP (ctx->self_comp) -#define BT_COMP_LOG_SELF_COMP_CLASS (ctx->self_comp_class) -#define BT_LOG_OUTPUT_LEVEL ((enum bt_log_level) ctx->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/RESOLVE" -#include "logging.hpp" -#include "logging/comp-logging.h" - -#include "common/assert.h" -#include "common/common.h" - -#include "ctf-meta-visitors.hpp" - -using field_class_stack_t = GPtrArray; - -/* - * A stack frame. - * - * `fc` contains a compound field class (structure, variant, array, - * or sequence) and `index` indicates the index of the field class in - * the upper frame (-1 for array and sequence field classes). `name` - * indicates the name of the field class in the upper frame (empty - * string for array and sequence field classes). - */ -struct field_class_stack_frame -{ - struct ctf_field_class *fc; - int64_t index; -}; - -/* - * The current context of the resolving engine. - */ -struct resolve_context -{ - bt_logging_level log_level; - - /* Weak, exactly one of these must be set */ - bt_self_component *self_comp; - bt_self_component_class *self_comp_class; - - struct ctf_trace_class *tc; - struct ctf_stream_class *sc; - struct ctf_event_class *ec; - - struct - { - struct ctf_field_class *packet_header; - struct ctf_field_class *packet_context; - struct ctf_field_class *event_header; - struct ctf_field_class *event_common_context; - struct ctf_field_class *event_spec_context; - struct ctf_field_class *event_payload; - } scopes; - - /* Root scope being visited */ - enum ctf_scope root_scope; - field_class_stack_t *field_class_stack; - struct ctf_field_class *cur_fc; -}; - -/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */ -static const char * const absolute_path_prefixes[] = { - /* CTF_SCOPE_PACKET_HEADER */ "trace.packet.header.", - /* CTF_SCOPE_PACKET_CONTEXT */ "stream.packet.context.", - /* CTF_SCOPE_EVENT_HEADER */ "stream.event.header.", - /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ "stream.event.context.", - /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ "event.context.", - /* CTF_SCOPE_EVENT_PAYLOAD */ "event.fields.", -}; - -/* Number of path tokens used for the absolute prefixes */ -static const uint64_t absolute_path_prefix_ptoken_counts[] = { - /* CTF_SCOPE_PACKET_HEADER */ 3, - /* CTF_SCOPE_PACKET_CONTEXT */ 3, - /* CTF_SCOPE_EVENT_HEADER */ 3, - /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ 3, - /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ 2, - /* CTF_SCOPE_EVENT_PAYLOAD */ 2, -}; - -static void destroy_field_class_stack_frame(struct field_class_stack_frame *frame) -{ - if (!frame) { - return; - } - - g_free(frame); -} - -/* - * Creates a class stack. - */ -static field_class_stack_t *field_class_stack_create(void) -{ - return g_ptr_array_new_with_free_func((GDestroyNotify) destroy_field_class_stack_frame); -} - -/* - * Destroys a class stack. - */ -static void field_class_stack_destroy(field_class_stack_t *stack) -{ - if (stack) { - g_ptr_array_free(stack, TRUE); - } -} - -/* - * Pushes a field class onto a class stack. - */ -static int field_class_stack_push(field_class_stack_t *stack, struct ctf_field_class *fc, - struct resolve_context *ctx) -{ - int ret = 0; - struct field_class_stack_frame *frame = NULL; - - if (!stack || !fc) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid parameter: stack or field class is `NULL`."); - ret = -1; - goto end; - } - - frame = g_new0(struct field_class_stack_frame, 1); - if (!frame) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one field class stack frame."); - ret = -1; - goto end; - } - - BT_COMP_LOGD("Pushing field class on context's stack: " - "fc-addr=%p, stack-size-before=%u", - fc, stack->len); - frame->fc = fc; - g_ptr_array_add(stack, frame); - -end: - return ret; -} - -/* - * Checks whether or not `stack` is empty. - */ -static bool field_class_stack_empty(field_class_stack_t *stack) -{ - return stack->len == 0; -} - -/* - * Returns the number of frames in `stack`. - */ -static size_t field_class_stack_size(field_class_stack_t *stack) -{ - return stack->len; -} - -/* - * Returns the top frame of `stack`. - */ -static struct field_class_stack_frame *field_class_stack_peek(field_class_stack_t *stack) -{ - BT_ASSERT(stack); - BT_ASSERT(!field_class_stack_empty(stack)); - - return (field_class_stack_frame *) g_ptr_array_index(stack, stack->len - 1); -} - -/* - * Returns the frame at index `index` in `stack`. - */ -static struct field_class_stack_frame *field_class_stack_at(field_class_stack_t *stack, - size_t index) -{ - BT_ASSERT(stack); - BT_ASSERT(index < stack->len); - - return (field_class_stack_frame *) g_ptr_array_index(stack, index); -} - -/* - * Removes the top frame of `stack`. - */ -static void field_class_stack_pop(field_class_stack_t *stack, struct resolve_context *ctx) -{ - if (!field_class_stack_empty(stack)) { - /* - * This will call the frame's destructor and free it, as - * well as put its contained field class. - */ - BT_COMP_LOGD("Popping context's stack: stack-size-before=%u", stack->len); - g_ptr_array_set_size(stack, stack->len - 1); - } -} - -/* - * Returns the scope field class of `scope` in the context `ctx`. - */ -static struct ctf_field_class *borrow_class_from_ctx(struct resolve_context *ctx, - enum ctf_scope scope) -{ - switch (scope) { - case CTF_SCOPE_PACKET_HEADER: - return ctx->scopes.packet_header; - case CTF_SCOPE_PACKET_CONTEXT: - return ctx->scopes.packet_context; - case CTF_SCOPE_EVENT_HEADER: - return ctx->scopes.event_header; - case CTF_SCOPE_EVENT_COMMON_CONTEXT: - return ctx->scopes.event_common_context; - case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: - return ctx->scopes.event_spec_context; - case CTF_SCOPE_EVENT_PAYLOAD: - return ctx->scopes.event_payload; - default: - bt_common_abort(); - } - - return NULL; -} - -/* - * Returns the CTF scope from a path string. May return -1 if the path - * is found to be relative. - */ -static enum ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr, - struct resolve_context *ctx) -{ - enum ctf_scope scope; - enum ctf_scope ret = CTF_SCOPE_PACKET_UNKNOWN; - const size_t prefixes_count = sizeof(absolute_path_prefixes) / sizeof(*absolute_path_prefixes); - - for (scope = CTF_SCOPE_PACKET_HEADER; scope < CTF_SCOPE_PACKET_HEADER + prefixes_count; - scope = (ctf_scope) (scope + 1)) { - /* - * Check if path string starts with a known absolute - * path prefix. - * - * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES. - */ - if (strncmp(pathstr, absolute_path_prefixes[scope], - strlen(absolute_path_prefixes[scope]))) { - /* Prefix does not match: try the next one */ - BT_COMP_LOGD("Prefix does not match: trying the next one: " - "path=\"%s\", path-prefix=\"%s\", scope=%s", - pathstr, absolute_path_prefixes[scope], ctf_scope_string(scope)); - continue; - } - - /* Found it! */ - ret = scope; - BT_COMP_LOGD("Found root scope from absolute path: " - "path=\"%s\", scope=%s", - pathstr, ctf_scope_string(scope)); - goto end; - } - -end: - return ret; -} - -/* - * Destroys a path token. - */ -static void ptokens_destroy_func(gpointer ptoken, gpointer) -{ - g_string_free((GString *) ptoken, TRUE); -} - -/* - * Destroys a path token list. - */ -static void ptokens_destroy(GList *ptokens) -{ - if (!ptokens) { - return; - } - - g_list_foreach(ptokens, ptokens_destroy_func, NULL); - g_list_free(ptokens); -} - -/* - * Returns the string contained in a path token. - */ -static const char *ptoken_get_string(GList *ptoken) -{ - GString *tokenstr = (GString *) ptoken->data; - - return tokenstr->str; -} - -/* - * Converts a path string to a path token list, that is, splits the - * individual words of a path string into a list of individual - * strings. - */ -static GList *pathstr_to_ptokens(const char *pathstr, struct resolve_context *ctx) -{ - const char *at = pathstr; - const char *last = at; - GList *ptokens = NULL; - - for (;;) { - if (*at == '.' || *at == '\0') { - GString *tokenstr; - - if (at == last) { - /* Error: empty token */ - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Empty path token: path=\"%s\", pos=%u", - pathstr, (unsigned int) (at - pathstr)); - goto error; - } - - tokenstr = g_string_new(NULL); - g_string_append_len(tokenstr, last, at - last); - ptokens = g_list_append(ptokens, tokenstr); - last = at + 1; - } - - if (*at == '\0') { - break; - } - - at++; - } - - return ptokens; - -error: - ptokens_destroy(ptokens); - return NULL; -} - -/* - * Converts a path token list to a field path object. The path token - * list is relative from `fc`. The index of the source looking for its - * target within `fc` is indicated by `src_index`. This can be - * `INT64_MAX` if the source is contained in `fc`. - * - * `field_path` is an output parameter owned by the caller that must be - * filled here. - */ -static int ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path, - struct ctf_field_class *fc, int64_t src_index, - struct resolve_context *ctx) -{ - int ret = 0; - GList *cur_ptoken = ptokens; - bool first_level_done = false; - - /* Locate target */ - while (cur_ptoken) { - int64_t child_index; - struct ctf_field_class *child_fc; - const char *ft_name = ptoken_get_string(cur_ptoken); - - BT_COMP_LOGD("Current path token: token=\"%s\"", ft_name); - - /* Find to which index corresponds the current path token */ - if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { - child_index = -1; - } else { - child_index = - ctf_field_class_compound_get_field_class_index_from_orig_name(fc, ft_name); - if (child_index < 0) { - /* - * Error: field name does not exist or - * wrong current class. - */ - BT_COMP_LOGD("Cannot get index of field class: " - "field-name=\"%s\", " - "src-index=%" PRId64 ", " - "child-index=%" PRId64 ", " - "first-level-done=%d", - ft_name, src_index, child_index, first_level_done); - ret = -1; - goto end; - } else if (child_index > src_index && !first_level_done) { - BT_COMP_LOGD("Child field class is located after source field class: " - "field-name=\"%s\", " - "src-index=%" PRId64 ", " - "child-index=%" PRId64 ", " - "first-level-done=%d", - ft_name, src_index, child_index, first_level_done); - ret = -1; - goto end; - } - - /* Next path token */ - cur_ptoken = g_list_next(cur_ptoken); - first_level_done = true; - } - - /* Create new field path entry */ - ctf_field_path_append_index(field_path, child_index); - - /* Get child field class */ - child_fc = ctf_field_class_compound_borrow_field_class_by_index(fc, child_index); - BT_ASSERT(child_fc); - - /* Move child class to current class */ - fc = child_fc; - } - -end: - return ret; -} - -/* - * Converts a known absolute path token list to a field path object - * within the resolving context `ctx`. - * - * `field_path` is an output parameter owned by the caller that must be - * filled here. - */ -static int absolute_ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path, - struct resolve_context *ctx) -{ - int ret = 0; - GList *cur_ptoken; - struct ctf_field_class *fc; - - /* - * Make sure we're not referring to a scope within a translated - * object. - */ - switch (field_path->root) { - case CTF_SCOPE_PACKET_HEADER: - if (ctx->tc->is_translated) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Trace class is already translated: " - "root-scope=%s", - ctf_scope_string(field_path->root)); - ret = -1; - goto end; - } - - break; - case CTF_SCOPE_PACKET_CONTEXT: - case CTF_SCOPE_EVENT_HEADER: - case CTF_SCOPE_EVENT_COMMON_CONTEXT: - if (!ctx->sc) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current stream class: " - "root-scope=%s", - ctf_scope_string(field_path->root)); - ret = -1; - goto end; - } - - if (ctx->sc->is_translated) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class is already translated: " - "root-scope=%s", - ctf_scope_string(field_path->root)); - ret = -1; - goto end; - } - - break; - case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: - case CTF_SCOPE_EVENT_PAYLOAD: - if (!ctx->ec) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current event class: " - "root-scope=%s", - ctf_scope_string(field_path->root)); - ret = -1; - goto end; - } - - if (ctx->ec->is_translated) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Event class is already translated: " - "root-scope=%s", - ctf_scope_string(field_path->root)); - ret = -1; - goto end; - } - - break; - - default: - bt_common_abort(); - } - - /* Skip absolute path tokens */ - cur_ptoken = g_list_nth(ptokens, absolute_path_prefix_ptoken_counts[field_path->root]); - - /* Start with root class */ - fc = borrow_class_from_ctx(ctx, field_path->root); - if (!fc) { - /* Error: root class is not available */ - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: " - "root-scope=%s", - ctf_scope_string(field_path->root)); - ret = -1; - goto end; - } - - /* Locate target */ - ret = ptokens_to_field_path(cur_ptoken, field_path, fc, INT64_MAX, ctx); - -end: - return ret; -} - -/* - * Converts a known relative path token list to a field path object - * within the resolving context `ctx`. - * - * `field_path` is an output parameter owned by the caller that must be - * filled here. - */ -static int relative_ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path, - struct resolve_context *ctx) -{ - int ret = 0; - int64_t parent_pos_in_stack; - struct ctf_field_path tail_field_path; - - ctf_field_path_init(&tail_field_path); - parent_pos_in_stack = field_class_stack_size(ctx->field_class_stack) - 1; - - while (parent_pos_in_stack >= 0) { - struct ctf_field_class *parent_class = - field_class_stack_at(ctx->field_class_stack, parent_pos_in_stack)->fc; - int64_t cur_index = - field_class_stack_at(ctx->field_class_stack, parent_pos_in_stack)->index; - - BT_COMP_LOGD("Locating target field class from current parent field class: " - "parent-pos=%" PRId64 ", parent-fc-addr=%p, " - "cur-index=%" PRId64, - parent_pos_in_stack, parent_class, cur_index); - - /* Locate target from current parent class */ - ret = ptokens_to_field_path(ptokens, &tail_field_path, parent_class, cur_index, ctx); - if (ret) { - /* Not found... yet */ - BT_COMP_LOGD_STR("Not found at this point."); - ctf_field_path_clear(&tail_field_path); - } else { - /* Found: stitch tail field path to head field path */ - uint64_t i = 0; - size_t tail_field_path_len = tail_field_path.path->len; - - while (BT_TRUE) { - struct ctf_field_class *cur_class = - field_class_stack_at(ctx->field_class_stack, i)->fc; - int64_t index = field_class_stack_at(ctx->field_class_stack, i)->index; - - if (cur_class == parent_class) { - break; - } - - ctf_field_path_append_index(field_path, index); - i++; - } - - for (i = 0; i < tail_field_path_len; i++) { - int64_t index = ctf_field_path_borrow_index_by_index(&tail_field_path, i); - - ctf_field_path_append_index(field_path, (int64_t) index); - } - break; - } - - parent_pos_in_stack--; - } - - if (parent_pos_in_stack < 0) { - /* Not found */ - ret = -1; - } - - ctf_field_path_fini(&tail_field_path); - return ret; -} - -/* - * Converts a path string to a field path object within the resolving - * context `ctx`. - */ -static int pathstr_to_field_path(const char *pathstr, struct ctf_field_path *field_path, - struct resolve_context *ctx) -{ - int ret = 0; - enum ctf_scope root_scope; - GList *ptokens = NULL; - - /* Convert path string to path tokens */ - ptokens = pathstr_to_ptokens(pathstr, ctx); - if (!ptokens) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot convert path string to path tokens: " - "path=\"%s\"", - pathstr); - ret = -1; - goto end; - } - - /* Absolute or relative path? */ - root_scope = get_root_scope_from_absolute_pathstr(pathstr, ctx); - - if (root_scope == CTF_SCOPE_PACKET_UNKNOWN) { - /* Relative path: start with current root scope */ - field_path->root = ctx->root_scope; - BT_COMP_LOGD("Detected relative path: starting with current root scope: " - "scope=%s", - ctf_scope_string(field_path->root)); - ret = relative_ptokens_to_field_path(ptokens, field_path, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot get relative field path of path string: " - "path=\"%s\", start-scope=%s, end-scope=%s", - pathstr, ctf_scope_string(ctx->root_scope), ctf_scope_string(field_path->root)); - goto end; - } - } else { - /* Absolute path: use found root scope */ - field_path->root = root_scope; - BT_COMP_LOGD("Detected absolute path: using root scope: " - "scope=%s", - ctf_scope_string(field_path->root)); - ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot get absolute field path of path string: " - "path=\"%s\", root-scope=%s", - pathstr, ctf_scope_string(root_scope)); - goto end; - } - } - - if (BT_LOG_ON_TRACE && ret == 0) { - GString *field_path_pretty = ctf_field_path_string(field_path); - const char *field_path_pretty_str = field_path_pretty ? field_path_pretty->str : "(null)"; - - BT_COMP_LOGD("Found field path: path=\"%s\", field-path=\"%s\"", pathstr, - field_path_pretty_str); - - if (field_path_pretty) { - g_string_free(field_path_pretty, TRUE); - } - } - -end: - ptokens_destroy(ptokens); - return ret; -} - -/* - * Retrieves a field class by following the field path `field_path` in - * the resolving context `ctx`. - */ -static struct ctf_field_class *field_path_to_field_class(struct ctf_field_path *field_path, - struct resolve_context *ctx) -{ - uint64_t i; - struct ctf_field_class *fc; - - /* Start with root class */ - fc = borrow_class_from_ctx(ctx, field_path->root); - if (!fc) { - /* Error: root class is not available */ - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: root-scope=%s", - ctf_scope_string(field_path->root)); - goto end; - } - - /* Locate target */ - for (i = 0; i < field_path->path->len; i++) { - struct ctf_field_class *child_fc; - int64_t child_index = ctf_field_path_borrow_index_by_index(field_path, i); - - /* Get child field class */ - child_fc = ctf_field_class_compound_borrow_field_class_by_index(fc, child_index); - BT_ASSERT(child_fc); - - /* Move child class to current class */ - fc = child_fc; - } - -end: - return fc; -} - -/* - * Fills the equivalent field path object of the context class stack. - */ -static void get_ctx_stack_field_path(struct resolve_context *ctx, struct ctf_field_path *field_path) -{ - uint64_t i; - - BT_ASSERT(field_path); - field_path->root = ctx->root_scope; - ctf_field_path_clear(field_path); - - for (i = 0; i < field_class_stack_size(ctx->field_class_stack); i++) { - struct field_class_stack_frame *frame = field_class_stack_at(ctx->field_class_stack, i); - - ctf_field_path_append_index(field_path, frame->index); - } -} - -/* - * Returns the index of the lowest common ancestor of two field path - * objects having the same root scope. - */ -static int64_t get_field_paths_lca_index(struct ctf_field_path *field_path1, - struct ctf_field_path *field_path2, - struct resolve_context *ctx) -{ - int64_t lca_index = 0; - uint64_t field_path1_len, field_path2_len; - - if (BT_LOG_ON_TRACE) { - GString *field_path1_pretty = ctf_field_path_string(field_path1); - GString *field_path2_pretty = ctf_field_path_string(field_path2); - const char *field_path1_pretty_str = - field_path1_pretty ? field_path1_pretty->str : "(null)"; - const char *field_path2_pretty_str = - field_path2_pretty ? field_path2_pretty->str : "(null)"; - - BT_COMP_LOGD("Finding lowest common ancestor (LCA) between two field paths: " - "field-path-1=\"%s\", field-path-2=\"%s\"", - field_path1_pretty_str, field_path2_pretty_str); - - if (field_path1_pretty) { - g_string_free(field_path1_pretty, TRUE); - } - - if (field_path2_pretty) { - g_string_free(field_path2_pretty, TRUE); - } - } - - /* - * Start from both roots and find the first mismatch. - */ - BT_ASSERT(field_path1->root == field_path2->root); - field_path1_len = field_path1->path->len; - field_path2_len = field_path2->path->len; - - while (true) { - int64_t target_index, ctx_index; - - if (lca_index == (int64_t) field_path2_len || lca_index == (int64_t) field_path1_len) { - /* - * This means that both field paths never split. - * This is invalid because the target cannot be - * an ancestor of the source. - */ - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Source field class is an ancestor of target field class or vice versa: " - "lca-index=%" PRId64 ", " - "field-path-1-len=%" PRIu64 ", " - "field-path-2-len=%" PRIu64, - lca_index, field_path1_len, field_path2_len); - lca_index = -1; - break; - } - - target_index = ctf_field_path_borrow_index_by_index(field_path1, lca_index); - ctx_index = ctf_field_path_borrow_index_by_index(field_path2, lca_index); - - if (target_index != ctx_index) { - /* LCA index is the previous */ - break; - } - - lca_index++; - } - - BT_COMP_LOGD("Found LCA: lca-index=%" PRId64, lca_index); - return lca_index; -} - -/* - * Validates a target field path. - */ -static int validate_target_field_path(struct ctf_field_path *target_field_path, - struct ctf_field_class *target_fc, - struct resolve_context *ctx) -{ - int ret = 0; - struct ctf_field_path ctx_field_path; - uint64_t target_field_path_len = target_field_path->path->len; - int64_t lca_index; - - /* Get context field path */ - ctf_field_path_init(&ctx_field_path); - get_ctx_stack_field_path(ctx, &ctx_field_path); - - /* - * Make sure the target is not a root. - */ - if (target_field_path_len == 0) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Target field path's length is 0 (targeting the root)."); - ret = -1; - goto end; - } - - /* - * Make sure the root of the target field path is not located - * after the context field path's root. - */ - if (target_field_path->root > ctx_field_path.root) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Target field class is located after source field class: " - "target-root=%s, source-root=%s", - ctf_scope_string(target_field_path->root), ctf_scope_string(ctx_field_path.root)); - ret = -1; - goto end; - } - - if (target_field_path->root == ctx_field_path.root) { - int64_t target_index, ctx_index; - - /* - * Find the index of the lowest common ancestor of both field - * paths. - */ - lca_index = get_field_paths_lca_index(target_field_path, &ctx_field_path, ctx); - if (lca_index < 0) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get least common ancestor."); - ret = -1; - goto end; - } - - /* - * Make sure the target field path is located before the - * context field path. - */ - target_index = - ctf_field_path_borrow_index_by_index(target_field_path, (uint64_t) lca_index); - ctx_index = ctf_field_path_borrow_index_by_index(&ctx_field_path, (uint64_t) lca_index); - - if (target_index >= ctx_index) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Target field class's index is greater than or equal to source field class's index in LCA: " - "lca-index=%" PRId64 ", " - "target-index=%" PRId64 ", " - "source-index=%" PRId64, - lca_index, target_index, ctx_index); - ret = -1; - goto end; - } - } - - /* - * Make sure the target class has the right class and properties. - */ - switch (ctx->cur_fc->type) { - case CTF_FIELD_CLASS_TYPE_VARIANT: - if (target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Variant field class's tag field class is not an enumeration field class: " - "tag-fc-addr=%p, tag-fc-id=%d", - target_fc, target_fc->type); - ret = -1; - goto end; - } - break; - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - if (target_fc->type != CTF_FIELD_CLASS_TYPE_INT && - target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Sequence field class's length field class is not an unsigned integer field class: " - "length-fc-addr=%p, length-fc-id=%d", - target_fc, target_fc->type); - ret = -1; - goto end; - } - - ctf_field_class_int *int_fc = ctf_field_class_as_int(target_fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Sequence field class's length field class is not an unsigned integer field class: " - "length-fc-addr=%p, length-fc-id=%d", - target_fc, target_fc->type); - ret = -1; - goto end; - } - break; - } - default: - bt_common_abort(); - } - -end: - ctf_field_path_fini(&ctx_field_path); - return ret; -} - -/* - * Resolves a variant or sequence field class `fc`. - */ -static int resolve_sequence_or_variant_field_class(struct ctf_field_class *fc, - struct resolve_context *ctx) -{ - int ret = 0; - const char *pathstr; - struct ctf_field_path target_field_path; - struct ctf_field_class *target_fc = NULL; - GString *target_field_path_pretty = NULL; - const char *target_field_path_pretty_str; - - ctf_field_path_init(&target_field_path); - - /* Get path string */ - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); - pathstr = seq_fc->length_ref->str; - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - pathstr = var_fc->tag_ref->str; - break; - } - default: - bt_common_abort(); - } - - if (!pathstr) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get path string."); - ret = -1; - goto end; - } - - /* Get target field path out of path string */ - ret = pathstr_to_field_path(pathstr, &target_field_path, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field path for path string: " - "path=\"%s\"", - pathstr); - goto end; - } - - target_field_path_pretty = ctf_field_path_string(&target_field_path); - target_field_path_pretty_str = target_field_path_pretty ? target_field_path_pretty->str : NULL; - - /* Get target field class */ - target_fc = field_path_to_field_class(&target_field_path, ctx); - if (!target_fc) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field class for path string: " - "path=\"%s\", target-field-path=\"%s\"", - pathstr, target_field_path_pretty_str); - ret = -1; - goto end; - } - - ret = validate_target_field_path(&target_field_path, target_fc, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid target field path for path string: " - "path=\"%s\", target-field-path=\"%s\"", - pathstr, target_field_path_pretty_str); - goto end; - } - - /* Set target field path and target field class */ - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); - - ctf_field_path_copy_content(&seq_fc->length_path, &target_field_path); - seq_fc->length_fc = ctf_field_class_as_int(target_fc); - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - ctf_field_path_copy_content(&var_fc->tag_path, &target_field_path); - ctf_field_class_variant_set_tag_field_class(var_fc, ctf_field_class_as_enum(target_fc)); - break; - } - default: - bt_common_abort(); - } - -end: - if (target_field_path_pretty) { - g_string_free(target_field_path_pretty, TRUE); - } - - ctf_field_path_fini(&target_field_path); - return ret; -} - -/* - * Resolves a field class `fc`. - */ -static int resolve_field_class(struct ctf_field_class *fc, struct resolve_context *ctx) -{ - int ret = 0; - - if (!fc) { - /* Field class is not available; still valid */ - goto end; - } - - ctx->cur_fc = fc; - - /* Resolve sequence/variant field class */ - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - case CTF_FIELD_CLASS_TYPE_VARIANT: - ret = resolve_sequence_or_variant_field_class(fc, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot resolve sequence field class's length or variant field class's tag: " - "ret=%d, fc-addr=%p", - ret, fc); - goto end; - } - - break; - default: - break; - } - - /* Recurse into compound classes */ - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - case CTF_FIELD_CLASS_TYPE_VARIANT: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - case CTF_FIELD_CLASS_TYPE_ARRAY: - { - uint64_t i; - uint64_t field_count = ctf_field_class_compound_get_field_class_count(fc); - - ret = field_class_stack_push(ctx->field_class_stack, fc, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot push field class on context's stack: " - "fc-addr=%p", - fc); - goto end; - } - - for (i = 0; i < field_count; i++) { - struct ctf_field_class *child_fc = - ctf_field_class_compound_borrow_field_class_by_index(fc, i); - - BT_ASSERT(child_fc); - - if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || - fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { - field_class_stack_peek(ctx->field_class_stack)->index = -1; - } else { - field_class_stack_peek(ctx->field_class_stack)->index = (int64_t) i; - } - - BT_COMP_LOGD("Resolving field class's child field class: " - "parent-fc-addr=%p, child-fc-addr=%p, " - "index=%" PRIu64 ", count=%" PRIu64, - fc, child_fc, i, field_count); - ret = resolve_field_class(child_fc, ctx); - if (ret) { - goto end; - } - } - - field_class_stack_pop(ctx->field_class_stack, ctx); - break; - } - default: - break; - } - -end: - return ret; -} - -/* - * Resolves the root field class corresponding to the scope `root_scope`. - */ -static int resolve_root_class(enum ctf_scope root_scope, struct resolve_context *ctx) -{ - int ret; - - BT_ASSERT(field_class_stack_size(ctx->field_class_stack) == 0); - ctx->root_scope = root_scope; - ret = resolve_field_class(borrow_class_from_ctx(ctx, root_scope), ctx); - ctx->root_scope = CTF_SCOPE_PACKET_UNKNOWN; - return ret; -} - -static int resolve_event_class_field_classes(struct resolve_context *ctx, - struct ctf_event_class *ec) -{ - int ret = 0; - - BT_ASSERT(!ctx->scopes.event_spec_context); - BT_ASSERT(!ctx->scopes.event_payload); - - if (ec->is_translated) { - goto end; - } - - ctx->ec = ec; - ctx->scopes.event_spec_context = ec->spec_context_fc; - ret = resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot resolve event specific context field class: " - "ret=%d", - ret); - goto end; - } - - ctx->scopes.event_payload = ec->payload_fc; - ret = resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event payload field class: " - "ret=%d", - ret); - goto end; - } - -end: - ctx->scopes.event_spec_context = NULL; - ctx->scopes.event_payload = NULL; - ctx->ec = NULL; - return ret; -} - -static int resolve_stream_class_field_classes(struct resolve_context *ctx, - struct ctf_stream_class *sc) -{ - int ret = 0; - uint64_t i; - - BT_ASSERT(!ctx->scopes.packet_context); - BT_ASSERT(!ctx->scopes.event_header); - BT_ASSERT(!ctx->scopes.event_common_context); - ctx->sc = sc; - - if (!sc->is_translated) { - ctx->scopes.packet_context = sc->packet_context_fc; - ret = resolve_root_class(CTF_SCOPE_PACKET_CONTEXT, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet context field class: " - "ret=%d", - ret); - goto end; - } - - ctx->scopes.event_header = sc->event_header_fc; - ret = resolve_root_class(CTF_SCOPE_EVENT_HEADER, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event header field class: " - "ret=%d", - ret); - goto end; - } - - ctx->scopes.event_common_context = sc->event_common_context_fc; - ret = resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot resolve event common context field class: " - "ret=%d", - ret); - goto end; - } - } - - ctx->scopes.packet_context = sc->packet_context_fc; - ctx->scopes.event_header = sc->event_header_fc; - ctx->scopes.event_common_context = sc->event_common_context_fc; - - for (i = 0; i < sc->event_classes->len; i++) { - ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[i]; - - ret = resolve_event_class_field_classes(ctx, ec); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event class's field classes: " - "ec-id=%" PRIu64 ", ec-name=\"%s\"", - ec->id, ec->name->str); - goto end; - } - } - -end: - ctx->scopes.packet_context = NULL; - ctx->scopes.event_header = NULL; - ctx->scopes.event_common_context = NULL; - ctx->sc = NULL; - return ret; -} - -int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc, - struct meta_log_config *log_cfg) -{ - int ret = 0; - uint64_t i; - - resolve_context local_ctx {}; - local_ctx.log_level = log_cfg->log_level; - local_ctx.self_comp = log_cfg->self_comp; - local_ctx.self_comp_class = log_cfg->self_comp_class; - local_ctx.tc = tc; - local_ctx.scopes.packet_header = tc->packet_header_fc; - local_ctx.root_scope = CTF_SCOPE_PACKET_HEADER; - - struct resolve_context *ctx = &local_ctx; - - /* Initialize class stack */ - ctx->field_class_stack = field_class_stack_create(); - if (!ctx->field_class_stack) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create field class stack."); - ret = -1; - goto end; - } - - if (!tc->is_translated) { - ctx->scopes.packet_header = tc->packet_header_fc; - ret = resolve_root_class(CTF_SCOPE_PACKET_HEADER, ctx); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet header field class: " - "ret=%d", - ret); - goto end; - } - } - - ctx->scopes.packet_header = tc->packet_header_fc; - - for (i = 0; i < tc->stream_classes->len; i++) { - ctf_stream_class *sc = (ctf_stream_class *) tc->stream_classes->pdata[i]; - - ret = resolve_stream_class_field_classes(ctx, sc); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve stream class's field classes: " - "sc-id=%" PRIu64, - sc->id); - goto end; - } - } - -end: - field_class_stack_destroy(ctx->field_class_stack); - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-translate.cpp b/src/plugins/ctf/common/metadata/ctf-meta-translate.cpp deleted file mode 100644 index e3ecfd07..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-translate.cpp +++ /dev/null @@ -1,651 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#include - -#include "common/assert.h" - -#include "ctf-meta-visitors.hpp" - -struct ctx -{ - bt_self_component *self_comp; - bt_trace_class *ir_tc; - bt_stream_class *ir_sc; - struct ctf_trace_class *tc; - struct ctf_stream_class *sc; - struct ctf_event_class *ec; - enum ctf_scope scope; -}; - -static inline bt_field_class *ctf_field_class_to_ir(struct ctx *ctx, struct ctf_field_class *fc); - -static inline void ctf_field_class_int_set_props(struct ctf_field_class_int *fc, - bt_field_class *ir_fc) -{ - bt_field_class_integer_set_field_value_range(ir_fc, fc->base.size); - bt_field_class_integer_set_preferred_display_base(ir_fc, fc->disp_base); -} - -static inline bt_field_class *ctf_field_class_int_to_ir(struct ctx *ctx, - struct ctf_field_class_int *fc) -{ - bt_field_class *ir_fc; - - if (fc->is_signed) { - ir_fc = bt_field_class_integer_signed_create(ctx->ir_tc); - } else { - ir_fc = bt_field_class_integer_unsigned_create(ctx->ir_tc); - } - - BT_ASSERT(ir_fc); - ctf_field_class_int_set_props(fc, ir_fc); - return ir_fc; -} - -static inline bt_field_class *ctf_field_class_enum_to_ir(struct ctx *ctx, - struct ctf_field_class_enum *fc) -{ - int ret; - bt_field_class *ir_fc; - uint64_t i; - - if (fc->base.is_signed) { - ir_fc = bt_field_class_enumeration_signed_create(ctx->ir_tc); - } else { - ir_fc = bt_field_class_enumeration_unsigned_create(ctx->ir_tc); - } - - BT_ASSERT(ir_fc); - ctf_field_class_int_set_props(&fc->base, ir_fc); - - for (i = 0; i < fc->mappings->len; i++) { - struct ctf_field_class_enum_mapping *mapping = - ctf_field_class_enum_borrow_mapping_by_index(fc, i); - bt_integer_range_set_signed *range_set_signed = NULL; - bt_integer_range_set_unsigned *range_set_unsigned = NULL; - uint64_t range_i; - - if (fc->base.is_signed) { - range_set_signed = bt_integer_range_set_signed_create(); - BT_ASSERT(range_set_signed); - } else { - range_set_unsigned = bt_integer_range_set_unsigned_create(); - BT_ASSERT(range_set_unsigned); - } - - for (range_i = 0; range_i < mapping->ranges->len; range_i++) { - struct ctf_range *range = - ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i); - - if (fc->base.is_signed) { - ret = bt_integer_range_set_signed_add_range(range_set_signed, range->lower.i, - range->upper.i); - } else { - ret = bt_integer_range_set_unsigned_add_range(range_set_unsigned, range->lower.u, - range->upper.u); - } - - BT_ASSERT(ret == 0); - } - - if (fc->base.is_signed) { - ret = bt_field_class_enumeration_signed_add_mapping(ir_fc, mapping->label->str, - range_set_signed); - BT_INTEGER_RANGE_SET_SIGNED_PUT_REF_AND_RESET(range_set_signed); - } else { - ret = bt_field_class_enumeration_unsigned_add_mapping(ir_fc, mapping->label->str, - range_set_unsigned); - BT_INTEGER_RANGE_SET_UNSIGNED_PUT_REF_AND_RESET(range_set_unsigned); - } - - BT_ASSERT(ret == 0); - } - - return ir_fc; -} - -static inline bt_field_class *ctf_field_class_float_to_ir(struct ctx *ctx, - struct ctf_field_class_float *fc) -{ - bt_field_class *ir_fc; - - if (fc->base.size == 32) { - ir_fc = bt_field_class_real_single_precision_create(ctx->ir_tc); - } else { - ir_fc = bt_field_class_real_double_precision_create(ctx->ir_tc); - } - BT_ASSERT(ir_fc); - - return ir_fc; -} - -static inline bt_field_class *ctf_field_class_string_to_ir(struct ctx *ctx, - struct ctf_field_class_string *) -{ - bt_field_class *ir_fc = bt_field_class_string_create(ctx->ir_tc); - - BT_ASSERT(ir_fc); - return ir_fc; -} - -static inline void translate_struct_field_class_members(struct ctx *ctx, - struct ctf_field_class_struct *fc, - bt_field_class *ir_fc, bool, - struct ctf_field_class_struct *) -{ - uint64_t i; - int ret; - - for (i = 0; i < fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(fc, i); - bt_field_class *member_ir_fc; - const char *name = named_fc->name->str; - - if (!named_fc->fc->in_ir) { - continue; - } - - member_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc); - BT_ASSERT(member_ir_fc); - ret = bt_field_class_structure_append_member(ir_fc, name, member_ir_fc); - BT_ASSERT(ret == 0); - bt_field_class_put_ref(member_ir_fc); - } -} - -static inline bt_field_class *ctf_field_class_struct_to_ir(struct ctx *ctx, - struct ctf_field_class_struct *fc) -{ - bt_field_class *ir_fc = bt_field_class_structure_create(ctx->ir_tc); - - BT_ASSERT(ir_fc); - translate_struct_field_class_members(ctx, fc, ir_fc, false, NULL); - return ir_fc; -} - -static inline bt_field_class *borrow_ir_fc_from_field_path(struct ctx *ctx, - struct ctf_field_path *field_path) -{ - bt_field_class *ir_fc = NULL; - struct ctf_field_class *fc = - ctf_field_path_borrow_field_class(field_path, ctx->tc, ctx->sc, ctx->ec); - - BT_ASSERT(fc); - - if (fc->in_ir) { - ir_fc = fc->ir_fc; - } - - return ir_fc; -} - -static inline const bt_field_class_enumeration_mapping * -find_ir_enum_field_class_mapping_by_label(const bt_field_class *fc, const char *label, - bool is_signed) -{ - const bt_field_class_enumeration_mapping *mapping = NULL; - uint64_t i; - - for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) { - const bt_field_class_enumeration_mapping *this_mapping; - const bt_field_class_enumeration_signed_mapping *signed_this_mapping = NULL; - const bt_field_class_enumeration_unsigned_mapping *unsigned_this_mapping = NULL; - - if (is_signed) { - signed_this_mapping = - bt_field_class_enumeration_signed_borrow_mapping_by_index_const(fc, i); - BT_ASSERT(signed_this_mapping); - this_mapping = - bt_field_class_enumeration_signed_mapping_as_mapping_const(signed_this_mapping); - } else { - unsigned_this_mapping = - bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(fc, i); - BT_ASSERT(unsigned_this_mapping); - this_mapping = - bt_field_class_enumeration_unsigned_mapping_as_mapping_const(unsigned_this_mapping); - } - - BT_ASSERT(this_mapping); - - if (strcmp(bt_field_class_enumeration_mapping_get_label(this_mapping), label) == 0) { - mapping = this_mapping; - goto end; - } - } - -end: - return mapping; -} - -static inline bt_field_class *ctf_field_class_variant_to_ir(struct ctx *ctx, - struct ctf_field_class_variant *fc) -{ - int ret; - bt_field_class *ir_fc; - uint64_t i; - bt_field_class *ir_tag_fc = NULL; - - if (fc->tag_path.root != CTF_SCOPE_PACKET_HEADER && - fc->tag_path.root != CTF_SCOPE_EVENT_HEADER) { - ir_tag_fc = borrow_ir_fc_from_field_path(ctx, &fc->tag_path); - BT_ASSERT(ir_tag_fc); - } - - ir_fc = bt_field_class_variant_create(ctx->ir_tc, ir_tag_fc); - BT_ASSERT(ir_fc); - - for (i = 0; i < fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(fc, i); - bt_field_class *option_ir_fc; - - BT_ASSERT(named_fc->fc->in_ir); - option_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc); - BT_ASSERT(option_ir_fc); - - if (ir_tag_fc) { - /* - * At this point the trace IR selector - * (enumeration) field class already exists if - * the variant is tagged (`ir_tag_fc`). This one - * already contains range sets for its mappings, - * so we just reuse the same, finding them by - * matching a variant field class's option's - * _original_ name (with a leading underscore, - * possibly) with a selector field class's - * mapping name. - */ - if (fc->tag_fc->base.is_signed) { - const bt_field_class_enumeration_signed_mapping *mapping = - (bt_field_class_enumeration_signed_mapping *) - find_ir_enum_field_class_mapping_by_label(ir_tag_fc, - named_fc->orig_name->str, true); - const bt_integer_range_set_signed *range_set; - - BT_ASSERT(mapping); - range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(mapping); - BT_ASSERT(range_set); - ret = bt_field_class_variant_with_selector_field_integer_signed_append_option( - ir_fc, named_fc->name->str, option_ir_fc, range_set); - } else { - const bt_field_class_enumeration_unsigned_mapping *mapping = - (bt_field_class_enumeration_unsigned_mapping *) - find_ir_enum_field_class_mapping_by_label(ir_tag_fc, - named_fc->orig_name->str, false); - const bt_integer_range_set_unsigned *range_set; - - BT_ASSERT(mapping); - range_set = - bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(mapping); - BT_ASSERT(range_set); - ret = bt_field_class_variant_with_selector_field_integer_unsigned_append_option( - ir_fc, named_fc->name->str, option_ir_fc, range_set); - } - } else { - ret = bt_field_class_variant_without_selector_append_option(ir_fc, named_fc->name->str, - option_ir_fc); - } - - BT_ASSERT(ret == 0); - bt_field_class_put_ref(option_ir_fc); - } - - return ir_fc; -} - -static inline bt_field_class *ctf_field_class_array_to_ir(struct ctx *ctx, - struct ctf_field_class_array *fc) -{ - bt_field_class *ir_fc; - bt_field_class *elem_ir_fc; - - if (fc->base.is_text) { - ir_fc = bt_field_class_string_create(ctx->ir_tc); - BT_ASSERT(ir_fc); - goto end; - } - - elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc); - BT_ASSERT(elem_ir_fc); - ir_fc = bt_field_class_array_static_create(ctx->ir_tc, elem_ir_fc, fc->length); - BT_ASSERT(ir_fc); - bt_field_class_put_ref(elem_ir_fc); - -end: - return ir_fc; -} - -static inline bt_field_class *ctf_field_class_sequence_to_ir(struct ctx *ctx, - struct ctf_field_class_sequence *fc) -{ - bt_field_class *ir_fc; - bt_field_class *elem_ir_fc; - bt_field_class *length_fc = NULL; - - if (fc->base.is_text) { - ir_fc = bt_field_class_string_create(ctx->ir_tc); - BT_ASSERT(ir_fc); - goto end; - } - - elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc); - BT_ASSERT(elem_ir_fc); - - if (fc->length_path.root != CTF_SCOPE_PACKET_HEADER && - fc->length_path.root != CTF_SCOPE_EVENT_HEADER) { - length_fc = borrow_ir_fc_from_field_path(ctx, &fc->length_path); - BT_ASSERT(length_fc); - } - - ir_fc = bt_field_class_array_dynamic_create(ctx->ir_tc, elem_ir_fc, length_fc); - BT_ASSERT(ir_fc); - bt_field_class_put_ref(elem_ir_fc); - BT_ASSERT(ir_fc); - -end: - return ir_fc; -} - -static inline bt_field_class *ctf_field_class_to_ir(struct ctx *ctx, struct ctf_field_class *fc) -{ - bt_field_class *ir_fc = NULL; - - BT_ASSERT(fc); - BT_ASSERT(fc->in_ir); - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_INT: - ir_fc = ctf_field_class_int_to_ir(ctx, ctf_field_class_as_int(fc)); - break; - case CTF_FIELD_CLASS_TYPE_ENUM: - ir_fc = ctf_field_class_enum_to_ir(ctx, ctf_field_class_as_enum(fc)); - break; - case CTF_FIELD_CLASS_TYPE_FLOAT: - ir_fc = ctf_field_class_float_to_ir(ctx, ctf_field_class_as_float(fc)); - break; - case CTF_FIELD_CLASS_TYPE_STRING: - ir_fc = ctf_field_class_string_to_ir(ctx, ctf_field_class_as_string(fc)); - break; - case CTF_FIELD_CLASS_TYPE_STRUCT: - ir_fc = ctf_field_class_struct_to_ir(ctx, ctf_field_class_as_struct(fc)); - break; - case CTF_FIELD_CLASS_TYPE_ARRAY: - ir_fc = ctf_field_class_array_to_ir(ctx, ctf_field_class_as_array(fc)); - break; - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - ir_fc = ctf_field_class_sequence_to_ir(ctx, ctf_field_class_as_sequence(fc)); - break; - case CTF_FIELD_CLASS_TYPE_VARIANT: - ir_fc = ctf_field_class_variant_to_ir(ctx, ctf_field_class_as_variant(fc)); - break; - default: - bt_common_abort(); - } - - fc->ir_fc = ir_fc; - return ir_fc; -} - -static inline bool -ctf_field_class_struct_has_immediate_member_in_ir(struct ctf_field_class_struct *fc) -{ - uint64_t i; - bool has_immediate_member_in_ir = false; - - /* - * If the structure field class has no members at all, then it - * was an empty structure in the beginning, so leave it existing - * and empty. - */ - if (fc->members->len == 0) { - has_immediate_member_in_ir = true; - goto end; - } - - for (i = 0; i < fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(fc, i); - - if (named_fc->fc->in_ir) { - has_immediate_member_in_ir = true; - goto end; - } - } - -end: - return has_immediate_member_in_ir; -} - -static inline bt_field_class *scope_ctf_field_class_to_ir(struct ctx *ctx) -{ - bt_field_class *ir_fc = NULL; - struct ctf_field_class *fc = NULL; - - switch (ctx->scope) { - case CTF_SCOPE_PACKET_CONTEXT: - fc = ctx->sc->packet_context_fc; - break; - case CTF_SCOPE_EVENT_COMMON_CONTEXT: - fc = ctx->sc->event_common_context_fc; - break; - case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: - fc = ctx->ec->spec_context_fc; - break; - case CTF_SCOPE_EVENT_PAYLOAD: - fc = ctx->ec->payload_fc; - break; - default: - bt_common_abort(); - } - - if (fc && ctf_field_class_struct_has_immediate_member_in_ir(ctf_field_class_as_struct(fc))) { - ir_fc = ctf_field_class_to_ir(ctx, fc); - } - - return ir_fc; -} - -static inline void ctf_event_class_to_ir(struct ctx *ctx) -{ - int ret; - bt_event_class *ir_ec = NULL; - bt_field_class *ir_fc; - - BT_ASSERT(ctx->ec); - - if (ctx->ec->is_translated) { - ir_ec = bt_stream_class_borrow_event_class_by_id(ctx->ir_sc, ctx->ec->id); - BT_ASSERT(ir_ec); - goto end; - } - - ir_ec = bt_event_class_create_with_id(ctx->ir_sc, ctx->ec->id); - BT_ASSERT(ir_ec); - bt_event_class_put_ref(ir_ec); - ctx->scope = CTF_SCOPE_EVENT_SPECIFIC_CONTEXT; - ir_fc = scope_ctf_field_class_to_ir(ctx); - if (ir_fc) { - ret = bt_event_class_set_specific_context_field_class(ir_ec, ir_fc); - BT_ASSERT(ret == 0); - bt_field_class_put_ref(ir_fc); - } - - ctx->scope = CTF_SCOPE_EVENT_PAYLOAD; - ir_fc = scope_ctf_field_class_to_ir(ctx); - if (ir_fc) { - ret = bt_event_class_set_payload_field_class(ir_ec, ir_fc); - BT_ASSERT(ret == 0); - bt_field_class_put_ref(ir_fc); - } - - if (ctx->ec->name->len > 0) { - ret = bt_event_class_set_name(ir_ec, ctx->ec->name->str); - BT_ASSERT(ret == 0); - } - - if (ctx->ec->emf_uri->len > 0) { - ret = bt_event_class_set_emf_uri(ir_ec, ctx->ec->emf_uri->str); - BT_ASSERT(ret == 0); - } - - if (ctx->ec->is_log_level_set) { - bt_event_class_set_log_level(ir_ec, ctx->ec->log_level); - } - - ctx->ec->is_translated = true; - ctx->ec->ir_ec = ir_ec; - -end: - return; -} - -static inline void ctf_stream_class_to_ir(struct ctx *ctx) -{ - int ret; - bt_field_class *ir_fc; - - BT_ASSERT(ctx->sc); - - if (ctx->sc->is_translated) { - ctx->ir_sc = bt_trace_class_borrow_stream_class_by_id(ctx->ir_tc, ctx->sc->id); - BT_ASSERT(ctx->ir_sc); - goto end; - } - - ctx->ir_sc = bt_stream_class_create_with_id(ctx->ir_tc, ctx->sc->id); - BT_ASSERT(ctx->ir_sc); - bt_stream_class_put_ref(ctx->ir_sc); - - if (ctx->sc->default_clock_class) { - BT_ASSERT(ctx->sc->default_clock_class->ir_cc); - ret = bt_stream_class_set_default_clock_class(ctx->ir_sc, - ctx->sc->default_clock_class->ir_cc); - BT_ASSERT(ret == 0); - } - - bt_stream_class_set_supports_packets(ctx->ir_sc, BT_TRUE, ctx->sc->packets_have_ts_begin, - ctx->sc->packets_have_ts_end); - bt_stream_class_set_supports_discarded_events(ctx->ir_sc, ctx->sc->has_discarded_events, - ctx->sc->discarded_events_have_default_cs); - bt_stream_class_set_supports_discarded_packets(ctx->ir_sc, ctx->sc->has_discarded_packets, - ctx->sc->discarded_packets_have_default_cs); - ctx->scope = CTF_SCOPE_PACKET_CONTEXT; - ir_fc = scope_ctf_field_class_to_ir(ctx); - if (ir_fc) { - ret = bt_stream_class_set_packet_context_field_class(ctx->ir_sc, ir_fc); - BT_ASSERT(ret == 0); - bt_field_class_put_ref(ir_fc); - } - - ctx->scope = CTF_SCOPE_EVENT_COMMON_CONTEXT; - ir_fc = scope_ctf_field_class_to_ir(ctx); - if (ir_fc) { - ret = bt_stream_class_set_event_common_context_field_class(ctx->ir_sc, ir_fc); - BT_ASSERT(ret == 0); - bt_field_class_put_ref(ir_fc); - } - - bt_stream_class_set_assigns_automatic_event_class_id(ctx->ir_sc, BT_FALSE); - bt_stream_class_set_assigns_automatic_stream_id(ctx->ir_sc, BT_FALSE); - - ctx->sc->is_translated = true; - ctx->sc->ir_sc = ctx->ir_sc; - -end: - return; -} - -static inline void ctf_clock_class_to_ir(bt_clock_class *ir_cc, struct ctf_clock_class *cc) -{ - int ret; - - if (strlen(cc->name->str) > 0) { - ret = bt_clock_class_set_name(ir_cc, cc->name->str); - BT_ASSERT(ret == 0); - } - - if (strlen(cc->description->str) > 0) { - ret = bt_clock_class_set_description(ir_cc, cc->description->str); - BT_ASSERT(ret == 0); - } - - bt_clock_class_set_frequency(ir_cc, cc->frequency); - bt_clock_class_set_precision(ir_cc, cc->precision); - bt_clock_class_set_offset(ir_cc, cc->offset_seconds, cc->offset_cycles); - - if (cc->has_uuid) { - bt_clock_class_set_uuid(ir_cc, cc->uuid); - } - - bt_clock_class_set_origin_is_unix_epoch(ir_cc, cc->is_absolute); -} - -static inline int ctf_trace_class_to_ir(struct ctx *ctx) -{ - int ret = 0; - uint64_t i; - - BT_ASSERT(ctx->tc); - BT_ASSERT(ctx->ir_tc); - - if (ctx->tc->is_translated) { - goto end; - } - - for (i = 0; i < ctx->tc->clock_classes->len; i++) { - ctf_clock_class *cc = (ctf_clock_class *) ctx->tc->clock_classes->pdata[i]; - - cc->ir_cc = bt_clock_class_create(ctx->self_comp); - ctf_clock_class_to_ir(cc->ir_cc, cc); - } - - bt_trace_class_set_assigns_automatic_stream_class_id(ctx->ir_tc, BT_FALSE); - ctx->tc->is_translated = true; - ctx->tc->ir_tc = ctx->ir_tc; - -end: - return ret; -} - -int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc, - struct ctf_trace_class *tc) -{ - int ret = 0; - uint64_t i; - struct ctx ctx = {}; - - ctx.self_comp = self_comp; - ctx.tc = tc; - ctx.ir_tc = ir_tc; - ret = ctf_trace_class_to_ir(&ctx); - if (ret) { - goto end; - } - - for (i = 0; i < tc->stream_classes->len; i++) { - uint64_t j; - ctx.sc = (ctf_stream_class *) tc->stream_classes->pdata[i]; - - ctf_stream_class_to_ir(&ctx); - - for (j = 0; j < ctx.sc->event_classes->len; j++) { - ctx.ec = (ctf_event_class *) ctx.sc->event_classes->pdata[j]; - - ctf_event_class_to_ir(&ctx); - ctx.ec = NULL; - } - - ctx.sc = NULL; - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp deleted file mode 100644 index bea62bf9..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2020 Philippe Proulx - */ - -#include - -#include "ctf-meta-visitors.hpp" - -static inline int set_alignments(struct ctf_field_class *fc) -{ - int ret = 0; - uint64_t i; - - if (!fc) { - goto end; - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - ret = set_alignments(named_fc->fc); - if (ret) { - goto end; - } - - if (named_fc->fc->alignment > fc->alignment) { - fc->alignment = named_fc->fc->alignment; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - for (i = 0; i < var_fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - ret = set_alignments(named_fc->fc); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - ret = set_alignments(array_fc->elem_fc); - if (ret) { - goto end; - } - - /* - * Use the alignment of the array/sequence field class's - * element FC as its own alignment. - * - * This is especially important when the array/sequence - * field's effective length is zero: as per CTF 1.8, the - * stream data decoding process still needs to align the - * cursor using the element's alignment [1]: - * - * > Arrays are always aligned on their element - * > alignment requirement. - * - * For example: - * - * struct { - * integer { size = 8; } a; - * integer { size = 8; align = 16; } b[0]; - * integer { size = 8; } c; - * }; - * - * When using this to decode the bytes 1, 2, and 3, then - * the decoded values are: - * - * `a`: 1 - * `b`: [] - * `c`: 3 - * - * [1]: https://diamon.org/ctf/#spec4.2.3 - */ - array_fc->base.alignment = array_fc->elem_fc->alignment; - break; - } - default: - break; - } - -end: - return ret; -} - -int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc) -{ - int ret = 0; - uint64_t i; - - if (!ctf_tc->is_translated) { - ret = set_alignments(ctf_tc->packet_header_fc); - if (ret) { - goto end; - } - } - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - uint64_t j; - - if (!sc->is_translated) { - ret = set_alignments(sc->packet_context_fc); - if (ret) { - goto end; - } - - ret = set_alignments(sc->event_header_fc); - if (ret) { - goto end; - } - - ret = set_alignments(sc->event_common_context_fc); - if (ret) { - goto end; - } - } - - for (j = 0; j < sc->event_classes->len; j++) { - struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; - - if (ec->is_translated) { - continue; - } - - ret = set_alignments(ec->spec_context_fc); - if (ret) { - goto end; - } - - ret = set_alignments(ec->payload_fc); - if (ret) { - goto end; - } - } - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp deleted file mode 100644 index ab10dd4f..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) -#define BT_COMP_LOG_SELF_COMP_CLASS (log_cfg->self_comp_class) -#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/UPDATE-DEF-CC" -#include "logging.hpp" - -#include "ctf-meta-visitors.hpp" - -static inline int find_mapped_clock_class(struct ctf_field_class *fc, - struct ctf_clock_class **clock_class, - struct meta_log_config *log_cfg) -{ - int ret = 0; - uint64_t i; - - if (!fc) { - goto end; - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_INT: - case CTF_FIELD_CLASS_TYPE_ENUM: - { - struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - - if (int_fc->mapped_clock_class) { - if (*clock_class && *clock_class != int_fc->mapped_clock_class) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class contains more than one " - "clock class: expected-cc-name=\"%s\", " - "other-cc-name=\"%s\"", - (*clock_class)->name->str, - int_fc->mapped_clock_class->name->str); - ret = -1; - goto end; - } - - *clock_class = int_fc->mapped_clock_class; - } - - break; - } - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - ret = find_mapped_clock_class(named_fc->fc, clock_class, log_cfg); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - for (i = 0; i < var_fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - ret = find_mapped_clock_class(named_fc->fc, clock_class, log_cfg); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - ret = find_mapped_clock_class(array_fc->elem_fc, clock_class, log_cfg); - if (ret) { - goto end; - } - - break; - } - default: - break; - } - -end: - return ret; -} - -static inline int update_stream_class_default_clock_class(struct ctf_stream_class *stream_class, - struct meta_log_config *log_cfg) -{ - int ret = 0; - struct ctf_clock_class *clock_class = stream_class->default_clock_class; - uint64_t i; - - ret = find_mapped_clock_class(stream_class->packet_context_fc, &clock_class, log_cfg); - if (ret) { - goto end; - } - - ret = find_mapped_clock_class(stream_class->event_header_fc, &clock_class, log_cfg); - if (ret) { - goto end; - } - - ret = find_mapped_clock_class(stream_class->event_common_context_fc, &clock_class, log_cfg); - if (ret) { - goto end; - } - - for (i = 0; i < stream_class->event_classes->len; i++) { - struct ctf_event_class *event_class = - (ctf_event_class *) stream_class->event_classes->pdata[i]; - - ret = find_mapped_clock_class(event_class->spec_context_fc, &clock_class, log_cfg); - if (ret) { - goto end; - } - - ret = find_mapped_clock_class(event_class->payload_fc, &clock_class, log_cfg); - if (ret) { - goto end; - } - } - - if (!stream_class->default_clock_class) { - stream_class->default_clock_class = clock_class; - } - -end: - return ret; -} - -int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc, - struct meta_log_config *log_cfg) -{ - uint64_t i; - int ret = 0; - struct ctf_clock_class *clock_class = NULL; - - ret = find_mapped_clock_class(ctf_tc->packet_header_fc, &clock_class, log_cfg); - if (ret) { - goto end; - } - - if (clock_class) { - ret = -1; - goto end; - } - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - struct ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - - ret = update_stream_class_default_clock_class( - (ctf_stream_class *) ctf_tc->stream_classes->pdata[i], log_cfg); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class contains more than one " - "clock class: stream-class-id=%" PRIu64, - sc->id); - goto end; - } - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp deleted file mode 100644 index c7902383..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include -#include - -#include "common/assert.h" -#include "compat/glib.h" - -#include "ctf-meta-visitors.hpp" - -static void force_update_field_class_in_ir(struct ctf_field_class *fc, bool in_ir) -{ - uint64_t i; - - if (!fc) { - goto end; - } - - fc->in_ir = in_ir; - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - force_update_field_class_in_ir(named_fc->fc, in_ir); - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_named_field_class *named_fc; - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - for (i = 0; i < var_fc->options->len; i++) { - named_fc = ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - force_update_field_class_in_ir(named_fc->fc, in_ir); - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - force_update_field_class_in_ir(array_fc->elem_fc, in_ir); - break; - } - default: - break; - } - -end: - return; -} - -static void update_field_class_in_ir(struct ctf_field_class *fc, GHashTable *ft_dependents) -{ - int64_t i; - - if (!fc) { - goto end; - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_INT: - case CTF_FIELD_CLASS_TYPE_ENUM: - { - struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - - /* - * Conditions to be in trace IR; one of: - * - * 1. Does NOT have a mapped clock class AND does not - * have a special meaning. - * 2. Another field class depends on it. - */ - if ((!int_fc->mapped_clock_class && int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE) || - bt_g_hash_table_contains(ft_dependents, fc)) { - fc->in_ir = true; - } - - break; - } - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - /* - * Make it part of IR if it's empty because it was - * originally empty. - */ - if (struct_fc->members->len == 0) { - fc->in_ir = true; - } - - /* Reverse order */ - for (i = (int64_t) struct_fc->members->len - 1; i >= 0; i--) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - update_field_class_in_ir(named_fc->fc, ft_dependents); - - if (named_fc->fc->in_ir) { - /* At least one member is part of IR */ - fc->in_ir = true; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_named_field_class *named_fc; - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - /* - * Reverse order, although it is not important for this - * loop because a field class within a variant field - * type's option cannot depend on a field class in - * another option of the same variant field class. - */ - for (i = (int64_t) var_fc->options->len - 1; i >= 0; i--) { - named_fc = ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - update_field_class_in_ir(named_fc->fc, ft_dependents); - - if (named_fc->fc->in_ir) { - /* At least one option is part of IR */ - fc->in_ir = true; - } - } - - if (fc->in_ir) { - /* - * At least one option will make it to IR. In - * this case, make all options part of IR - * because the variant's tag could still select - * (dynamically) a removed option. This can mean - * having an empty structure as an option, for - * example, but at least all the options are - * selectable. - */ - for (i = 0; i < var_fc->options->len; i++) { - ctf_field_class_variant_borrow_option_by_index(var_fc, i)->fc->in_ir = true; - } - - /* - * This variant field class is part of IR and - * depends on a tag field class (which must also - * be part of IR). - */ - g_hash_table_insert(ft_dependents, var_fc->tag_fc, var_fc->tag_fc); - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - update_field_class_in_ir(array_fc->elem_fc, ft_dependents); - fc->in_ir = array_fc->elem_fc->in_ir; - - if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) { - struct ctf_field_class_array *arr_fc = ctf_field_class_as_array(fc); - - assert(arr_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE || - arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID); - - /* - * UUID field class: nothing depends on this, so - * it's not part of IR. - */ - if (arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID) { - fc->in_ir = false; - array_fc->elem_fc->in_ir = false; - } - } else if (fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { - if (fc->in_ir) { - struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); - - /* - * This sequence field class is part of - * IR and depends on a length field class - * (which must also be part of IR). - */ - g_hash_table_insert(ft_dependents, seq_fc->length_fc, seq_fc->length_fc); - } - } - - break; - } - default: - fc->in_ir = true; - break; - } - -end: - return; -} - -/* - * Scopes and field classes are processed in reverse order because we need - * to know if a given integer field class has dependents (sequence or - * variant field classes) when we reach it. Dependents can only be located - * after the length/tag field class in the metadata tree. - */ -int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc) -{ - int ret = 0; - uint64_t i; - - GHashTable *ft_dependents = g_hash_table_new(g_direct_hash, g_direct_equal); - - BT_ASSERT(ft_dependents); - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - uint64_t j; - - for (j = 0; j < sc->event_classes->len; j++) { - ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; - - if (ec->is_translated) { - continue; - } - - update_field_class_in_ir(ec->payload_fc, ft_dependents); - update_field_class_in_ir(ec->spec_context_fc, ft_dependents); - } - - if (!sc->is_translated) { - update_field_class_in_ir(sc->event_common_context_fc, ft_dependents); - force_update_field_class_in_ir(sc->event_header_fc, false); - update_field_class_in_ir(sc->packet_context_fc, ft_dependents); - } - } - - if (!ctf_tc->is_translated) { - force_update_field_class_in_ir(ctf_tc->packet_header_fc, false); - } - - g_hash_table_destroy(ft_dependents); - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp deleted file mode 100644 index 23c65745..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#include "ctf-meta-visitors.hpp" - -static int set_int_field_class_meaning_by_name(struct ctf_field_class *fc, const char *field_name, - const char *id_name, - enum ctf_field_class_meaning meaning) -{ - int ret = 0; - uint64_t i; - - if (!fc) { - goto end; - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_INT: - case CTF_FIELD_CLASS_TYPE_ENUM: - { - struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - - if (field_name && strcmp(field_name, id_name) == 0) { - int_fc->meaning = meaning; - } - - break; - } - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - ret = set_int_field_class_meaning_by_name(named_fc->fc, named_fc->name->str, id_name, - meaning); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - for (i = 0; i < var_fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - ret = set_int_field_class_meaning_by_name(named_fc->fc, NULL, id_name, meaning); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - ret = set_int_field_class_meaning_by_name(array_fc->elem_fc, NULL, id_name, meaning); - if (ret) { - goto end; - } - - break; - } - default: - break; - } - -end: - return ret; -} - -static int update_stream_class_meanings(struct ctf_stream_class *sc) -{ - int ret = 0; - struct ctf_field_class_int *int_fc; - uint64_t i; - - if (!sc->is_translated) { - if (sc->packet_context_fc) { - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_END_TIME; - - /* - * Remove mapped clock class to avoid updating - * the clock immediately when decoding. - */ - int_fc->mapped_clock_class = NULL; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "packet_seq_num"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "packet_size"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "content_size"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE; - } - } - - if (sc->event_header_fc) { - ret = set_int_field_class_meaning_by_name(sc->event_header_fc, NULL, "id", - CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID); - if (ret) { - goto end; - } - } - } - - for (i = 0; i < sc->event_classes->len; i++) { - struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[i]; - - if (ec->is_translated) { - continue; - } - } - -end: - return ret; -} - -int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc) -{ - int ret = 0; - struct ctf_field_class_int *int_fc; - struct ctf_named_field_class *named_fc; - uint64_t i; - - if (!ctf_tc->is_translated && ctf_tc->packet_header_fc) { - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "magic"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_MAGIC; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_id"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_instance_id"); - if (int_fc) { - int_fc->meaning = CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID; - } - - named_fc = ctf_field_class_struct_borrow_member_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "uuid"); - if (named_fc && named_fc->fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) { - struct ctf_field_class_array *array_fc = ctf_field_class_as_array(named_fc->fc); - - array_fc->meaning = CTF_FIELD_CLASS_MEANING_UUID; - } - } - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - ret = update_stream_class_meanings((ctf_stream_class *) ctf_tc->stream_classes->pdata[i]); - if (ret) { - goto end; - } - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp deleted file mode 100644 index a8f5add6..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Philippe Proulx - */ - -#include - -#include "ctf-meta-visitors.hpp" - -int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc) -{ - struct ctf_field_class_int *int_fc; - uint64_t i; - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - struct ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - - if (sc->is_translated) { - continue; - } - - if (!sc->packet_context_fc) { - continue; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin"); - if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME) { - sc->packets_have_ts_begin = true; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end"); - if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_PACKET_END_TIME) { - sc->packets_have_ts_end = true; - } - - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded"); - if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT) { - sc->has_discarded_events = true; - } - - sc->discarded_events_have_default_cs = - sc->has_discarded_events && sc->packets_have_ts_begin && sc->packets_have_ts_end; - int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "packet_seq_num"); - if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT) { - sc->has_discarded_packets = true; - } - - sc->discarded_packets_have_default_cs = - sc->has_discarded_packets && sc->packets_have_ts_begin && sc->packets_have_ts_end; - } - - return 0; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp deleted file mode 100644 index 6c3bfc97..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include - -#include "ctf-meta-visitors.hpp" - -static inline int set_text_array_sequence_field_class(struct ctf_field_class *fc) -{ - int ret = 0; - uint64_t i; - - if (!fc) { - goto end; - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - ret = set_text_array_sequence_field_class(named_fc->fc); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - for (i = 0; i < var_fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - ret = set_text_array_sequence_field_class(named_fc->fc); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - if (array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_INT || - array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_ENUM) { - struct ctf_field_class_int *int_fc = ctf_field_class_as_int(array_fc->elem_fc); - - if (int_fc->base.base.alignment == 8 && int_fc->base.size == 8 && - int_fc->encoding == CTF_ENCODING_UTF8) { - array_fc->is_text = true; - - /* - * Force integer element to be unsigned; - * this makes the decoder enter a single - * path when reading a text - * array/sequence and we can safely - * decode bytes as characters anyway. - */ - int_fc->is_signed = false; - } - } - - ret = set_text_array_sequence_field_class(array_fc->elem_fc); - if (ret) { - goto end; - } - - break; - } - default: - break; - } - -end: - return ret; -} - -int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc) -{ - int ret = 0; - uint64_t i; - - if (!ctf_tc->is_translated) { - ret = set_text_array_sequence_field_class(ctf_tc->packet_header_fc); - if (ret) { - goto end; - } - } - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - uint64_t j; - - if (!sc->is_translated) { - ret = set_text_array_sequence_field_class(sc->packet_context_fc); - if (ret) { - goto end; - } - - ret = set_text_array_sequence_field_class(sc->event_header_fc); - if (ret) { - goto end; - } - - ret = set_text_array_sequence_field_class(sc->event_common_context_fc); - if (ret) { - goto end; - } - } - - for (j = 0; j < sc->event_classes->len; j++) { - struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; - - if (ec->is_translated) { - continue; - } - - ret = set_text_array_sequence_field_class(ec->spec_context_fc); - if (ret) { - goto end; - } - - ret = set_text_array_sequence_field_class(ec->payload_fc); - if (ret) { - goto end; - } - } - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp deleted file mode 100644 index 65e4c9fe..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#include "common/assert.h" - -#include "ctf-meta-visitors.hpp" - -static int update_field_class_stored_value_index(struct ctf_field_class *fc, - struct ctf_trace_class *tc, - struct ctf_stream_class *sc, - struct ctf_event_class *ec) -{ - int ret = 0; - uint64_t i; - struct ctf_field_path *field_path = NULL; - struct ctf_field_class_int *tgt_fc = NULL; - uint64_t *stored_value_index = NULL; - - if (!fc) { - goto end; - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - field_path = &var_fc->tag_path; - stored_value_index = &var_fc->stored_tag_index; - tgt_fc = &var_fc->tag_fc->base; - break; - } - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); - - field_path = &seq_fc->length_path; - stored_value_index = &seq_fc->stored_length_index; - tgt_fc = seq_fc->length_fc; - break; - } - default: - break; - } - - if (field_path) { - BT_ASSERT(tgt_fc); - BT_ASSERT(tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_INT || - tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_ENUM); - if (tgt_fc->storing_index >= 0) { - /* Already storing its value */ - *stored_value_index = (uint64_t) tgt_fc->storing_index; - } else { - /* Not storing its value: allocate new index */ - tgt_fc->storing_index = tc->stored_value_count; - *stored_value_index = (uint64_t) tgt_fc->storing_index; - tc->stored_value_count++; - } - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - ret = update_field_class_stored_value_index(named_fc->fc, tc, sc, ec); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - for (i = 0; i < var_fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - ret = update_field_class_stored_value_index(named_fc->fc, tc, sc, ec); - if (ret) { - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - ret = update_field_class_stored_value_index(array_fc->elem_fc, tc, sc, ec); - if (ret) { - goto end; - } - - break; - } - default: - break; - } - -end: - return ret; -} - -int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc) -{ - uint64_t i; - - if (!ctf_tc->is_translated) { - update_field_class_stored_value_index(ctf_tc->packet_header_fc, ctf_tc, NULL, NULL); - } - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - uint64_t j; - ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - - if (!sc->is_translated) { - update_field_class_stored_value_index(sc->packet_context_fc, ctf_tc, sc, NULL); - update_field_class_stored_value_index(sc->event_header_fc, ctf_tc, sc, NULL); - update_field_class_stored_value_index(sc->event_common_context_fc, ctf_tc, sc, NULL); - } - - for (j = 0; j < sc->event_classes->len; j++) { - struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; - - if (!ec->is_translated) { - update_field_class_stored_value_index(ec->spec_context_fc, ctf_tc, sc, ec); - update_field_class_stored_value_index(ec->payload_fc, ctf_tc, sc, ec); - } - } - } - - return 0; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-validate.cpp b/src/plugins/ctf/common/metadata/ctf-meta-validate.cpp deleted file mode 100644 index 9a01c593..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-validate.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include - -#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) -#define BT_COMP_LOG_SELF_COMP_CLASS (log_cfg->self_comp_class) -#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/VALIDATE" -#include "logging.hpp" - -#include "ctf-meta-visitors.hpp" - -static int validate_stream_class(struct ctf_stream_class *sc, struct meta_log_config *log_cfg) -{ - int ret = 0; - struct ctf_field_class_int *int_fc; - struct ctf_field_class *fc; - - if (sc->is_translated) { - goto end; - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet context field class: " - "`timestamp_begin` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " - "`timestamp_begin` member is signed."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet context field class: " - "`timestamp_end` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " - "`timestamp_end` member is signed."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet context field class: " - "`events_discarded` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " - "`events_discarded` member is signed."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "packet_seq_num"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet context field class: " - "`packet_seq_num` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " - "`packet_seq_num` member is signed."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "packet_size"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet context field class: " - "`packet_size` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " - "`packet_size` member is signed."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(sc->packet_context_fc), "content_size"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet context field class: " - "`content_size` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " - "`content_size` member is signed."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(sc->event_header_fc), "id"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: " - "`id` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: " - "`id` member is signed."); - goto invalid; - } - } else { - if (sc->event_classes->len > 1) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: " - "missing `id` member as there's " - "more than one event class."); - goto invalid; - } - } - - goto end; - -invalid: - ret = -1; - -end: - return ret; -} - -int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, struct meta_log_config *log_cfg) -{ - int ret = 0; - struct ctf_field_class_int *int_fc; - uint64_t i; - - if (!ctf_tc->is_translated) { - struct ctf_field_class *fc; - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "magic"); - if (fc) { - struct ctf_named_field_class *named_fc = ctf_field_class_struct_borrow_member_by_index( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), 0); - - if (named_fc->fc != fc) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`magic` member is not the first member."); - goto invalid; - } - - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet header field class: " - "`magic` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`magic` member is signed."); - goto invalid; - } - - if (int_fc->base.size != 32) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`magic` member is not 32-bit."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_id"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet header field class: " - "`stream_id` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`stream_id` member is signed."); - goto invalid; - } - } else { - if (ctf_tc->stream_classes->len > 1) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "missing `stream_id` member as there's " - "more than one stream class."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_instance_id"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet header field class: " - "`stream_instance_id` member is not an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`stream_instance_id` member is signed."); - goto invalid; - } - } - - fc = ctf_field_class_struct_borrow_member_field_class_by_name( - ctf_field_class_as_struct(ctf_tc->packet_header_fc), "uuid"); - if (fc) { - if (fc->type != CTF_FIELD_CLASS_TYPE_ARRAY) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet header field class: " - "`uuid` member is not an array field class."); - goto invalid; - } - - ctf_field_class_array *array_fc = ctf_field_class_as_array(fc); - - if (array_fc->length != 16) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet header field class: " - "`uuid` member is not a 16-element array field class."); - goto invalid; - } - - if (array_fc->base.elem_fc->type != CTF_FIELD_CLASS_TYPE_INT) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid packet header field class: " - "`uuid` member's element field class is not " - "an integer field class."); - goto invalid; - } - - int_fc = ctf_field_class_as_int(array_fc->base.elem_fc); - - if (int_fc->is_signed) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`uuid` member's element field class " - "is a signed integer field class."); - goto invalid; - } - - if (int_fc->base.size != 8) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`uuid` member's element field class " - "is not an 8-bit integer field class."); - goto invalid; - } - - if (int_fc->base.base.alignment != 8) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " - "`uuid` member's element field class's " - "alignment is not 8."); - goto invalid; - } - } - } - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - struct ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - - ret = validate_stream_class(sc, log_cfg); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid stream class: sc-id=%" PRIu64, - sc->id); - goto invalid; - } - } - - goto end; - -invalid: - ret = -1; - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta-visitors.hpp b/src/plugins/ctf/common/metadata/ctf-meta-visitors.hpp deleted file mode 100644 index 5294ecec..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-visitors.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#ifndef _CTF_META_VISITORS_H -#define _CTF_META_VISITORS_H - -#include - -#include "ctf-meta.hpp" - -struct meta_log_config; - -int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc, - struct meta_log_config *log_cfg); - -int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc, - struct ctf_trace_class *tc); - -int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc, - struct meta_log_config *log_cfg); - -int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc); - -int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc); - -int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc); - -int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc); - -int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc); - -int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc); - -int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, struct meta_log_config *log_cfg); - -void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc, - struct meta_log_config *log_cfg); - -#endif /* _CTF_META_VISITORS_H */ diff --git a/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp b/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp deleted file mode 100644 index 6d7e274a..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) -#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/WARN-MEANINGLESS-HEADER-FIELDS" -#include "logging.hpp" -#include "logging/comp-logging.h" - -#include "common/assert.h" - -#include "ctf-meta-visitors.hpp" - -static inline void warn_meaningless_field(const char *name, const char *scope_name, - struct meta_log_config *log_cfg) -{ - BT_ASSERT(name); - BT_COMP_LOGW("User field found in %s: ignoring: name=\"%s\"", scope_name, name); -} - -static inline void warn_meaningless_fields(struct ctf_field_class *fc, const char *name, - const char *scope_name, struct meta_log_config *log_cfg) -{ - uint64_t i; - - if (!fc) { - goto end; - } - - /* - * 'name' is guaranteed to be non-NULL whenever the field class is not a - * structure. In the case of a structure field class, its members' names - * are used. - */ - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_FLOAT: - case CTF_FIELD_CLASS_TYPE_STRING: - warn_meaningless_field(name, scope_name, log_cfg); - break; - case CTF_FIELD_CLASS_TYPE_INT: - case CTF_FIELD_CLASS_TYPE_ENUM: - { - struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - - if (int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE && !int_fc->mapped_clock_class) { - warn_meaningless_field(name, scope_name, log_cfg); - } - - break; - } - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - warn_meaningless_fields(named_fc->fc, named_fc->name->str, scope_name, log_cfg); - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - - for (i = 0; i < var_fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - warn_meaningless_fields(named_fc->fc, named_fc->name->str, scope_name, log_cfg); - } - - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - { - struct ctf_field_class_array *array_fc = ctf_field_class_as_array(fc); - - if (array_fc->meaning != CTF_FIELD_CLASS_MEANING_NONE) { - goto end; - } - } - /* fall-through */ - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - warn_meaningless_fields(array_fc->elem_fc, name, scope_name, log_cfg); - break; - } - default: - bt_common_abort(); - } - -end: - return; -} - -void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc, - struct meta_log_config *log_cfg) -{ - uint64_t i; - - if (!ctf_tc->is_translated) { - warn_meaningless_fields(ctf_tc->packet_header_fc, NULL, "packet header", log_cfg); - } - - for (i = 0; i < ctf_tc->stream_classes->len; i++) { - ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; - - if (!sc->is_translated) { - warn_meaningless_fields(sc->event_header_fc, NULL, "event header", log_cfg); - } - } -} diff --git a/src/plugins/ctf/common/metadata/ctf-meta.hpp b/src/plugins/ctf/common/metadata/ctf-meta.hpp deleted file mode 100644 index 87469d3b..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta.hpp +++ /dev/null @@ -1,1748 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#ifndef _CTF_META_H -#define _CTF_META_H - -#include -#include -#include - -#include - -#include "common/assert.h" -#include "common/common.h" -#include "common/uuid.h" - -enum ctf_field_class_type -{ - CTF_FIELD_CLASS_TYPE_INT, - CTF_FIELD_CLASS_TYPE_ENUM, - CTF_FIELD_CLASS_TYPE_FLOAT, - CTF_FIELD_CLASS_TYPE_STRING, - CTF_FIELD_CLASS_TYPE_STRUCT, - CTF_FIELD_CLASS_TYPE_ARRAY, - CTF_FIELD_CLASS_TYPE_SEQUENCE, - CTF_FIELD_CLASS_TYPE_VARIANT, -}; - -enum ctf_field_class_meaning -{ - CTF_FIELD_CLASS_MEANING_NONE, - CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME, - CTF_FIELD_CLASS_MEANING_PACKET_END_TIME, - CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID, - CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID, - CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID, - CTF_FIELD_CLASS_MEANING_MAGIC, - CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT, - CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT, - CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE, - CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE, - CTF_FIELD_CLASS_MEANING_UUID, -}; - -enum ctf_byte_order -{ - CTF_BYTE_ORDER_UNKNOWN, - CTF_BYTE_ORDER_DEFAULT, - CTF_BYTE_ORDER_LITTLE, - CTF_BYTE_ORDER_BIG, -}; - -enum ctf_encoding -{ - CTF_ENCODING_NONE, - CTF_ENCODING_UTF8, -}; - -enum ctf_scope -{ - CTF_SCOPE_PACKET_UNKNOWN = -1, - CTF_SCOPE_PACKET_HEADER = 0, - CTF_SCOPE_PACKET_CONTEXT, - CTF_SCOPE_EVENT_HEADER, - CTF_SCOPE_EVENT_COMMON_CONTEXT, - CTF_SCOPE_EVENT_SPECIFIC_CONTEXT, - CTF_SCOPE_EVENT_PAYLOAD, -}; - -struct ctf_clock_class -{ - GString *name; - GString *description; - uint64_t frequency; - uint64_t precision; - int64_t offset_seconds; - uint64_t offset_cycles; - bt_uuid_t uuid; - bool has_uuid; - bool is_absolute; - - /* Weak, set during translation */ - bt_clock_class *ir_cc; -}; - -struct ctf_field_class -{ - enum ctf_field_class_type type; - unsigned int alignment; - bool is_compound; - bool in_ir; - - /* Weak, set during translation. NULL if `in_ir` is false below. */ - bt_field_class *ir_fc; -}; - -struct ctf_field_class_bit_array -{ - struct ctf_field_class base; - enum ctf_byte_order byte_order; - unsigned int size; -}; - -struct ctf_field_class_int -{ - struct ctf_field_class_bit_array base; - enum ctf_field_class_meaning meaning; - bool is_signed; - bt_field_class_integer_preferred_display_base disp_base; - enum ctf_encoding encoding; - int64_t storing_index; - - /* Weak */ - struct ctf_clock_class *mapped_clock_class; -}; - -struct ctf_range -{ - union - { - uint64_t u; - int64_t i; - } lower; - - union - { - uint64_t u; - int64_t i; - } upper; -}; - -struct ctf_field_class_enum_mapping -{ - GString *label; - - /* Array of `struct ctf_range` */ - GArray *ranges; -}; - -struct ctf_field_class_enum -{ - struct ctf_field_class_int base; - - /* Array of `struct ctf_field_class_enum_mapping` */ - GArray *mappings; -}; - -struct ctf_field_class_float -{ - struct ctf_field_class_bit_array base; -}; - -struct ctf_field_class_string -{ - struct ctf_field_class base; - enum ctf_encoding encoding; -}; - -struct ctf_named_field_class -{ - /* Original name which can include a leading `_` */ - GString *orig_name; - - /* Name as translated to trace IR (leading `_` removed) */ - GString *name; - - /* Owned by this */ - struct ctf_field_class *fc; -}; - -struct ctf_field_class_struct -{ - struct ctf_field_class base; - - /* Array of `struct ctf_named_field_class` */ - GArray *members; -}; - -struct ctf_field_path -{ - enum ctf_scope root; - - /* Array of `int64_t` */ - GArray *path; -}; - -struct ctf_field_class_variant_range -{ - struct ctf_range range; - uint64_t option_index; -}; - -struct ctf_field_class_variant -{ - struct ctf_field_class base; - GString *tag_ref; - struct ctf_field_path tag_path; - uint64_t stored_tag_index; - - /* Array of `struct ctf_named_field_class` */ - GArray *options; - - /* Array of `struct ctf_field_class_variant_range` */ - GArray *ranges; - - /* Weak */ - struct ctf_field_class_enum *tag_fc; -}; - -struct ctf_field_class_array_base -{ - struct ctf_field_class base; - struct ctf_field_class *elem_fc; - bool is_text; -}; - -struct ctf_field_class_array -{ - struct ctf_field_class_array_base base; - enum ctf_field_class_meaning meaning; - uint64_t length; -}; - -struct ctf_field_class_sequence -{ - struct ctf_field_class_array_base base; - GString *length_ref; - struct ctf_field_path length_path; - uint64_t stored_length_index; - - /* Weak */ - struct ctf_field_class_int *length_fc; -}; - -struct ctf_event_class -{ - GString *name; - uint64_t id; - GString *emf_uri; - bt_event_class_log_level log_level; - bool is_translated; - bool is_log_level_set; - - /* Owned by this */ - struct ctf_field_class *spec_context_fc; - - /* Owned by this */ - struct ctf_field_class *payload_fc; - - /* Weak, set during translation */ - bt_event_class *ir_ec; -}; - -struct ctf_stream_class -{ - uint64_t id; - bool is_translated; - bool packets_have_ts_begin; - bool packets_have_ts_end; - bool has_discarded_events; - bool has_discarded_packets; - bool discarded_events_have_default_cs; - bool discarded_packets_have_default_cs; - - /* Owned by this */ - struct ctf_field_class *packet_context_fc; - - /* Owned by this */ - struct ctf_field_class *event_header_fc; - - /* Owned by this */ - struct ctf_field_class *event_common_context_fc; - - /* Array of `struct ctf_event_class *`, owned by this */ - GPtrArray *event_classes; - - /* - * Hash table mapping event class IDs to `struct ctf_event_class *`, - * weak. - */ - GHashTable *event_classes_by_id; - - /* Weak */ - struct ctf_clock_class *default_clock_class; - - /* Weak, set during translation */ - bt_stream_class *ir_sc; -}; - -enum ctf_trace_class_env_entry_type -{ - CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT, - CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR, -}; - -struct ctf_trace_class_env_entry -{ - enum ctf_trace_class_env_entry_type type; - GString *name; - - struct - { - int64_t i; - GString *str; - } value; -}; - -struct ctf_trace_class -{ - unsigned int major; - unsigned int minor; - bt_uuid_t uuid; - bool is_uuid_set; - enum ctf_byte_order default_byte_order; - - /* Owned by this */ - struct ctf_field_class *packet_header_fc; - - uint64_t stored_value_count; - - /* Array of `struct ctf_clock_class *` (owned by this) */ - GPtrArray *clock_classes; - - /* Array of `struct ctf_stream_class *` */ - GPtrArray *stream_classes; - - /* Array of `struct ctf_trace_class_env_entry` */ - GArray *env_entries; - - bool is_translated; - - /* Weak, set during translation */ - bt_trace_class *ir_tc; - - struct - { - bool lttng_crash; - bool lttng_event_after_packet; - bool barectf_event_before_packet; - } quirks; -}; - -static inline ctf_field_class_bit_array *ctf_field_class_as_bit_array(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || - (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM || - fc->type == CTF_FIELD_CLASS_TYPE_FLOAT)); - return (ctf_field_class_bit_array *) fc; -} - -static inline ctf_field_class_int *ctf_field_class_as_int(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || - (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM)); - return (ctf_field_class_int *) fc; -} - -static inline ctf_field_class_enum *ctf_field_class_as_enum(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ENUM); - return (ctf_field_class_enum *) fc; -} - -static inline ctf_field_class_float *ctf_field_class_as_float(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_FLOAT); - return (ctf_field_class_float *) fc; -} - -static inline ctf_field_class_string *ctf_field_class_as_string(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRING); - return (ctf_field_class_string *) fc; -} - -static inline ctf_field_class_struct *ctf_field_class_as_struct(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRUCT); - return (ctf_field_class_struct *) fc; -} - -static inline ctf_field_class_array_base *ctf_field_class_as_array_base(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || - fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE)); - return (ctf_field_class_array_base *) fc; -} - -static inline ctf_field_class_array *ctf_field_class_as_array(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ARRAY); - return (ctf_field_class_array *) fc; -} - -static inline ctf_field_class_sequence *ctf_field_class_as_sequence(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE); - return (ctf_field_class_sequence *) fc; -} - -static inline ctf_field_class_variant *ctf_field_class_as_variant(ctf_field_class *fc) -{ - BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_VARIANT); - return (ctf_field_class_variant *) fc; -} - -static inline void ctf_field_class_destroy(struct ctf_field_class *fc); - -static inline void _ctf_field_class_init(struct ctf_field_class *fc, enum ctf_field_class_type type, - unsigned int alignment) -{ - BT_ASSERT(fc); - fc->type = type; - fc->alignment = alignment; - fc->in_ir = false; -} - -static inline void _ctf_field_class_bit_array_init(struct ctf_field_class_bit_array *fc, - enum ctf_field_class_type type) -{ - _ctf_field_class_init(&fc->base, type, 1); -} - -static inline void _ctf_field_class_int_init(struct ctf_field_class_int *fc, - enum ctf_field_class_type type) -{ - _ctf_field_class_bit_array_init(&fc->base, type); - fc->meaning = CTF_FIELD_CLASS_MEANING_NONE; - fc->storing_index = -1; -} - -static inline void ctf_field_path_init(struct ctf_field_path *field_path) -{ - BT_ASSERT(field_path); - field_path->path = g_array_new(FALSE, TRUE, sizeof(int64_t)); - BT_ASSERT(field_path->path); -} - -static inline void ctf_field_path_fini(struct ctf_field_path *field_path) -{ - BT_ASSERT(field_path); - - if (field_path->path) { - g_array_free(field_path->path, TRUE); - } -} - -static inline void _ctf_named_field_class_init(struct ctf_named_field_class *named_fc) -{ - BT_ASSERT(named_fc); - named_fc->name = g_string_new(NULL); - BT_ASSERT(named_fc->name); - named_fc->orig_name = g_string_new(NULL); - BT_ASSERT(named_fc->orig_name); -} - -static inline void _ctf_named_field_class_fini(struct ctf_named_field_class *named_fc) -{ - BT_ASSERT(named_fc); - - if (named_fc->name) { - g_string_free(named_fc->name, TRUE); - } - - if (named_fc->orig_name) { - g_string_free(named_fc->orig_name, TRUE); - } - - ctf_field_class_destroy(named_fc->fc); -} - -static inline void _ctf_field_class_enum_mapping_init(struct ctf_field_class_enum_mapping *mapping) -{ - BT_ASSERT(mapping); - mapping->label = g_string_new(NULL); - BT_ASSERT(mapping->label); - mapping->ranges = g_array_new(FALSE, TRUE, sizeof(struct ctf_range)); - BT_ASSERT(mapping->ranges); -} - -static inline void _ctf_field_class_enum_mapping_fini(struct ctf_field_class_enum_mapping *mapping) -{ - BT_ASSERT(mapping); - - if (mapping->label) { - g_string_free(mapping->label, TRUE); - } - - if (mapping->ranges) { - g_array_free(mapping->ranges, TRUE); - } -} - -static inline struct ctf_field_class_int *ctf_field_class_int_create(void) -{ - struct ctf_field_class_int *fc = g_new0(struct ctf_field_class_int, 1); - - BT_ASSERT(fc); - _ctf_field_class_int_init(fc, CTF_FIELD_CLASS_TYPE_INT); - return fc; -} - -static inline struct ctf_field_class_float *ctf_field_class_float_create(void) -{ - struct ctf_field_class_float *fc = g_new0(struct ctf_field_class_float, 1); - - BT_ASSERT(fc); - _ctf_field_class_bit_array_init(&fc->base, CTF_FIELD_CLASS_TYPE_FLOAT); - return fc; -} - -static inline struct ctf_field_class_string *ctf_field_class_string_create(void) -{ - struct ctf_field_class_string *fc = g_new0(struct ctf_field_class_string, 1); - - BT_ASSERT(fc); - _ctf_field_class_init(&fc->base, CTF_FIELD_CLASS_TYPE_STRING, 8); - return fc; -} - -static inline struct ctf_field_class_enum *ctf_field_class_enum_create(void) -{ - struct ctf_field_class_enum *fc = g_new0(struct ctf_field_class_enum, 1); - - BT_ASSERT(fc); - _ctf_field_class_int_init(&fc->base, CTF_FIELD_CLASS_TYPE_ENUM); - fc->mappings = g_array_new(FALSE, TRUE, sizeof(struct ctf_field_class_enum_mapping)); - BT_ASSERT(fc->mappings); - return fc; -} - -static inline struct ctf_field_class_struct *ctf_field_class_struct_create(void) -{ - struct ctf_field_class_struct *fc = g_new0(struct ctf_field_class_struct, 1); - - BT_ASSERT(fc); - _ctf_field_class_init(&fc->base, CTF_FIELD_CLASS_TYPE_STRUCT, 1); - fc->members = g_array_new(FALSE, TRUE, sizeof(struct ctf_named_field_class)); - BT_ASSERT(fc->members); - fc->base.is_compound = true; - return fc; -} - -static inline struct ctf_field_class_variant *ctf_field_class_variant_create(void) -{ - struct ctf_field_class_variant *fc = g_new0(struct ctf_field_class_variant, 1); - - BT_ASSERT(fc); - _ctf_field_class_init(&fc->base, CTF_FIELD_CLASS_TYPE_VARIANT, 1); - fc->options = g_array_new(FALSE, TRUE, sizeof(struct ctf_named_field_class)); - BT_ASSERT(fc->options); - fc->ranges = g_array_new(FALSE, TRUE, sizeof(struct ctf_field_class_variant_range)); - BT_ASSERT(fc->ranges); - fc->tag_ref = g_string_new(NULL); - BT_ASSERT(fc->tag_ref); - ctf_field_path_init(&fc->tag_path); - fc->base.is_compound = true; - return fc; -} - -static inline struct ctf_field_class_array *ctf_field_class_array_create(void) -{ - struct ctf_field_class_array *fc = g_new0(struct ctf_field_class_array, 1); - - BT_ASSERT(fc); - _ctf_field_class_init(&fc->base.base, CTF_FIELD_CLASS_TYPE_ARRAY, 1); - fc->base.base.is_compound = true; - return fc; -} - -static inline struct ctf_field_class_sequence *ctf_field_class_sequence_create(void) -{ - struct ctf_field_class_sequence *fc = g_new0(struct ctf_field_class_sequence, 1); - - BT_ASSERT(fc); - _ctf_field_class_init(&fc->base.base, CTF_FIELD_CLASS_TYPE_SEQUENCE, 1); - fc->length_ref = g_string_new(NULL); - BT_ASSERT(fc->length_ref); - ctf_field_path_init(&fc->length_path); - fc->base.base.is_compound = true; - return fc; -} - -static inline void _ctf_field_class_int_destroy(struct ctf_field_class_int *fc) -{ - BT_ASSERT(fc); - g_free(fc); -} - -static inline void _ctf_field_class_enum_destroy(struct ctf_field_class_enum *fc) -{ - BT_ASSERT(fc); - - if (fc->mappings) { - uint64_t i; - - for (i = 0; i < fc->mappings->len; i++) { - struct ctf_field_class_enum_mapping *mapping = - &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, i); - - _ctf_field_class_enum_mapping_fini(mapping); - } - - g_array_free(fc->mappings, TRUE); - } - - g_free(fc); -} - -static inline void _ctf_field_class_float_destroy(struct ctf_field_class_float *fc) -{ - BT_ASSERT(fc); - g_free(fc); -} - -static inline void _ctf_field_class_string_destroy(struct ctf_field_class_string *fc) -{ - BT_ASSERT(fc); - g_free(fc); -} - -static inline void _ctf_field_class_struct_destroy(struct ctf_field_class_struct *fc) -{ - BT_ASSERT(fc); - - if (fc->members) { - uint64_t i; - - for (i = 0; i < fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - &bt_g_array_index(fc->members, struct ctf_named_field_class, i); - - _ctf_named_field_class_fini(named_fc); - } - - g_array_free(fc->members, TRUE); - } - - g_free(fc); -} - -static inline void _ctf_field_class_array_base_fini(struct ctf_field_class_array_base *fc) -{ - BT_ASSERT(fc); - ctf_field_class_destroy(fc->elem_fc); -} - -static inline void _ctf_field_class_array_destroy(struct ctf_field_class_array *fc) -{ - BT_ASSERT(fc); - _ctf_field_class_array_base_fini(&fc->base); - g_free(fc); -} - -static inline void _ctf_field_class_sequence_destroy(struct ctf_field_class_sequence *fc) -{ - BT_ASSERT(fc); - _ctf_field_class_array_base_fini(&fc->base); - - if (fc->length_ref) { - g_string_free(fc->length_ref, TRUE); - } - - ctf_field_path_fini(&fc->length_path); - g_free(fc); -} - -static inline void _ctf_field_class_variant_destroy(struct ctf_field_class_variant *fc) -{ - BT_ASSERT(fc); - - if (fc->options) { - uint64_t i; - - for (i = 0; i < fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - &bt_g_array_index(fc->options, struct ctf_named_field_class, i); - - _ctf_named_field_class_fini(named_fc); - } - - g_array_free(fc->options, TRUE); - } - - if (fc->ranges) { - g_array_free(fc->ranges, TRUE); - } - - if (fc->tag_ref) { - g_string_free(fc->tag_ref, TRUE); - } - - ctf_field_path_fini(&fc->tag_path); - g_free(fc); -} - -static inline void ctf_field_class_destroy(struct ctf_field_class *fc) -{ - if (!fc) { - return; - } - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_INT: - _ctf_field_class_int_destroy(ctf_field_class_as_int(fc)); - break; - case CTF_FIELD_CLASS_TYPE_ENUM: - _ctf_field_class_enum_destroy(ctf_field_class_as_enum(fc)); - break; - case CTF_FIELD_CLASS_TYPE_FLOAT: - _ctf_field_class_float_destroy(ctf_field_class_as_float(fc)); - break; - case CTF_FIELD_CLASS_TYPE_STRING: - _ctf_field_class_string_destroy(ctf_field_class_as_string(fc)); - break; - case CTF_FIELD_CLASS_TYPE_STRUCT: - _ctf_field_class_struct_destroy(ctf_field_class_as_struct(fc)); - break; - case CTF_FIELD_CLASS_TYPE_ARRAY: - _ctf_field_class_array_destroy(ctf_field_class_as_array(fc)); - break; - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - _ctf_field_class_sequence_destroy(ctf_field_class_as_sequence(fc)); - break; - case CTF_FIELD_CLASS_TYPE_VARIANT: - _ctf_field_class_variant_destroy(ctf_field_class_as_variant(fc)); - break; - default: - bt_common_abort(); - } -} - -static inline struct ctf_range * -ctf_field_class_enum_mapping_borrow_range_by_index(struct ctf_field_class_enum_mapping *mapping, - uint64_t index) -{ - BT_ASSERT_DBG(mapping); - BT_ASSERT_DBG(index < mapping->ranges->len); - return &bt_g_array_index(mapping->ranges, struct ctf_range, index); -} - -static inline struct ctf_field_class_enum_mapping * -ctf_field_class_enum_borrow_mapping_by_index(struct ctf_field_class_enum *fc, uint64_t index) -{ - BT_ASSERT_DBG(fc); - BT_ASSERT_DBG(index < fc->mappings->len); - return &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, index); -} - -static inline struct ctf_field_class_enum_mapping * -ctf_field_class_enum_borrow_mapping_by_label(struct ctf_field_class_enum *fc, const char *label) -{ - struct ctf_field_class_enum_mapping *ret_mapping = NULL; - uint64_t i; - - BT_ASSERT_DBG(fc); - BT_ASSERT_DBG(label); - - for (i = 0; i < fc->mappings->len; i++) { - struct ctf_field_class_enum_mapping *mapping = - ctf_field_class_enum_borrow_mapping_by_index(fc, i); - - if (strcmp(mapping->label->str, label) == 0) { - ret_mapping = mapping; - goto end; - } - } - -end: - return ret_mapping; -} - -static inline void ctf_field_class_enum_map_range(struct ctf_field_class_enum *fc, - const char *label, uint64_t u_lower, - uint64_t u_upper) -{ - struct ctf_field_class_enum_mapping *mapping = NULL; - struct ctf_range range = { - .lower = - { - .u = u_lower, - }, - .upper = - { - .u = u_upper, - }, - }; - uint64_t i; - - BT_ASSERT(fc); - BT_ASSERT(label); - - for (i = 0; i < fc->mappings->len; i++) { - mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, i); - - if (strcmp(mapping->label->str, label) == 0) { - break; - } - } - - if (i == fc->mappings->len) { - mapping = NULL; - } - - if (!mapping) { - g_array_set_size(fc->mappings, fc->mappings->len + 1); - mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, fc->mappings->len - 1); - _ctf_field_class_enum_mapping_init(mapping); - g_string_assign(mapping->label, label); - } - - g_array_append_val(mapping->ranges, range); -} - -static inline struct ctf_named_field_class * -ctf_field_class_struct_borrow_member_by_index(struct ctf_field_class_struct *fc, uint64_t index) -{ - BT_ASSERT_DBG(fc); - BT_ASSERT_DBG(index < fc->members->len); - return &bt_g_array_index(fc->members, struct ctf_named_field_class, index); -} - -static inline struct ctf_named_field_class * -ctf_field_class_struct_borrow_member_by_name(struct ctf_field_class_struct *fc, const char *name) -{ - uint64_t i; - struct ctf_named_field_class *ret_named_fc = NULL; - - BT_ASSERT_DBG(fc); - BT_ASSERT_DBG(name); - - for (i = 0; i < fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(fc, i); - - if (strcmp(name, named_fc->name->str) == 0) { - ret_named_fc = named_fc; - goto end; - } - } - -end: - return ret_named_fc; -} - -static inline struct ctf_field_class * -ctf_field_class_struct_borrow_member_field_class_by_name(struct ctf_field_class_struct *struct_fc, - const char *name) -{ - struct ctf_named_field_class *named_fc = NULL; - struct ctf_field_class *fc = NULL; - - if (!struct_fc) { - goto end; - } - - named_fc = ctf_field_class_struct_borrow_member_by_name(struct_fc, name); - if (!named_fc) { - goto end; - } - - fc = named_fc->fc; - -end: - return fc; -} - -static inline struct ctf_field_class_int * -ctf_field_class_struct_borrow_member_int_field_class_by_name( - struct ctf_field_class_struct *struct_fc, const char *name) -{ - ctf_field_class *member_fc = - ctf_field_class_struct_borrow_member_field_class_by_name(struct_fc, name); - - if (!member_fc) { - return nullptr; - } - - if (member_fc->type != CTF_FIELD_CLASS_TYPE_INT && - member_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - return nullptr; - } - - return ctf_field_class_as_int(member_fc); -} - -static inline void _ctf_named_field_class_unescape_orig_name(struct ctf_named_field_class *named_fc) -{ - const char *name = named_fc->orig_name->str; - - if (name[0] == '_') { - name++; - } - - g_string_assign(named_fc->name, name); -} - -static inline void ctf_field_class_struct_append_member(struct ctf_field_class_struct *fc, - const char *orig_name, - struct ctf_field_class *member_fc) -{ - struct ctf_named_field_class *named_fc; - - BT_ASSERT(fc); - BT_ASSERT(orig_name); - g_array_set_size(fc->members, fc->members->len + 1); - - named_fc = &bt_g_array_index(fc->members, struct ctf_named_field_class, fc->members->len - 1); - _ctf_named_field_class_init(named_fc); - g_string_assign(named_fc->orig_name, orig_name); - _ctf_named_field_class_unescape_orig_name(named_fc); - named_fc->fc = member_fc; - - if (member_fc->alignment > fc->base.alignment) { - fc->base.alignment = member_fc->alignment; - } -} - -static inline struct ctf_named_field_class * -ctf_field_class_variant_borrow_option_by_index(struct ctf_field_class_variant *fc, uint64_t index) -{ - BT_ASSERT_DBG(fc); - BT_ASSERT_DBG(index < fc->options->len); - return &bt_g_array_index(fc->options, struct ctf_named_field_class, index); -} - -static inline struct ctf_named_field_class * -ctf_field_class_variant_borrow_option_by_name(struct ctf_field_class_variant *fc, const char *name) -{ - uint64_t i; - struct ctf_named_field_class *ret_named_fc = NULL; - - BT_ASSERT_DBG(fc); - BT_ASSERT_DBG(name); - - for (i = 0; i < fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(fc, i); - - if (strcmp(name, named_fc->name->str) == 0) { - ret_named_fc = named_fc; - goto end; - } - } - -end: - return ret_named_fc; -} - -static inline struct ctf_field_class_variant_range * -ctf_field_class_variant_borrow_range_by_index(struct ctf_field_class_variant *fc, uint64_t index) -{ - BT_ASSERT_DBG(fc); - BT_ASSERT_DBG(index < fc->ranges->len); - return &bt_g_array_index(fc->ranges, struct ctf_field_class_variant_range, index); -} - -static inline void ctf_field_class_variant_append_option(struct ctf_field_class_variant *fc, - const char *orig_name, - struct ctf_field_class *option_fc) -{ - struct ctf_named_field_class *named_fc; - - BT_ASSERT(fc); - BT_ASSERT(orig_name); - g_array_set_size(fc->options, fc->options->len + 1); - - named_fc = &bt_g_array_index(fc->options, struct ctf_named_field_class, fc->options->len - 1); - _ctf_named_field_class_init(named_fc); - g_string_assign(named_fc->orig_name, orig_name); - _ctf_named_field_class_unescape_orig_name(named_fc); - named_fc->fc = option_fc; -} - -static inline void ctf_field_class_variant_set_tag_field_class(struct ctf_field_class_variant *fc, - struct ctf_field_class_enum *tag_fc) -{ - uint64_t option_i; - - BT_ASSERT(fc); - BT_ASSERT(tag_fc); - fc->tag_fc = tag_fc; - - for (option_i = 0; option_i < fc->options->len; option_i++) { - uint64_t range_i; - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(fc, option_i); - struct ctf_field_class_enum_mapping *mapping; - - mapping = ctf_field_class_enum_borrow_mapping_by_label(tag_fc, named_fc->orig_name->str); - if (!mapping) { - continue; - } - - for (range_i = 0; range_i < mapping->ranges->len; range_i++) { - struct ctf_range *range = - ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i); - struct ctf_field_class_variant_range var_range; - - var_range.range = *range; - var_range.option_index = option_i; - g_array_append_val(fc->ranges, var_range); - } - } -} - -static inline struct ctf_field_class * -ctf_field_class_compound_borrow_field_class_by_index(struct ctf_field_class *comp_fc, - uint64_t index) -{ - struct ctf_field_class *fc = NULL; - - switch (comp_fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_named_field_class *named_fc = ctf_field_class_struct_borrow_member_by_index( - (struct ctf_field_class_struct *) comp_fc, index); - - BT_ASSERT_DBG(named_fc); - fc = named_fc->fc; - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_named_field_class *named_fc = ctf_field_class_variant_borrow_option_by_index( - (struct ctf_field_class_variant *) comp_fc, index); - - BT_ASSERT_DBG(named_fc); - fc = named_fc->fc; - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - { - struct ctf_field_class_array_base *array_fc = (struct ctf_field_class_array_base *) comp_fc; - - fc = array_fc->elem_fc; - break; - } - default: - break; - } - - return fc; -} - -static inline uint64_t ctf_field_class_compound_get_field_class_count(struct ctf_field_class *fc) -{ - uint64_t field_count; - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = (struct ctf_field_class_struct *) fc; - - field_count = struct_fc->members->len; - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) fc; - - field_count = var_fc->options->len; - break; - } - case CTF_FIELD_CLASS_TYPE_ARRAY: - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - /* - * Array and sequence types always contain a single - * member (the element type). - */ - field_count = 1; - break; - default: - bt_common_abort(); - } - - return field_count; -} - -static inline int64_t -ctf_field_class_compound_get_field_class_index_from_orig_name(struct ctf_field_class *fc, - const char *orig_name) -{ - int64_t ret_index = -1; - uint64_t i; - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_STRUCT: - { - struct ctf_field_class_struct *struct_fc = (struct ctf_field_class_struct *) fc; - - for (i = 0; i < struct_fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - - if (strcmp(orig_name, named_fc->orig_name->str) == 0) { - ret_index = (int64_t) i; - goto end; - } - } - - break; - } - case CTF_FIELD_CLASS_TYPE_VARIANT: - { - struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) fc; - - for (i = 0; i < var_fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - ctf_field_class_variant_borrow_option_by_index(var_fc, i); - - if (strcmp(orig_name, named_fc->orig_name->str) == 0) { - ret_index = (int64_t) i; - goto end; - } - } - - break; - } - default: - break; - } - -end: - return ret_index; -} - -static inline void ctf_field_path_append_index(struct ctf_field_path *fp, int64_t index) -{ - BT_ASSERT(fp); - g_array_append_val(fp->path, index); -} - -static inline int64_t ctf_field_path_borrow_index_by_index(struct ctf_field_path *fp, - uint64_t index) -{ - BT_ASSERT_DBG(fp); - BT_ASSERT_DBG(index < fp->path->len); - return bt_g_array_index(fp->path, int64_t, index); -} - -static inline void ctf_field_path_clear(struct ctf_field_path *fp) -{ - BT_ASSERT(fp); - g_array_set_size(fp->path, 0); -} - -static inline const char *ctf_scope_string(enum ctf_scope scope) -{ - switch (scope) { - case CTF_SCOPE_PACKET_HEADER: - return "PACKET_HEADER"; - case CTF_SCOPE_PACKET_CONTEXT: - return "PACKET_CONTEXT"; - case CTF_SCOPE_EVENT_HEADER: - return "EVENT_HEADER"; - case CTF_SCOPE_EVENT_COMMON_CONTEXT: - return "EVENT_COMMON_CONTEXT"; - case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: - return "EVENT_SPECIFIC_CONTEXT"; - case CTF_SCOPE_EVENT_PAYLOAD: - return "EVENT_PAYLOAD"; - default: - bt_common_abort(); - } -} - -static inline GString *ctf_field_path_string(struct ctf_field_path *path) -{ - GString *str = g_string_new(NULL); - uint64_t i; - - BT_ASSERT(path); - - if (!str) { - goto end; - } - - g_string_append_printf(str, "[%s", ctf_scope_string(path->root)); - - for (i = 0; i < path->path->len; i++) { - g_string_append_printf(str, ", %" PRId64, ctf_field_path_borrow_index_by_index(path, i)); - } - - g_string_append(str, "]"); - -end: - return str; -} - -static inline struct ctf_field_class * -ctf_field_path_borrow_field_class(struct ctf_field_path *field_path, struct ctf_trace_class *tc, - struct ctf_stream_class *sc, struct ctf_event_class *ec) -{ - uint64_t i; - struct ctf_field_class *fc; - - switch (field_path->root) { - case CTF_SCOPE_PACKET_HEADER: - fc = tc->packet_header_fc; - break; - case CTF_SCOPE_PACKET_CONTEXT: - fc = sc->packet_context_fc; - break; - case CTF_SCOPE_EVENT_HEADER: - fc = sc->event_header_fc; - break; - case CTF_SCOPE_EVENT_COMMON_CONTEXT: - fc = sc->event_common_context_fc; - break; - case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: - fc = ec->spec_context_fc; - break; - case CTF_SCOPE_EVENT_PAYLOAD: - fc = ec->payload_fc; - break; - default: - bt_common_abort(); - } - - BT_ASSERT_DBG(fc); - - for (i = 0; i < field_path->path->len; i++) { - int64_t child_index = ctf_field_path_borrow_index_by_index(field_path, i); - struct ctf_field_class *child_fc = - ctf_field_class_compound_borrow_field_class_by_index(fc, child_index); - BT_ASSERT_DBG(child_fc); - fc = child_fc; - } - - BT_ASSERT_DBG(fc); - return fc; -} - -static inline struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc); - -static inline void ctf_field_class_bit_array_copy_content(struct ctf_field_class_bit_array *dst_fc, - struct ctf_field_class_bit_array *src_fc) -{ - BT_ASSERT(dst_fc); - BT_ASSERT(src_fc); - dst_fc->byte_order = src_fc->byte_order; - dst_fc->size = src_fc->size; -} - -static inline void ctf_field_class_int_copy_content(struct ctf_field_class_int *dst_fc, - struct ctf_field_class_int *src_fc) -{ - ctf_field_class_bit_array_copy_content(&dst_fc->base, &src_fc->base); - dst_fc->meaning = src_fc->meaning; - dst_fc->is_signed = src_fc->is_signed; - dst_fc->disp_base = src_fc->disp_base; - dst_fc->encoding = src_fc->encoding; - dst_fc->mapped_clock_class = src_fc->mapped_clock_class; - dst_fc->storing_index = src_fc->storing_index; -} - -static inline struct ctf_field_class_int *_ctf_field_class_int_copy(struct ctf_field_class_int *fc) -{ - struct ctf_field_class_int *copy_fc = ctf_field_class_int_create(); - - BT_ASSERT(copy_fc); - ctf_field_class_int_copy_content(copy_fc, fc); - return copy_fc; -} - -static inline struct ctf_field_class_enum * -_ctf_field_class_enum_copy(struct ctf_field_class_enum *fc) -{ - struct ctf_field_class_enum *copy_fc = ctf_field_class_enum_create(); - uint64_t i; - - BT_ASSERT(copy_fc); - ctf_field_class_int_copy_content(©_fc->base, &fc->base); - - for (i = 0; i < fc->mappings->len; i++) { - uint64_t range_i; - - struct ctf_field_class_enum_mapping *mapping = - &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, i); - - for (range_i = 0; range_i < mapping->ranges->len; range_i++) { - struct ctf_range *range = &bt_g_array_index(mapping->ranges, struct ctf_range, range_i); - - ctf_field_class_enum_map_range(copy_fc, mapping->label->str, range->lower.u, - range->upper.u); - } - } - - return copy_fc; -} - -static inline struct ctf_field_class_float * -_ctf_field_class_float_copy(struct ctf_field_class_float *fc) -{ - struct ctf_field_class_float *copy_fc = ctf_field_class_float_create(); - - BT_ASSERT(copy_fc); - ctf_field_class_bit_array_copy_content(©_fc->base, &fc->base); - return copy_fc; -} - -static inline struct ctf_field_class_string * -_ctf_field_class_string_copy(struct ctf_field_class_string *) -{ - struct ctf_field_class_string *copy_fc = ctf_field_class_string_create(); - - BT_ASSERT(copy_fc); - return copy_fc; -} - -static inline struct ctf_field_class_struct * -_ctf_field_class_struct_copy(struct ctf_field_class_struct *fc) -{ - struct ctf_field_class_struct *copy_fc = ctf_field_class_struct_create(); - uint64_t i; - - BT_ASSERT(copy_fc); - - for (i = 0; i < fc->members->len; i++) { - struct ctf_named_field_class *named_fc = - &bt_g_array_index(fc->members, struct ctf_named_field_class, i); - - ctf_field_class_struct_append_member(copy_fc, named_fc->name->str, - ctf_field_class_copy(named_fc->fc)); - } - - return copy_fc; -} - -static inline void ctf_field_path_copy_content(struct ctf_field_path *dst_fp, - struct ctf_field_path *src_fp) -{ - uint64_t i; - - BT_ASSERT(dst_fp); - BT_ASSERT(src_fp); - dst_fp->root = src_fp->root; - ctf_field_path_clear(dst_fp); - - for (i = 0; i < src_fp->path->len; i++) { - int64_t index = ctf_field_path_borrow_index_by_index(src_fp, i); - - ctf_field_path_append_index(dst_fp, index); - } -} - -static inline struct ctf_field_class_variant * -_ctf_field_class_variant_copy(struct ctf_field_class_variant *fc) -{ - struct ctf_field_class_variant *copy_fc = ctf_field_class_variant_create(); - uint64_t i; - - BT_ASSERT(copy_fc); - - for (i = 0; i < fc->options->len; i++) { - struct ctf_named_field_class *named_fc = - &bt_g_array_index(fc->options, struct ctf_named_field_class, i); - - ctf_field_class_variant_append_option(copy_fc, named_fc->name->str, - ctf_field_class_copy(named_fc->fc)); - } - - for (i = 0; i < fc->ranges->len; i++) { - struct ctf_field_class_variant_range *range = - &bt_g_array_index(fc->ranges, struct ctf_field_class_variant_range, i); - - g_array_append_val(copy_fc->ranges, *range); - } - - ctf_field_path_copy_content(©_fc->tag_path, &fc->tag_path); - g_string_assign(copy_fc->tag_ref, fc->tag_ref->str); - copy_fc->stored_tag_index = fc->stored_tag_index; - return copy_fc; -} - -static inline void -ctf_field_class_array_base_copy_content(struct ctf_field_class_array_base *dst_fc, - struct ctf_field_class_array_base *src_fc) -{ - BT_ASSERT(dst_fc); - BT_ASSERT(src_fc); - dst_fc->elem_fc = ctf_field_class_copy(src_fc->elem_fc); - dst_fc->is_text = src_fc->is_text; -} - -static inline struct ctf_field_class_array * -_ctf_field_class_array_copy(struct ctf_field_class_array *fc) -{ - struct ctf_field_class_array *copy_fc = ctf_field_class_array_create(); - - BT_ASSERT(copy_fc); - ctf_field_class_array_base_copy_content(©_fc->base, &fc->base); - copy_fc->length = fc->length; - return copy_fc; -} - -static inline struct ctf_field_class_sequence * -_ctf_field_class_sequence_copy(struct ctf_field_class_sequence *fc) -{ - struct ctf_field_class_sequence *copy_fc = ctf_field_class_sequence_create(); - - BT_ASSERT(copy_fc); - ctf_field_class_array_base_copy_content(©_fc->base, &fc->base); - ctf_field_path_copy_content(©_fc->length_path, &fc->length_path); - g_string_assign(copy_fc->length_ref, fc->length_ref->str); - copy_fc->stored_length_index = fc->stored_length_index; - return copy_fc; -} - -static inline struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc) -{ - struct ctf_field_class *copy_fc = NULL; - - if (!fc) { - goto end; - } - - /* - * Translation should not have happened yet. - */ - BT_ASSERT(!fc->ir_fc); - - switch (fc->type) { - case CTF_FIELD_CLASS_TYPE_INT: - copy_fc = &_ctf_field_class_int_copy(ctf_field_class_as_int(fc))->base.base; - break; - case CTF_FIELD_CLASS_TYPE_ENUM: - copy_fc = &_ctf_field_class_enum_copy(ctf_field_class_as_enum(fc))->base.base.base; - break; - case CTF_FIELD_CLASS_TYPE_FLOAT: - copy_fc = &_ctf_field_class_float_copy(ctf_field_class_as_float(fc))->base.base; - break; - case CTF_FIELD_CLASS_TYPE_STRING: - copy_fc = &_ctf_field_class_string_copy(ctf_field_class_as_string(fc))->base; - break; - case CTF_FIELD_CLASS_TYPE_STRUCT: - copy_fc = &_ctf_field_class_struct_copy(ctf_field_class_as_struct(fc))->base; - break; - case CTF_FIELD_CLASS_TYPE_ARRAY: - copy_fc = &_ctf_field_class_array_copy(ctf_field_class_as_array(fc))->base.base; - break; - case CTF_FIELD_CLASS_TYPE_SEQUENCE: - copy_fc = &_ctf_field_class_sequence_copy(ctf_field_class_as_sequence(fc))->base.base; - break; - case CTF_FIELD_CLASS_TYPE_VARIANT: - copy_fc = &_ctf_field_class_variant_copy(ctf_field_class_as_variant(fc))->base; - break; - default: - bt_common_abort(); - } - - copy_fc->type = fc->type; - copy_fc->alignment = fc->alignment; - copy_fc->in_ir = fc->in_ir; - -end: - return copy_fc; -} - -static inline struct ctf_event_class *ctf_event_class_create(void) -{ - struct ctf_event_class *ec = g_new0(struct ctf_event_class, 1); - - BT_ASSERT(ec); - ec->name = g_string_new(NULL); - BT_ASSERT(ec->name); - ec->emf_uri = g_string_new(NULL); - BT_ASSERT(ec->emf_uri); - ec->is_log_level_set = false; - return ec; -} - -static inline void ctf_event_class_set_log_level(struct ctf_event_class *ec, - enum bt_event_class_log_level log_level) -{ - BT_ASSERT(ec); - ec->log_level = log_level; - ec->is_log_level_set = true; -} - -static inline void ctf_event_class_destroy(struct ctf_event_class *ec) -{ - if (!ec) { - return; - } - - if (ec->name) { - g_string_free(ec->name, TRUE); - } - - if (ec->emf_uri) { - g_string_free(ec->emf_uri, TRUE); - } - - ctf_field_class_destroy(ec->spec_context_fc); - ctf_field_class_destroy(ec->payload_fc); - g_free(ec); -} - -static inline struct ctf_stream_class *ctf_stream_class_create(void) -{ - struct ctf_stream_class *sc = g_new0(struct ctf_stream_class, 1); - - BT_ASSERT(sc); - sc->event_classes = g_ptr_array_new_with_free_func((GDestroyNotify) ctf_event_class_destroy); - BT_ASSERT(sc->event_classes); - sc->event_classes_by_id = g_hash_table_new(g_direct_hash, g_direct_equal); - BT_ASSERT(sc->event_classes_by_id); - return sc; -} - -static inline void ctf_stream_class_destroy(struct ctf_stream_class *sc) -{ - if (!sc) { - return; - } - - if (sc->event_classes) { - g_ptr_array_free(sc->event_classes, TRUE); - } - - if (sc->event_classes_by_id) { - g_hash_table_destroy(sc->event_classes_by_id); - } - - ctf_field_class_destroy(sc->packet_context_fc); - ctf_field_class_destroy(sc->event_header_fc); - ctf_field_class_destroy(sc->event_common_context_fc); - g_free(sc); -} - -static inline void ctf_stream_class_append_event_class(struct ctf_stream_class *sc, - struct ctf_event_class *ec) -{ - g_ptr_array_add(sc->event_classes, ec); - g_hash_table_insert(sc->event_classes_by_id, GUINT_TO_POINTER((guint) ec->id), ec); -} - -static inline struct ctf_event_class * -ctf_stream_class_borrow_event_class_by_id(struct ctf_stream_class *sc, uint64_t type) -{ - BT_ASSERT_DBG(sc); - return (struct ctf_event_class *) g_hash_table_lookup(sc->event_classes_by_id, - GUINT_TO_POINTER((guint) type)); -} - -static inline void _ctf_trace_class_env_entry_init(struct ctf_trace_class_env_entry *entry) -{ - BT_ASSERT(entry); - entry->name = g_string_new(NULL); - BT_ASSERT(entry->name); - entry->value.str = g_string_new(NULL); - BT_ASSERT(entry->value.str); -} - -static inline void _ctf_trace_class_env_entry_fini(struct ctf_trace_class_env_entry *entry) -{ - BT_ASSERT(entry); - - if (entry->name) { - g_string_free(entry->name, TRUE); - } - - if (entry->value.str) { - g_string_free(entry->value.str, TRUE); - } -} - -static inline struct ctf_clock_class *ctf_clock_class_create(void) -{ - struct ctf_clock_class *cc = g_new0(struct ctf_clock_class, 1); - - BT_ASSERT(cc); - cc->name = g_string_new(NULL); - BT_ASSERT(cc->name); - cc->description = g_string_new(NULL); - BT_ASSERT(cc->description); - return cc; -} - -static inline void ctf_clock_class_destroy(struct ctf_clock_class *cc) -{ - if (!cc) { - return; - } - - if (cc->name) { - g_string_free(cc->name, TRUE); - } - - if (cc->description) { - g_string_free(cc->description, TRUE); - } - - bt_clock_class_put_ref(cc->ir_cc); - g_free(cc); -} - -static inline struct ctf_trace_class *ctf_trace_class_create(void) -{ - struct ctf_trace_class *tc = g_new0(struct ctf_trace_class, 1); - - BT_ASSERT(tc); - tc->default_byte_order = CTF_BYTE_ORDER_UNKNOWN; - tc->clock_classes = g_ptr_array_new_with_free_func((GDestroyNotify) ctf_clock_class_destroy); - BT_ASSERT(tc->clock_classes); - tc->stream_classes = g_ptr_array_new_with_free_func((GDestroyNotify) ctf_stream_class_destroy); - BT_ASSERT(tc->stream_classes); - tc->env_entries = g_array_new(FALSE, TRUE, sizeof(struct ctf_trace_class_env_entry)); - return tc; -} - -static inline void ctf_trace_class_destroy(struct ctf_trace_class *tc) -{ - if (!tc) { - return; - } - - ctf_field_class_destroy(tc->packet_header_fc); - - if (tc->clock_classes) { - g_ptr_array_free(tc->clock_classes, TRUE); - } - - if (tc->stream_classes) { - g_ptr_array_free(tc->stream_classes, TRUE); - } - - if (tc->env_entries) { - uint64_t i; - - for (i = 0; i < tc->env_entries->len; i++) { - struct ctf_trace_class_env_entry *entry = - &bt_g_array_index(tc->env_entries, struct ctf_trace_class_env_entry, i); - - _ctf_trace_class_env_entry_fini(entry); - } - - g_array_free(tc->env_entries, TRUE); - } - - g_free(tc); -} - -static inline void ctf_trace_class_append_env_entry(struct ctf_trace_class *tc, const char *name, - enum ctf_trace_class_env_entry_type type, - const char *str_value, int64_t i_value) -{ - struct ctf_trace_class_env_entry *entry; - - BT_ASSERT(tc); - BT_ASSERT(name); - g_array_set_size(tc->env_entries, tc->env_entries->len + 1); - - entry = &bt_g_array_index(tc->env_entries, struct ctf_trace_class_env_entry, - tc->env_entries->len - 1); - entry->type = type; - _ctf_trace_class_env_entry_init(entry); - g_string_assign(entry->name, name); - - if (str_value) { - g_string_assign(entry->value.str, str_value); - } - - entry->value.i = i_value; -} - -static inline struct ctf_stream_class * -ctf_trace_class_borrow_stream_class_by_id(struct ctf_trace_class *tc, uint64_t id) -{ - uint64_t i; - struct ctf_stream_class *ret_sc = NULL; - - BT_ASSERT_DBG(tc); - - for (i = 0; i < tc->stream_classes->len; i++) { - struct ctf_stream_class *sc = (struct ctf_stream_class *) tc->stream_classes->pdata[i]; - - if (sc->id == id) { - ret_sc = sc; - goto end; - } - } - -end: - return ret_sc; -} - -static inline struct ctf_clock_class * -ctf_trace_class_borrow_clock_class_by_name(struct ctf_trace_class *tc, const char *name) -{ - uint64_t i; - struct ctf_clock_class *ret_cc = NULL; - - BT_ASSERT_DBG(tc); - BT_ASSERT_DBG(name); - - for (i = 0; i < tc->clock_classes->len; i++) { - struct ctf_clock_class *cc = (struct ctf_clock_class *) tc->clock_classes->pdata[i]; - - BT_ASSERT_DBG(cc->name); - if (strcmp(cc->name->str, name) == 0) { - ret_cc = cc; - goto end; - } - } - -end: - return ret_cc; -} - -static inline struct ctf_trace_class_env_entry * -ctf_trace_class_borrow_env_entry_by_index(struct ctf_trace_class *tc, uint64_t index) -{ - BT_ASSERT_DBG(tc); - BT_ASSERT_DBG(index < tc->env_entries->len); - return &bt_g_array_index(tc->env_entries, struct ctf_trace_class_env_entry, index); -} - -static inline struct ctf_trace_class_env_entry * -ctf_trace_class_borrow_env_entry_by_name(struct ctf_trace_class *tc, const char *name) -{ - struct ctf_trace_class_env_entry *ret_entry = NULL; - uint64_t i; - - BT_ASSERT_DBG(tc); - BT_ASSERT_DBG(name); - - for (i = 0; i < tc->env_entries->len; i++) { - struct ctf_trace_class_env_entry *env_entry = - ctf_trace_class_borrow_env_entry_by_index(tc, i); - - if (strcmp(env_entry->name->str, name) == 0) { - ret_entry = env_entry; - goto end; - } - } - -end: - return ret_entry; -} - -#endif /* _CTF_META_H */ diff --git a/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp b/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp deleted file mode 100644 index 2150465b..00000000 --- a/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2017 Philippe Proulx - */ - -#include -#include -#include -#include - -#include - -#define BT_COMP_LOG_SELF_COMP self_comp -#define BT_COMP_LOG_SELF_COMP_CLASS self_comp_class -#define BT_LOG_OUTPUT_LEVEL log_level -#define BT_LOG_TAG "PLUGIN/CTF/META/DECODER-DECODE-PACKET" -#include "logging.hpp" -#include "logging/comp-logging.h" - -#include "common/uuid.h" -#include "compat/memstream.h" - -#include "decoder-packetized-file-stream-to-buf.hpp" -#include "decoder.hpp" - -#define TSDL_MAGIC 0x75d11d57 - -struct ctf_metadata_decoder -{ - struct ctf_visitor_generate_ir *visitor; - bt_uuid_t uuid; - bool is_uuid_set; - int bo; - struct ctf_metadata_decoder_config config; -}; - -struct packet_header -{ - uint32_t magic; - bt_uuid_t uuid; - 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__)); - -static int decode_packet(FILE *in_fp, FILE *out_fp, int byte_order, bool *is_uuid_set, - uint8_t *uuid, bt_logging_level log_level, bt_self_component *self_comp, - bt_self_component_class *self_comp_class) -{ - struct packet_header header; - size_t readlen, writelen, toread; - uint8_t buf[512 + 1]; /* + 1 for debug-mode \0 */ - int ret = 0; - const long offset = ftell(in_fp); - - if (offset < 0) { - BT_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP, - "Failed to get current metadata file position", "."); - goto error; - } - BT_COMP_LOGD("Decoding metadata packet: offset=%ld", offset); - readlen = fread(&header, sizeof(header), 1, in_fp); - if (feof(in_fp) != 0) { - BT_COMP_LOGI("Reached end of file: offset=%ld", ftell(in_fp)); - goto end; - } - if (readlen < 1) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot decode metadata packet: offset=%ld", - offset); - 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) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Metadata packet compression is not supported as of this version: " - "compression-scheme=%u, offset=%ld", - (unsigned int) header.compression_scheme, offset); - goto error; - } - - if (header.encryption_scheme) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Metadata packet encryption is not supported as of this version: " - "encryption-scheme=%u, offset=%ld", - (unsigned int) header.encryption_scheme, offset); - goto error; - } - - if (header.checksum || header.checksum_scheme) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Metadata packet checksum verification is not supported as of this version: " - "checksum-scheme=%u, checksum=%x, offset=%ld", - (unsigned int) header.checksum_scheme, header.checksum, offset); - goto error; - } - - if (!ctf_metadata_decoder_is_packet_version_valid(header.major, header.minor)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid metadata packet version: " - "version=%u.%u, offset=%ld", - header.major, header.minor, offset); - goto error; - } - - /* Set expected trace UUID if not set; otherwise validate it */ - if (is_uuid_set) { - if (!*is_uuid_set) { - bt_uuid_copy(uuid, header.uuid); - *is_uuid_set = true; - } else if (bt_uuid_compare(header.uuid, uuid)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Metadata UUID mismatch between packets of the same stream: " - "packet-uuid=\"" BT_UUID_FMT "\", " - "expected-uuid=\"" BT_UUID_FMT "\", " - "offset=%ld", - BT_UUID_FMT_VALUES(header.uuid), BT_UUID_FMT_VALUES(uuid), offset); - goto error; - } - } - - if ((header.content_size / CHAR_BIT) < sizeof(header)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Bad metadata packet content size: content-size=%u, " - "offset=%ld", - header.content_size, offset); - goto error; - } - - toread = header.content_size / CHAR_BIT - sizeof(header); - - for (;;) { - size_t loop_read; - - loop_read = MIN(sizeof(buf) - 1, toread); - readlen = fread(buf, sizeof(uint8_t), loop_read, in_fp); - if (ferror(in_fp)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot read metadata packet buffer: " - "offset=%ld, read-size=%zu", - ftell(in_fp), loop_read); - goto error; - } - if (readlen > loop_read) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("fread returned more byte than expected: " - "read-size-asked=%zu, read-size-returned=%zu", - loop_read, readlen); - goto error; - } - - writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp); - if (writelen < readlen || ferror(out_fp)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot write decoded metadata text to buffer: " - "read-offset=%ld, write-size=%zu", - ftell(in_fp), readlen); - 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) { - BT_COMP_LOGW_STR("Missing padding at the end of the metadata stream."); - } - break; - } - } - - goto end; - -error: - ret = -1; - -end: - return ret; -} - -int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order, - bool *is_uuid_set, uint8_t *uuid, - bt_logging_level log_level, - bt_self_component *self_comp, - bt_self_component_class *self_comp_class) -{ - 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) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot open memory stream: %s.", strerror(errno)); - goto error; - } - - for (;;) { - if (feof(fp) != 0) { - break; - } - - tret = decode_packet(fp, out_fp, byte_order, is_uuid_set, uuid, log_level, self_comp, - self_comp_class); - if (tret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot decode packet: index=%zu", - packet_index); - goto error; - } - - packet_index++; - } - - /* Make sure the whole string ends with a null character */ - tret = fputc('\0', out_fp); - if (tret == EOF) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot append '\\0' to the decoded metadata buffer."); - goto error; - } - - /* Close stream, which also flushes the buffer */ - ret = bt_close_memstream(buf, &size, out_fp); - /* - * See fclose(3). Further access to out_fp after both success - * and error, even through another bt_close_memstream(), results - * in undefined behavior. Nullify out_fp to ensure we don't - * fclose it twice on error. - */ - out_fp = NULL; - if (ret < 0) { - BT_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP, "Cannot close memory stream", "."); - goto error; - } - - goto end; - -error: - ret = -1; - - if (out_fp) { - if (bt_close_memstream(buf, &size, out_fp)) { - BT_COMP_LOGE_ERRNO("Cannot close memory stream", "."); - } - } - - if (*buf) { - free(*buf); - *buf = NULL; - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp b/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp deleted file mode 100644 index 8d831536..00000000 --- a/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Efficios Inc. - */ - -#ifndef SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF -#define SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF - -#include - -#include - -#include - -int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order, - bool *is_uuid_set, uint8_t *uuid, - bt_logging_level log_level, - bt_self_component *self_comp, - bt_self_component_class *self_comp_class); - -#endif /* SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF */ diff --git a/src/plugins/ctf/common/metadata/decoder.cpp b/src/plugins/ctf/common/metadata/decoder.cpp deleted file mode 100644 index deaeedb4..00000000 --- a/src/plugins/ctf/common/metadata/decoder.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2017 Philippe Proulx - */ - -#include -#include -#include -#include -#include -#include - -#include - -#define BT_COMP_LOG_SELF_COMP (mdec->config.self_comp) -#define BT_COMP_LOG_SELF_COMP_CLASS (mdec->config.self_comp_class) -#define BT_LOG_OUTPUT_LEVEL ((enum bt_log_level) mdec->config.log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/DECODER" -#include "logging.hpp" -#include "logging/comp-logging.h" - -#include "common/assert.h" -#include "common/uuid.h" -#include "compat/memstream.h" - -#include "ast.hpp" -#include "decoder-packetized-file-stream-to-buf.hpp" -#include "decoder.hpp" -#include "parser-wrap.hpp" -#include "scanner.hpp" - -#define TSDL_MAGIC 0x75d11d57 - -struct ctf_metadata_decoder -{ - struct ctf_scanner *scanner; - GString *text; - struct ctf_visitor_generate_ir *visitor; - bt_uuid_t uuid; - bool is_uuid_set; - int bo; - struct ctf_metadata_decoder_config config; - struct meta_log_config log_cfg; - bool has_checked_plaintext_signature; -}; - -struct packet_header -{ - uint32_t magic; - bt_uuid_t uuid; - 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__)); - -int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order, - bt_logging_level log_level, bt_self_component *self_comp) -{ - uint32_t magic; - size_t len; - int ret = 0; - - *is_packetized = false; - len = fread(&magic, sizeof(magic), 1, fp); - if (len != 1) { - BT_COMP_LOG_CUR_LVL( - BT_LOG_INFO, log_level, self_comp, - "Cannot read first metadata packet header: assuming the stream is not packetized."); - ret = -1; - goto end; - } - - if (byte_order) { - if (magic == TSDL_MAGIC) { - *is_packetized = true; - *byte_order = BYTE_ORDER; - } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) { - *is_packetized = true; - *byte_order = BYTE_ORDER == BIG_ENDIAN ? LITTLE_ENDIAN : BIG_ENDIAN; - } - } - -end: - rewind(fp); - - return ret; -} - -struct ctf_metadata_decoder * -ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config) -{ - struct ctf_metadata_decoder *mdec = g_new0(struct ctf_metadata_decoder, 1); - - BT_ASSERT(config); - BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, config->log_level, config->self_comp, - "Creating CTF metadata decoder: " - "clock-class-offset-s=%" PRId64 ", " - "clock-class-offset-ns=%" PRId64, - config->clock_class_offset_s, config->clock_class_offset_ns); - - if (!mdec) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, config->log_level, config->self_comp, - "Failed to allocate one CTF metadata decoder."); - goto end; - } - - mdec->log_cfg.log_level = config->log_level; - mdec->log_cfg.self_comp = config->self_comp; - mdec->log_cfg.self_comp_class = config->self_comp_class; - mdec->scanner = ctf_scanner_alloc(); - if (!mdec->scanner) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot allocate a metadata lexical scanner: " - "mdec-addr=%p", - mdec); - goto error; - } - - mdec->text = g_string_new(NULL); - if (!mdec->text) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one GString: " - "mdec-addr=%p", - mdec); - goto error; - } - - mdec->bo = -1; - mdec->config = *config; - mdec->visitor = ctf_visitor_generate_ir_create(config); - if (!mdec->visitor) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to create a CTF IR metadata AST visitor: " - "mdec-addr=%p", - mdec); - goto error; - } - - BT_COMP_LOGD("Creating CTF metadata decoder: " - "clock-class-offset-s=%" PRId64 ", " - "clock-class-offset-ns=%" PRId64 ", addr=%p", - config->clock_class_offset_s, config->clock_class_offset_ns, mdec); - goto end; - -error: - ctf_metadata_decoder_destroy(mdec); - mdec = NULL; - -end: - return mdec; -} - -void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *mdec) -{ - if (!mdec) { - return; - } - - if (mdec->scanner) { - ctf_scanner_free(mdec->scanner); - } - - if (mdec->text) { - g_string_free(mdec->text, TRUE); - } - - BT_COMP_LOGD("Destroying CTF metadata decoder: addr=%p", mdec); - ctf_visitor_generate_ir_destroy(mdec->visitor); - g_free(mdec); -} - -enum ctf_metadata_decoder_status -ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *mdec, FILE *fp) -{ - enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK; - int ret; - char *buf = NULL; - bool close_fp = false; - long start_pos = -1; - bool is_packetized; - - BT_ASSERT(mdec); - ret = ctf_metadata_decoder_is_packetized(fp, &is_packetized, &mdec->bo, mdec->config.log_level, - mdec->config.self_comp); - if (ret) { - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - if (is_packetized) { - BT_COMP_LOGI("Metadata stream is packetized: mdec-addr=%p", mdec); - ret = ctf_metadata_decoder_packetized_file_stream_to_buf( - fp, &buf, mdec->bo, &mdec->is_uuid_set, mdec->uuid, mdec->config.log_level, - mdec->config.self_comp, mdec->config.self_comp_class); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot decode packetized metadata packets to metadata text: " - "mdec-addr=%p, ret=%d", - mdec, ret); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - if (strlen(buf) == 0) { - /* An empty metadata packet is OK. */ - goto end; - } - - /* Convert the real file pointer to a memory file pointer */ - fp = bt_fmemopen(buf, strlen(buf), "rb"); - close_fp = true; - if (!fp) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot memory-open metadata buffer: %s: " - "mdec-addr=%p", - strerror(errno), mdec); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - } else if (!mdec->has_checked_plaintext_signature) { - unsigned int major, minor; - ssize_t nr_items; - const long init_pos = ftell(fp); - - BT_COMP_LOGI("Metadata stream is plain text: mdec-addr=%p", mdec); - - if (init_pos < 0) { - BT_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP, - "Failed to get current file position", "."); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - /* Check text-only metadata header and version */ - nr_items = fscanf(fp, "/* CTF %10u.%10u", &major, &minor); - if (nr_items < 2) { - BT_COMP_LOGW( - "Missing \"/* CTF major.minor\" signature in plain text metadata file stream: " - "mdec-addr=%p", - mdec); - } - - BT_COMP_LOGI("Found metadata stream version in signature: version=%u.%u", major, minor); - - if (!ctf_metadata_decoder_is_packet_version_valid(major, minor)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Invalid metadata version found in plain text signature: " - "version=%u.%u, mdec-addr=%p", - major, minor, mdec); - status = CTF_METADATA_DECODER_STATUS_INVAL_VERSION; - goto end; - } - - if (fseek(fp, init_pos, SEEK_SET)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot seek metadata file stream to initial position: %s: " - "mdec-addr=%p", - strerror(errno), mdec); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - mdec->has_checked_plaintext_signature = true; - } - -#if YYDEBUG - if (BT_LOG_ON_TRACE) { - yydebug = 1; - } -#endif - - /* Save the file's position: we'll seek back to append the plain text */ - BT_ASSERT(fp); - - if (mdec->config.keep_plain_text) { - start_pos = ftell(fp); - } - - /* Append the metadata text content */ - ret = ctf_scanner_append_ast(mdec->scanner, fp); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot create the metadata AST out of the metadata text: " - "mdec-addr=%p", - mdec); - status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; - goto end; - } - - /* We know it's complete: append plain text */ - if (mdec->config.keep_plain_text) { - BT_ASSERT(start_pos != -1); - ret = fseek(fp, start_pos, SEEK_SET); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to seek file: ret=%d, mdec-addr=%p", - ret, mdec); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - ret = bt_common_append_file_content_to_g_string(mdec->text, fp); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to append to current plain text: " - "ret=%d, mdec-addr=%p", - ret, mdec); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - } - - ret = ctf_visitor_semantic_check(0, &mdec->scanner->ast->root, &mdec->log_cfg); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Validation of the metadata semantics failed: " - "mdec-addr=%p", - mdec); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - if (mdec->config.create_trace_class) { - ret = ctf_visitor_generate_ir_visit_node(mdec->visitor, &mdec->scanner->ast->root); - switch (ret) { - case 0: - /* Success */ - break; - case -EINCOMPLETE: - BT_COMP_LOGD("While visiting metadata AST: incomplete data: " - "mdec-addr=%p", - mdec); - status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; - goto end; - default: - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Failed to visit AST node to create CTF IR objects: " - "mdec-addr=%p, ret=%d", - mdec, ret); - status = CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR; - goto end; - } - } - -end: -#if YYDEBUG - yydebug = 0; -#endif - - if (fp && close_fp) { - if (fclose(fp)) { - BT_COMP_LOGE("Cannot close metadata file stream: " - "mdec-addr=%p", - mdec); - } - } - - free(buf); - - return status; -} - -bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec) -{ - BT_ASSERT_DBG(mdec); - BT_ASSERT_DBG(mdec->config.create_trace_class); - return ctf_visitor_generate_ir_get_ir_trace_class(mdec->visitor); -} - -struct ctf_trace_class * -ctf_metadata_decoder_borrow_ctf_trace_class(struct ctf_metadata_decoder *mdec) -{ - BT_ASSERT_DBG(mdec); - BT_ASSERT_DBG(mdec->config.create_trace_class); - return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor); -} - -const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec) -{ - BT_ASSERT_DBG(mdec); - BT_ASSERT_DBG(mdec->config.keep_plain_text); - return mdec->text->str; -} - -int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec) -{ - BT_ASSERT_DBG(mdec); - return mdec->bo; -} - -int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid) -{ - int ret = 0; - - BT_ASSERT_DBG(mdec); - - if (!mdec->is_uuid_set) { - ret = -1; - goto end; - } - - bt_uuid_copy(uuid, mdec->uuid); - -end: - return ret; -} - -static enum ctf_metadata_decoder_status find_uuid_in_trace_decl(struct ctf_metadata_decoder *mdec, - struct ctf_node *trace_node, - bt_uuid_t uuid) -{ - enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK; - struct ctf_node *entry_node; - struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list; - char *left = NULL; - - bt_list_for_each_entry (entry_node, decl_list, siblings) { - if (entry_node->type == NODE_CTF_EXPRESSION) { - int ret; - - left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left); - if (!left) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot concatenate unary strings."); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - if (strcmp(left, "uuid") == 0) { - ret = ctf_ast_get_unary_uuid(&entry_node->u.ctf_expression.right, uuid, - mdec->config.log_level, mdec->config.self_comp); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid trace's `uuid` attribute."); - status = CTF_METADATA_DECODER_STATUS_ERROR; - goto end; - } - - goto end; - } - - g_free(left); - left = NULL; - } - } - - status = CTF_METADATA_DECODER_STATUS_NONE; - -end: - g_free(left); - return status; -} - -enum ctf_metadata_decoder_status -ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid) -{ - enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; - struct ctf_node *root_node = &mdec->scanner->ast->root; - struct ctf_node *trace_node; - - if (!root_node) { - status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; - goto end; - } - - trace_node = bt_list_entry(root_node->u.root.trace.next, struct ctf_node, siblings); - if (!trace_node) { - status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; - goto end; - } - - status = find_uuid_in_trace_decl(mdec, trace_node, uuid); - -end: - return status; -} diff --git a/src/plugins/ctf/common/metadata/decoder.hpp b/src/plugins/ctf/common/metadata/decoder.hpp deleted file mode 100644 index d4385f4c..00000000 --- a/src/plugins/ctf/common/metadata/decoder.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2017 Philippe Proulx - */ - -#ifndef _METADATA_DECODER_H -#define _METADATA_DECODER_H - -#include -#include - -#include - -#include "common/uuid.h" - -/* CTF metadata decoder status */ -enum ctf_metadata_decoder_status -{ - CTF_METADATA_DECODER_STATUS_OK = 0, - CTF_METADATA_DECODER_STATUS_NONE = 1, - 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, -}; - -/* Decoding configuration */ -struct ctf_metadata_decoder_config -{ - /* Active log level to use */ - bt_logging_level log_level; - - /* - * Component or component class to use for logging (exactly one of - * them must be non-`NULL`); weak - */ - bt_self_component *self_comp; - bt_self_component_class *self_comp_class; - - /* Additional clock class offset to apply */ - int64_t clock_class_offset_s; - int64_t clock_class_offset_ns; - bool force_clock_class_origin_unix_epoch; - - /* True to create trace class objects */ - bool create_trace_class; - - /* - * True to keep the plain text when content is appended with - * ctf_metadata_decoder_append_content(). - */ - bool keep_plain_text; -}; - -/* - * Creates a CTF metadata decoder. - * - * Returns `NULL` on error. - */ -struct ctf_metadata_decoder * -ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config); - -/* - * Destroys a CTF metadata decoder that you created with - * ctf_metadata_decoder_create(). - */ -void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *metadata_decoder); - -/* - * Appends content to the metadata decoder. - * - * This function reads the metadata from the current position of `fp` - * until the end of this file stream. - * - * The metadata can be packetized or not. - * - * The metadata chunk needs to be complete and lexically 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 everything goes as expected, this function returns - * `CTF_METADATA_DECODER_STATUS_OK`. - */ -enum ctf_metadata_decoder_status -ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *metadata_decoder, FILE *fp); - -/* - * Returns the trace IR trace class of this metadata decoder (new - * reference). - * - * Returns `NULL` if there's none yet or if the metadata decoder is not - * configured to create trace classes. - */ -bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec); - -/* - * Returns the CTF IR trace class of this metadata decoder. - * - * Returns `NULL` if there's none yet or if the metadata decoder is not - * configured to create trace classes. - */ -struct ctf_trace_class * -ctf_metadata_decoder_borrow_ctf_trace_class(struct ctf_metadata_decoder *mdec); - -/* - * Checks whether or not a given metadata file stream `fp` is - * packetized, setting `is_packetized` accordingly on success. On - * success, also sets `*byte_order` to the byte order of the first - * packet. - * - * This function uses `log_level` and `self_comp` for logging purposes. - * `self_comp` can be `NULL` if not available. - */ -int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order, - bt_logging_level log_level, bt_self_component *self_comp); - -/* - * Returns the byte order of the decoder's metadata stream as set by the - * last call to ctf_metadata_decoder_append_content(). - * - * Returns -1 if unknown (plain text content). - */ -int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec); - -/* - * Returns the UUID of the decoder's metadata stream as set by the last - * call to ctf_metadata_decoder_append_content(). - */ -int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid); - -/* - * Returns the UUID of the decoder's trace class, if available. - * - * Returns: - * - * * `CTF_METADATA_DECODER_STATUS_OK`: success. - * * `CTF_METADATA_DECODER_STATUS_NONE`: no UUID. - * * `CTF_METADATA_DECODER_STATUS_INCOMPLETE`: missing metadata content. - */ -enum ctf_metadata_decoder_status -ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid); - -/* - * Returns the metadata decoder's current metadata text. - */ -const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec); - -static inline bool ctf_metadata_decoder_is_packet_version_valid(unsigned int major, - unsigned int minor) -{ - return major == 1 && minor == 8; -} - -#endif /* _METADATA_DECODER_H */ diff --git a/src/plugins/ctf/common/metadata/lexer.lpp b/src/plugins/ctf/common/metadata/lexer.lpp deleted file mode 100644 index 7c2d5d38..00000000 --- a/src/plugins/ctf/common/metadata/lexer.lpp +++ /dev/null @@ -1,121 +0,0 @@ -%{ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * - * Common Trace Formal Lexer - */ - -#include -#include - -#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level -#define BT_LOG_TAG "PLUGIN-CTF-METADATA-LEXER" -#include "plugins/ctf/common/metadata/logging.hpp" - -#include "plugins/ctf/common/metadata/ast.hpp" -#include "plugins/ctf/common/metadata/parser-wrap.hpp" -#include "plugins/ctf/common/metadata/scanner.hpp" - -#define YY_FATAL_ERROR(_msg) BT_LOGF_STR(_msg) - -#define PARSE_INTEGER_LITERAL(base) \ - do { \ - errno = 0; \ - yylval->ull = strtoull(yytext, NULL, base); \ - if (errno) { \ - _BT_LOGE_APPEND_CAUSE_LINENO(yylineno, \ - "Cannot parser constant integer: " \ - "base=%d, text=\"%s\"", base, yytext); \ - return CTF_ERROR; \ - } \ - } while (0) -%} - -%x comment_ml comment_sl string_lit char_const -%option reentrant yylineno noyywrap bison-bridge -%option extra-type="struct ctf_scanner *" - /* bison-locations */ -INTEGER_SUFFIX (U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu) -DIGIT [0-9] -NONDIGIT [a-zA-Z_] -HEXDIGIT [0-9A-Fa-f] -OCTALDIGIT [0-7] -UCHARLOWERCASE \\u{HEXDIGIT}{4} -UCHARUPPERCASE \\U{HEXDIGIT}{8} -ID_NONDIGIT {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE} -IDENTIFIER {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})* -%% - - /* - * Using start conditions to deal with comments - * and strings. - */ - -"/*" BEGIN(comment_ml); -[^*\n]* /* eat anything that's not a '*' */ -"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -\n -"*"+"/" BEGIN(INITIAL); - -"//"[^\n]*\n /* skip comment */ - -L?\"(\\.|[^\\"])*\" { if (import_string(yyextra, yylval, yytext, '\"') < 0) return CTF_ERROR; else return CTF_STRING_LITERAL; } -L?\'(\\.|[^\\'])*\' { if (import_string(yyextra, yylval, yytext, '\'') < 0) return CTF_ERROR; else return CTF_CHARACTER_LITERAL; } - -"[" return CTF_LSBRAC; -"]" return CTF_RSBRAC; -"(" return CTF_LPAREN; -")" return CTF_RPAREN; -"{" return CTF_LBRAC; -"}" return CTF_RBRAC; -"->" return CTF_RARROW; -"*" return CTF_STAR; -"+" return CTF_PLUS; -"-" return CTF_MINUS; -"<" return CTF_LT; -">" return CTF_GT; -:= return CTF_TYPEASSIGN; -: return CTF_COLON; -; return CTF_SEMICOLON; -"..." return CTF_DOTDOTDOT; -"." return CTF_DOT; -= return CTF_EQUAL; -"," return CTF_COMMA; -align setstring(yyextra, yylval, yytext); return CTF_TOK_ALIGN; -const setstring(yyextra, yylval, yytext); return CTF_CONST; -char setstring(yyextra, yylval, yytext); return CTF_CHAR; -clock setstring(yyextra, yylval, yytext); return CTF_CLOCK; -double setstring(yyextra, yylval, yytext); return CTF_DOUBLE; -enum setstring(yyextra, yylval, yytext); return CTF_ENUM; -env setstring(yyextra, yylval, yytext); return CTF_ENV; -event setstring(yyextra, yylval, yytext); return CTF_EVENT; -floating_point setstring(yyextra, yylval, yytext); return CTF_FLOATING_POINT; -float setstring(yyextra, yylval, yytext); return CTF_FLOAT; -integer setstring(yyextra, yylval, yytext); return CTF_INTEGER; -int setstring(yyextra, yylval, yytext); return CTF_INT; -long setstring(yyextra, yylval, yytext); return CTF_LONG; -short setstring(yyextra, yylval, yytext); return CTF_SHORT; -signed setstring(yyextra, yylval, yytext); return CTF_SIGNED; -stream setstring(yyextra, yylval, yytext); return CTF_STREAM; -string setstring(yyextra, yylval, yytext); return CTF_STRING; -struct setstring(yyextra, yylval, yytext); return CTF_STRUCT; -trace setstring(yyextra, yylval, yytext); return CTF_TRACE; -callsite setstring(yyextra, yylval, yytext); return CTF_CALLSITE; -typealias setstring(yyextra, yylval, yytext); return CTF_TYPEALIAS; -typedef setstring(yyextra, yylval, yytext); return CTF_TYPEDEF; -unsigned setstring(yyextra, yylval, yytext); return CTF_UNSIGNED; -variant setstring(yyextra, yylval, yytext); return CTF_VARIANT; -void setstring(yyextra, yylval, yytext); return CTF_VOID; -_Bool setstring(yyextra, yylval, yytext); return CTF_BOOL; -_Complex setstring(yyextra, yylval, yytext); return CTF_COMPLEX; -_Imaginary setstring(yyextra, yylval, yytext); return CTF_IMAGINARY; -[1-9]{DIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(10); return CTF_INTEGER_LITERAL; -0{OCTALDIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(8); return CTF_INTEGER_LITERAL; -0[xX]{HEXDIGIT}+{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(16); return CTF_INTEGER_LITERAL; - -{IDENTIFIER} BT_LOGT("Got identifier: id=\"%s\"", yytext); setstring(yyextra, yylval, yytext); if (is_type(yyextra, yytext)) return ID_TYPE; else return IDENTIFIER; -[ \t\r\n] ; /* ignore */ -. _BT_LOGE_APPEND_CAUSE_LINENO(yylineno, "Invalid character: char=\"%c\", val=0x%02x", isprint((unsigned char) yytext[0]) ? yytext[0] : '\0', yytext[0]); return CTF_ERROR; -%% diff --git a/src/plugins/ctf/common/metadata/logging.cpp b/src/plugins/ctf/common/metadata/logging.cpp deleted file mode 100644 index 058a6b4b..00000000 --- a/src/plugins/ctf/common/metadata/logging.cpp +++ /dev/null @@ -1,10 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2017 Jérémie Galarneau - */ - -#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level -#include "logging/log-api.h" - -BT_LOG_INIT_LOG_LEVEL(ctf_plugin_metadata_log_level, "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL"); diff --git a/src/plugins/ctf/common/metadata/logging.hpp b/src/plugins/ctf/common/metadata/logging.hpp deleted file mode 100644 index 234a1d60..00000000 --- a/src/plugins/ctf/common/metadata/logging.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2017 Jérémie Galarneau - */ - -#ifndef CTF_METADATA_LOGGING_H -#define CTF_METADATA_LOGGING_H - -#include - -#include "logging/comp-logging.h" -#include "logging/log.h" - -/* - * This global log level is for the generated lexer and parser: we can't - * use a contextual log level for their "tracing", so they rely on this. - */ -BT_LOG_LEVEL_EXTERN_SYMBOL(ctf_plugin_metadata_log_level); - -/* - * To be used by functions without a context structure to pass all the - * logging configuration at once. - */ -struct meta_log_config -{ - bt_logging_level log_level; - - /* Weak, exactly one of these must be set */ - bt_self_component *self_comp; - bt_self_component_class *self_comp_class; -}; - -#define _BT_LOGT_LINENO(_lineno, _msg, args...) \ - BT_LOGT("At line %u in metadata stream: " _msg, _lineno, ##args) - -#define _BT_LOGW_LINENO(_lineno, _msg, args...) \ - BT_LOGW("At line %u in metadata stream: " _msg, _lineno, ##args) - -#define _BT_LOGE_APPEND_CAUSE_LINENO(_lineno, _msg, args...) \ - do { \ - BT_LOGE("At line %u in metadata stream: " _msg, _lineno, ##args); \ - (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( \ - "CTF metadata parser", "At line %u in metadata stream: " _msg, _lineno, ##args); \ - } while (0) - -#define _BT_COMP_LOGT_LINENO(_lineno, _msg, args...) \ - BT_COMP_LOGT("At line %u in metadata stream: " _msg, _lineno, ##args) - -#define _BT_COMP_LOGW_LINENO(_lineno, _msg, args...) \ - BT_COMP_LOGW("At line %u in metadata stream: " _msg, _lineno, ##args) - -#define _BT_COMP_LOGE_LINENO(_lineno, _msg, args...) \ - BT_COMP_LOGE("At line %u in metadata stream: " _msg, _lineno, ##args) - -#define _BT_COMP_LOGE_APPEND_CAUSE_LINENO(_lineno, _msg, args...) \ - BT_COMP_LOGE_APPEND_CAUSE(BT_COMP_LOG_SELF_COMP, "At line %u in metadata stream: " _msg, \ - _lineno, ##args) - -#define _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(_msg, args...) \ - BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(BT_COMP_LOG_SELF_COMP, BT_COMP_LOG_SELF_COMP_CLASS, \ - _msg, ##args) - -#endif /* CTF_METADATA_LOGGING_H */ diff --git a/src/plugins/ctf/common/metadata/objstack.cpp b/src/plugins/ctf/common/metadata/objstack.cpp deleted file mode 100644 index bdf31e02..00000000 --- a/src/plugins/ctf/common/metadata/objstack.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2013 Mathieu Desnoyers - * - * Common Trace Format Object Stack. - */ - -#include - -#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level -#define BT_LOG_TAG "PLUGIN/CTF/META/OBJSTACK" -#include "logging.hpp" - -#include "common/align.h" -#include "common/list.h" - -#include "objstack.hpp" - -#define OBJSTACK_ALIGN 8 /* Object stack alignment */ -#define OBJSTACK_INIT_LEN 128 -#define OBJSTACK_POISON 0xcc - -struct objstack -{ - struct bt_list_head head; /* list of struct objstack_node */ -}; - -struct objstack_node -{ - struct bt_list_head node; - size_t len; - size_t used_len; - char __attribute__((aligned(OBJSTACK_ALIGN))) data[]; -}; - -struct objstack *objstack_create(void) -{ - struct objstack *objstack; - struct objstack_node *node; - - objstack = (struct objstack *) calloc(1, sizeof(*objstack)); - if (!objstack) { - BT_LOGE_STR("Failed to allocate one object stack."); - return NULL; - } - node = (objstack_node *) calloc(sizeof(struct objstack_node) + OBJSTACK_INIT_LEN, sizeof(char)); - if (!node) { - BT_LOGE_STR("Failed to allocate one object stack node."); - free(objstack); - return NULL; - } - BT_INIT_LIST_HEAD(&objstack->head); - bt_list_add_tail(&node->node, &objstack->head); - node->len = OBJSTACK_INIT_LEN; - return objstack; -} - -static void objstack_node_free(struct objstack_node *node) -{ - size_t offset, len; - char *p; - - if (!node) - return; - p = (char *) node; - len = sizeof(*node) + node->len; - for (offset = 0; offset < len; offset++) - p[offset] = OBJSTACK_POISON; - free(node); -} - -void objstack_destroy(struct objstack *objstack) -{ - struct objstack_node *node, *p; - - if (!objstack) - return; - bt_list_for_each_entry_safe (node, p, &objstack->head, node) { - bt_list_del(&node->node); - objstack_node_free(node); - } - free(objstack); -} - -static struct objstack_node *objstack_append_node(struct objstack *objstack) -{ - struct objstack_node *last_node, *new_node; - - /* Get last node */ - last_node = bt_list_entry(objstack->head.prev, struct objstack_node, node); - - /* Allocate new node with double of size of last node */ - new_node = (objstack_node *) calloc(sizeof(struct objstack_node) + (last_node->len << 1), - sizeof(char)); - if (!new_node) { - BT_LOGE_STR("Failed to allocate one object stack node."); - return NULL; - } - bt_list_add_tail(&new_node->node, &objstack->head); - new_node->len = last_node->len << 1; - return new_node; -} - -void *objstack_alloc(struct objstack *objstack, size_t len) -{ - struct objstack_node *last_node; - void *p; - - len = BT_ALIGN(len, OBJSTACK_ALIGN); - - /* Get last node */ - last_node = bt_list_entry(objstack->head.prev, struct objstack_node, node); - while (last_node->len - last_node->used_len < len) { - last_node = objstack_append_node(objstack); - if (!last_node) { - return NULL; - } - } - p = &last_node->data[last_node->used_len]; - last_node->used_len += len; - return p; -} diff --git a/src/plugins/ctf/common/metadata/objstack.hpp b/src/plugins/ctf/common/metadata/objstack.hpp deleted file mode 100644 index 2c91e140..00000000 --- a/src/plugins/ctf/common/metadata/objstack.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2013 Mathieu Desnoyers - * - * Common Trace Format Object Stack. - */ - -#ifndef _OBJSTACK_H -#define _OBJSTACK_H - -#include - -struct objstack *objstack_create(void); -void objstack_destroy(struct objstack *objstack); - -/* - * Allocate len bytes of zeroed memory. - * Return NULL on error. - */ -void *objstack_alloc(struct objstack *objstack, size_t len); - -#endif /* _OBJSTACK_H */ diff --git a/src/plugins/ctf/common/metadata/parser-wrap.hpp b/src/plugins/ctf/common/metadata/parser-wrap.hpp deleted file mode 100644 index e35c3621..00000000 --- a/src/plugins/ctf/common/metadata/parser-wrap.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 EfficiOS Inc. - */ - -#ifndef BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H -#define BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H - -/* - * Small wrapper around the bison-generated parser.h to conditionally define - * YYDEBUG (and therefore the yydebug declaration). - */ - -#include "logging/log.h" - -#if BT_LOG_ENABLED_TRACE -# define YYDEBUG 1 -# define YYFPRINTF(_stream, _fmt, args...) BT_LOGT(_fmt, ##args) -#else -# define YYDEBUG 0 -#endif - -#define ALLOW_INCLUDE_PARSER_H -#include "plugins/ctf/common/metadata/parser.hpp" -#undef ALLOW_INCLUDE_PARSER_H - -#endif diff --git a/src/plugins/ctf/common/metadata/parser.ypp b/src/plugins/ctf/common/metadata/parser.ypp deleted file mode 100644 index eb6e32c7..00000000 --- a/src/plugins/ctf/common/metadata/parser.ypp +++ /dev/null @@ -1,2607 +0,0 @@ -%{ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 - Mathieu Desnoyers - * - * Common Trace Format Metadata Grammar. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level -#define BT_LOG_TAG "PLUGIN/CTF/META/PARSER" -#include "plugins/ctf/common/metadata/logging.hpp" - -#include "common/list.h" -#include "common/assert.h" - -#include "plugins/ctf/common/metadata/ast.hpp" -#include "plugins/ctf/common/metadata/objstack.hpp" -#include "plugins/ctf/common/metadata/parser-wrap.hpp" - -/* - * Avoid warning about "yynerrs" being unused, seen with bison 3.5.1 + clang 15 - * on Ubuntu 20.04. - */ -BT_DIAG_IGNORE_UNUSED_BUT_SET_VARIABLE - -/* Join two lists, put "add" at the end of "head". */ -static inline void -_bt_list_splice_tail (struct bt_list_head *add, struct bt_list_head *head) -{ - /* Do nothing if the list which gets added is empty. */ - if (add != add->next) { - add->next->prev = head->prev; - add->prev->next = head; - head->prev->next = add->next; - head->prev = add->prev; - } -} - -int yylex(union YYSTYPE *yyval, yyscan_t yyscanner); -int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals); -int yylex_destroy(yyscan_t yyscanner); -void yyrestart(FILE * in_str, yyscan_t yyscanner); -int yyget_lineno(yyscan_t yyscanner); -char *yyget_text(yyscan_t yyscanner); - -/* - * Static node for out of memory errors. Only "type" is used. lineno is - * always left at 0. The rest of the node content can be overwritten, - * but is never used. - */ -static struct ctf_node error_node = { - .parent = nullptr, - .siblings = {}, - .tmp_head = {}, - .lineno = 0, - .visited = 0, - .type = NODE_ERROR, -}; - -const char *node_type(struct ctf_node *node) -{ - switch (node->type) { -#define ENTRY(S) case S: return #S; - FOREACH_CTF_NODES(ENTRY) -#undef ENTRY - }; - - bt_common_abort(); -} - -void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src) -{ - lvalp->s = (char *) objstack_alloc(scanner->objstack, strlen(src) + 1); - strcpy(lvalp->s, src); -} - -static -int str_check(size_t str_len, size_t offset, size_t len) -{ - /* check overflow */ - if (offset + len < offset) - return -1; - if (offset + len > str_len) - return -1; - return 0; -} - -static -int bt_isodigit(int c) -{ - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - return 1; - default: - return 0; - } -} - -static -int parse_base_sequence(const char *src, size_t len, size_t pos, - char *buffer, size_t *buf_len, int base) -{ - const size_t max_char = 3; - int nr_char = 0; - - while (!str_check(len, pos, 1) && nr_char < max_char) { - char c = src[pos++]; - - if (base == 8) { - if (bt_isodigit(c)) - buffer[nr_char++] = c; - else - break; - } else if (base == 16) { - if (isxdigit(c)) - buffer[nr_char++] = c; - else - break; - - } else { - /* Unsupported base */ - return -1; - } - } - BT_ASSERT_DBG(nr_char > 0); - buffer[nr_char] = '\0'; - *buf_len = nr_char; - return 0; -} - -static -int import_basic_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, - size_t len, const char *src, char delim) -{ - size_t pos = 0, dpos = 0; - - if (str_check(len, pos, 1)) - return -1; - if (src[pos++] != delim) - return -1; - - while (src[pos] != delim) { - char c; - - if (str_check(len, pos, 1)) - return -1; - c = src[pos++]; - if (c == '\\') { - if (str_check(len, pos, 1)) - return -1; - c = src[pos++]; - - switch (c) { - case 'a': - c = '\a'; - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case '\\': - c = '\\'; - break; - case '\'': - c = '\''; - break; - case '\"': - c = '\"'; - break; - case '?': - c = '?'; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - char oct_buffer[4]; - size_t oct_len; - - if (parse_base_sequence(src, len, pos - 1, - oct_buffer, &oct_len, 8)) - return -1; - c = strtoul(&oct_buffer[0], NULL, 8); - pos += oct_len - 1; - break; - } - case 'x': - { - char hex_buffer[4]; - size_t hex_len; - - if (parse_base_sequence(src, len, pos, - hex_buffer, &hex_len, 16)) - return -1; - c = strtoul(&hex_buffer[0], NULL, 16); - pos += hex_len; - break; - } - default: - return -1; - } - } - if (str_check(len, dpos, 1)) - return -1; - lvalp->s[dpos++] = c; - } - - if (str_check(len, dpos, 1)) - return -1; - lvalp->s[dpos++] = '\0'; - - if (str_check(len, pos, 1)) - return -1; - if (src[pos++] != delim) - return -1; - - if (str_check(len, pos, 1)) - return -1; - if (src[pos] != '\0') - return -1; - return 0; -} - -int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, - const char *src, char delim) -{ - size_t len; - - len = strlen(src) + 1; - lvalp->s = (char *) objstack_alloc(scanner->objstack, len); - if (src[0] == 'L') { - // TODO: import wide string - _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner), - "wide characters are not supported as of this version: " - "scanner-addr=%p", scanner); - return -1; - } else { - return import_basic_string(scanner, lvalp, len, src, delim); - } -} - -static void init_scope(struct ctf_scanner_scope *scope, - struct ctf_scanner_scope *parent) -{ - scope->parent = parent; - scope->classes = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, NULL); -} - -static void finalize_scope(struct ctf_scanner_scope *scope) -{ - g_hash_table_destroy(scope->classes); -} - -static void push_scope(struct ctf_scanner *scanner) -{ - struct ctf_scanner_scope *ns; - - BT_LOGT("Pushing scope: scanner-addr=%p", scanner); - ns = (ctf_scanner_scope *) malloc(sizeof(struct ctf_scanner_scope)); - init_scope(ns, scanner->cs); - scanner->cs = ns; -} - -static void pop_scope(struct ctf_scanner *scanner) -{ - struct ctf_scanner_scope *os; - - BT_LOGT("Popping scope: scanner-addr=%p", scanner); - os = scanner->cs; - scanner->cs = os->parent; - finalize_scope(os); - free(os); -} - -static int lookup_type(struct ctf_scanner_scope *s, const char *id) -{ - int ret; - - ret = GPOINTER_TO_INT(g_hash_table_lookup(s->classes, id)); - BT_LOGT("Looked up type: scanner-addr=%p, id=\"%s\", ret=%d", - s, id, ret); - return ret; -} - -int is_type(struct ctf_scanner *scanner, const char *id) -{ - struct ctf_scanner_scope *it; - int ret = 0; - - for (it = scanner->cs; it; it = it->parent) { - if (lookup_type(it, id)) { - ret = 1; - break; - } - } - BT_LOGT("Found if ID is type: scanner-addr=%p, id=\"%s\", ret=%d", - scanner, id, ret); - return ret; -} - -static void add_type(struct ctf_scanner *scanner, char *id) -{ - BT_LOGT("Adding type: scanner-addr=%p, id=\"%s\"", - scanner, id); - if (lookup_type(scanner->cs, id)) - return; - g_hash_table_insert(scanner->cs->classes, id, id); -} - -static struct ctf_node *make_node(struct ctf_scanner *scanner, - enum node_type type) -{ - struct ctf_node *node; - - node = (ctf_node *) objstack_alloc(scanner->objstack, sizeof(*node)); - if (!node) { - _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner->scanner), - "failed to allocate one stack entry: " - "scanner-addr=%p", scanner); - return &error_node; - } - node->type = type; - node->lineno = yyget_lineno(scanner->scanner); - BT_INIT_LIST_HEAD(&node->tmp_head); - bt_list_add(&node->siblings, &node->tmp_head); - - switch (type) { - case NODE_ROOT: - node->type = NODE_ERROR; - BT_LOGE("Trying to create root node: scanner-addr=%p", - scanner); - break; - case NODE_EVENT: - BT_INIT_LIST_HEAD(&node->u.event.declaration_list); - break; - case NODE_STREAM: - BT_INIT_LIST_HEAD(&node->u.stream.declaration_list); - break; - case NODE_ENV: - BT_INIT_LIST_HEAD(&node->u.env.declaration_list); - break; - case NODE_TRACE: - BT_INIT_LIST_HEAD(&node->u.trace.declaration_list); - break; - case NODE_CLOCK: - BT_INIT_LIST_HEAD(&node->u.clock.declaration_list); - break; - case NODE_CALLSITE: - BT_INIT_LIST_HEAD(&node->u.callsite.declaration_list); - break; - case NODE_CTF_EXPRESSION: - BT_INIT_LIST_HEAD(&node->u.ctf_expression.left); - BT_INIT_LIST_HEAD(&node->u.ctf_expression.right); - break; - case NODE_UNARY_EXPRESSION: - break; - case NODE_TYPEDEF: - BT_INIT_LIST_HEAD(&node->u.field_class_def.field_class_declarators); - break; - case NODE_TYPEALIAS_TARGET: - BT_INIT_LIST_HEAD(&node->u.field_class_alias_target.field_class_declarators); - break; - case NODE_TYPEALIAS_ALIAS: - BT_INIT_LIST_HEAD(&node->u.field_class_alias_name.field_class_declarators); - break; - case NODE_TYPEALIAS: - break; - case NODE_TYPE_SPECIFIER: - break; - case NODE_TYPE_SPECIFIER_LIST: - BT_INIT_LIST_HEAD(&node->u.field_class_specifier_list.head); - break; - case NODE_POINTER: - break; - case NODE_TYPE_DECLARATOR: - BT_INIT_LIST_HEAD(&node->u.field_class_declarator.pointers); - break; - case NODE_FLOATING_POINT: - BT_INIT_LIST_HEAD(&node->u.floating_point.expressions); - break; - case NODE_INTEGER: - BT_INIT_LIST_HEAD(&node->u.integer.expressions); - break; - case NODE_STRING: - BT_INIT_LIST_HEAD(&node->u.string.expressions); - break; - case NODE_ENUMERATOR: - BT_INIT_LIST_HEAD(&node->u.enumerator.values); - break; - case NODE_ENUM: - BT_INIT_LIST_HEAD(&node->u._enum.enumerator_list); - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - BT_INIT_LIST_HEAD(&node->u.struct_or_variant_declaration.field_class_declarators); - break; - case NODE_VARIANT: - BT_INIT_LIST_HEAD(&node->u.variant.declaration_list); - break; - case NODE_STRUCT: - BT_INIT_LIST_HEAD(&node->u._struct.declaration_list); - BT_INIT_LIST_HEAD(&node->u._struct.min_align); - break; - case NODE_UNKNOWN: - default: - node->type = NODE_ERROR; - BT_LOGE("Unknown node type: scanner-addr=%p, node-type=%d", - scanner, type); - break; - } - - return node; -} - -static int reparent_ctf_expression(struct ctf_node *node, - struct ctf_node *parent) -{ - switch (parent->type) { - case NODE_EVENT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); - break; - case NODE_STREAM: - _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); - break; - case NODE_ENV: - _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); - break; - case NODE_TRACE: - _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); - break; - case NODE_CLOCK: - _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); - break; - case NODE_CALLSITE: - _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); - break; - case NODE_FLOATING_POINT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.floating_point.expressions); - break; - case NODE_INTEGER: - _bt_list_splice_tail(&node->tmp_head, &parent->u.integer.expressions); - break; - case NODE_STRING: - _bt_list_splice_tail(&node->tmp_head, &parent->u.string.expressions); - break; - - case NODE_ROOT: - case NODE_CTF_EXPRESSION: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_TYPE_DECLARATOR: - case NODE_ENUMERATOR: - case NODE_ENUM: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_VARIANT: - case NODE_STRUCT: - case NODE_UNARY_EXPRESSION: - return -EPERM; - - case NODE_UNKNOWN: - default: - BT_LOGE("Unknown node type: node-type=%d", parent->type); - return -EINVAL; - } - return 0; -} - -static int reparent_typedef(struct ctf_node *node, struct ctf_node *parent) -{ - switch (parent->type) { - case NODE_ROOT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list); - break; - case NODE_EVENT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); - break; - case NODE_STREAM: - _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); - break; - case NODE_ENV: - _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); - break; - case NODE_TRACE: - _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); - break; - case NODE_CLOCK: - _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); - break; - case NODE_CALLSITE: - _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); - break; - case NODE_VARIANT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); - break; - case NODE_STRUCT: - _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); - break; - - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_CTF_EXPRESSION: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_TYPE_DECLARATOR: - case NODE_ENUMERATOR: - case NODE_ENUM: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_UNARY_EXPRESSION: - return -EPERM; - - case NODE_UNKNOWN: - default: - BT_LOGE("Unknown node type: node-type=%d", parent->type); - return -EINVAL; - } - return 0; -} - -static int reparent_field_class_alias(struct ctf_node *node, struct ctf_node *parent) -{ - switch (parent->type) { - case NODE_ROOT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list); - break; - case NODE_EVENT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); - break; - case NODE_STREAM: - _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); - break; - case NODE_ENV: - _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); - break; - case NODE_TRACE: - _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); - break; - case NODE_CLOCK: - _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); - break; - case NODE_CALLSITE: - _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); - break; - case NODE_VARIANT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); - break; - case NODE_STRUCT: - _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); - break; - - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_CTF_EXPRESSION: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_TYPE_DECLARATOR: - case NODE_ENUMERATOR: - case NODE_ENUM: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_UNARY_EXPRESSION: - return -EPERM; - - case NODE_UNKNOWN: - default: - BT_LOGE("Unknown node type: node-type=%d", parent->type); - return -EINVAL; - } - return 0; -} - -static int reparent_field_class_specifier(struct ctf_node *node, - struct ctf_node *parent) -{ - switch (parent->type) { - case NODE_TYPE_SPECIFIER_LIST: - _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_specifier_list.head); - break; - - case NODE_TYPE_SPECIFIER: - case NODE_EVENT: - case NODE_STREAM: - case NODE_ENV: - case NODE_TRACE: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_VARIANT: - case NODE_STRUCT: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_TYPE_DECLARATOR: - case NODE_ENUM: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_TYPEALIAS: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_CTF_EXPRESSION: - case NODE_POINTER: - case NODE_ENUMERATOR: - case NODE_UNARY_EXPRESSION: - return -EPERM; - - case NODE_UNKNOWN: - default: - BT_LOGE("Unknown node type: node-type=%d", parent->type); - return -EINVAL; - } - return 0; -} - -static int reparent_field_class_specifier_list(struct ctf_node *node, - struct ctf_node *parent) -{ - switch (parent->type) { - case NODE_ROOT: - bt_list_add_tail(&node->siblings, &parent->u.root.declaration_list); - break; - case NODE_EVENT: - bt_list_add_tail(&node->siblings, &parent->u.event.declaration_list); - break; - case NODE_STREAM: - bt_list_add_tail(&node->siblings, &parent->u.stream.declaration_list); - break; - case NODE_ENV: - bt_list_add_tail(&node->siblings, &parent->u.env.declaration_list); - break; - case NODE_TRACE: - bt_list_add_tail(&node->siblings, &parent->u.trace.declaration_list); - break; - case NODE_CLOCK: - bt_list_add_tail(&node->siblings, &parent->u.clock.declaration_list); - break; - case NODE_CALLSITE: - bt_list_add_tail(&node->siblings, &parent->u.callsite.declaration_list); - break; - case NODE_VARIANT: - bt_list_add_tail(&node->siblings, &parent->u.variant.declaration_list); - break; - case NODE_STRUCT: - bt_list_add_tail(&node->siblings, &parent->u._struct.declaration_list); - break; - case NODE_TYPEDEF: - parent->u.field_class_def.field_class_specifier_list = node; - break; - case NODE_TYPEALIAS_TARGET: - parent->u.field_class_alias_target.field_class_specifier_list = node; - break; - case NODE_TYPEALIAS_ALIAS: - parent->u.field_class_alias_name.field_class_specifier_list = node; - break; - case NODE_ENUM: - parent->u._enum.container_field_class = node; - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - parent->u.struct_or_variant_declaration.field_class_specifier_list = node; - break; - case NODE_TYPE_DECLARATOR: - case NODE_TYPE_SPECIFIER: - case NODE_TYPEALIAS: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_CTF_EXPRESSION: - case NODE_POINTER: - case NODE_ENUMERATOR: - case NODE_UNARY_EXPRESSION: - return -EPERM; - - case NODE_UNKNOWN: - default: - BT_LOGE("Unknown node type: node-type=%d", parent->type); - return -EINVAL; - } - return 0; -} - -static int reparent_field_class_declarator(struct ctf_node *node, - struct ctf_node *parent) -{ - switch (parent->type) { - case NODE_TYPE_DECLARATOR: - parent->u.field_class_declarator.type = TYPEDEC_NESTED; - parent->u.field_class_declarator.u.nested.field_class_declarator = node; - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - _bt_list_splice_tail(&node->tmp_head, &parent->u.struct_or_variant_declaration.field_class_declarators); - break; - case NODE_TYPEDEF: - _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_def.field_class_declarators); - break; - case NODE_TYPEALIAS_TARGET: - _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_target.field_class_declarators); - break; - case NODE_TYPEALIAS_ALIAS: - _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_name.field_class_declarators); - break; - - case NODE_ROOT: - case NODE_EVENT: - case NODE_STREAM: - case NODE_ENV: - case NODE_TRACE: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_VARIANT: - case NODE_STRUCT: - case NODE_TYPEALIAS: - case NODE_ENUM: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_CTF_EXPRESSION: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_ENUMERATOR: - case NODE_UNARY_EXPRESSION: - return -EPERM; - - case NODE_UNKNOWN: - default: - BT_LOGE("Unknown node type: node-type=%d", parent->type); - return -EINVAL; - } - return 0; -} - -/* - * set_parent_node - * - * Link node to parent. Returns 0 on success, -EPERM if it is not permitted to - * create the link declared by the input, -ENOENT if node or parent is NULL, - * -EINVAL if there is an internal structure problem. - */ -static int set_parent_node(struct ctf_node *node, - struct ctf_node *parent) -{ - if (!node || !parent) - return -ENOENT; - - /* Note: Linking to parent will be done only by an external visitor */ - - switch (node->type) { - case NODE_ROOT: - BT_LOGE_STR("Trying to reparent root node."); - return -EINVAL; - - case NODE_EVENT: - if (parent->type == NODE_ROOT) { - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.event); - } else { - return -EPERM; - } - break; - case NODE_STREAM: - if (parent->type == NODE_ROOT) { - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.stream); - } else { - return -EPERM; - } - break; - case NODE_ENV: - if (parent->type == NODE_ROOT) { - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.env); - } else { - return -EPERM; - } - break; - case NODE_TRACE: - if (parent->type == NODE_ROOT) { - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.trace); - } else { - return -EPERM; - } - break; - case NODE_CLOCK: - if (parent->type == NODE_ROOT) { - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.clock); - } else { - return -EPERM; - } - break; - case NODE_CALLSITE: - if (parent->type == NODE_ROOT) { - _bt_list_splice_tail(&node->tmp_head, &parent->u.root.callsite); - } else { - return -EPERM; - } - break; - - case NODE_CTF_EXPRESSION: - return reparent_ctf_expression(node, parent); - case NODE_UNARY_EXPRESSION: - if (parent->type == NODE_TYPE_DECLARATOR) - parent->u.field_class_declarator.bitfield_len = node; - else - return -EPERM; - break; - - case NODE_TYPEDEF: - return reparent_typedef(node, parent); - case NODE_TYPEALIAS_TARGET: - if (parent->type == NODE_TYPEALIAS) - parent->u.field_class_alias.target = node; - else - return -EINVAL; - /* fall-through */ - case NODE_TYPEALIAS_ALIAS: - if (parent->type == NODE_TYPEALIAS) - parent->u.field_class_alias.alias = node; - else - return -EINVAL; - /* fall-through */ - case NODE_TYPEALIAS: - return reparent_field_class_alias(node, parent); - - case NODE_POINTER: - if (parent->type == NODE_TYPE_DECLARATOR) { - _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_declarator.pointers); - } else - return -EPERM; - break; - case NODE_TYPE_DECLARATOR: - return reparent_field_class_declarator(node, parent); - - case NODE_TYPE_SPECIFIER_LIST: - return reparent_field_class_specifier_list(node, parent); - - case NODE_TYPE_SPECIFIER: - return reparent_field_class_specifier(node, parent); - - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_ENUM: - case NODE_VARIANT: - case NODE_STRUCT: - return -EINVAL; /* Dealt with internally within grammar */ - - case NODE_ENUMERATOR: - if (parent->type == NODE_ENUM) { - _bt_list_splice_tail(&node->tmp_head, &parent->u._enum.enumerator_list); - } else { - return -EPERM; - } - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - switch (parent->type) { - case NODE_STRUCT: - _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); - break; - case NODE_VARIANT: - _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); - break; - default: - return -EINVAL; - } - break; - - case NODE_UNKNOWN: - default: - BT_LOGE("Unknown node type: node-type=%d", parent->type); - return -EINVAL; - } - return 0; -} - -static -void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str) -{ - _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner->scanner), - "%s: token=\"%s\"", str, yyget_text(scanner->scanner)); -} - -#define reparent_error(scanner, str) \ -do { \ - yyerror(scanner, scanner->scanner, YY_("reparent_error: " str)); \ - YYERROR; \ -} while (0) - -static struct ctf_ast *ctf_ast_alloc(struct ctf_scanner *scanner) -{ - struct ctf_ast *ast; - - ast = (ctf_ast *) objstack_alloc(scanner->objstack, sizeof(*ast)); - if (!ast) - return NULL; - ast->root.type = NODE_ROOT; - BT_INIT_LIST_HEAD(&ast->root.tmp_head); - BT_INIT_LIST_HEAD(&ast->root.u.root.declaration_list); - BT_INIT_LIST_HEAD(&ast->root.u.root.trace); - BT_INIT_LIST_HEAD(&ast->root.u.root.env); - BT_INIT_LIST_HEAD(&ast->root.u.root.stream); - BT_INIT_LIST_HEAD(&ast->root.u.root.event); - BT_INIT_LIST_HEAD(&ast->root.u.root.clock); - BT_INIT_LIST_HEAD(&ast->root.u.root.callsite); - return ast; -} - -int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input) -{ - /* Start processing new stream */ - yyrestart(input, scanner->scanner); - return yyparse(scanner, scanner->scanner); -} - -struct ctf_scanner *ctf_scanner_alloc(void) -{ - struct ctf_scanner *scanner; - int ret; - - scanner = (ctf_scanner *) malloc(sizeof(*scanner)); - if (!scanner) - return NULL; - memset(scanner, 0, sizeof(*scanner)); - ret = yylex_init_extra(scanner, &scanner->scanner); - if (ret) { - BT_LOGE("yylex_init_extra() failed: ret=%d", ret); - goto cleanup_scanner; - } - scanner->objstack = objstack_create(); - if (!scanner->objstack) - goto cleanup_lexer; - scanner->ast = ctf_ast_alloc(scanner); - if (!scanner->ast) - goto cleanup_objstack; - init_scope(&scanner->root_scope, NULL); - scanner->cs = &scanner->root_scope; - - return scanner; - -cleanup_objstack: - objstack_destroy(scanner->objstack); -cleanup_lexer: - ret = yylex_destroy(scanner->scanner); - if (!ret) - BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d", - scanner, ret); -cleanup_scanner: - free(scanner); - return NULL; -} - -void ctf_scanner_free(struct ctf_scanner *scanner) -{ - int ret; - - if (!scanner) - return; - - struct ctf_scanner_scope *scope = scanner->cs; - - do { - struct ctf_scanner_scope *parent = scope->parent; - finalize_scope(scope); - - /* - * The root scope is allocated within the ctf_scanner structure, - * do doesn't need freeing. All others are allocated on their - * own. - */ - if (scope != &scanner->root_scope) - free(scope); - - scope = parent; - } while (scope); - - objstack_destroy(scanner->objstack); - ret = yylex_destroy(scanner->scanner); - if (ret) - BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d", - scanner, ret); - free(scanner); -} - -/* - * The bison-provided version of strlen (yystrlen) generates a benign - * -Wnull-dereference warning. That version is used when building on cygwin, - * for example, but you can also enable it by hand (to test) by removing the - * preprocessor conditional around it. - * - * Define yystrlen such that it will always use strlen. As far as we know, - * strlen provided by all the platforms we use is reliable. - */ -#define yystrlen strlen - -%} - -/* - * This ends up in parser.h and makes sure those who want to include it pass - * through parser-wrap.h. - */ -%code requires { -#ifndef ALLOW_INCLUDE_PARSER_H -# error "Don't include parser.h directly, include parser-wrap.h instead." -#endif - -#include "plugins/ctf/common/metadata/scanner.hpp" -} - -%code provides { - void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src); - - int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim); -} - -%define api.pure - /* %locations */ -%error-verbose -%parse-param {struct ctf_scanner *scanner} -%parse-param {yyscan_t yyscanner} -%lex-param {yyscan_t yyscanner} -/* - * Expect two shift-reduce conflicts. Caused by enum name-opt : type {} - * vs struct { int :value; } (unnamed bit-field). The default is to - * shift, so whenever we encounter an enumeration, we are doing the - * proper thing (shift). It is illegal to declare an enumeration - * "bit-field", so it is OK if this situation ends up in a parsing - * error. - */ -%expect 2 -%start file -%token CTF_INTEGER_LITERAL CTF_STRING_LITERAL CTF_CHARACTER_LITERAL CTF_LSBRAC CTF_RSBRAC CTF_LPAREN CTF_RPAREN CTF_LBRAC CTF_RBRAC CTF_RARROW CTF_STAR CTF_PLUS CTF_MINUS CTF_LT CTF_GT CTF_TYPEASSIGN CTF_COLON CTF_SEMICOLON CTF_DOTDOTDOT CTF_DOT CTF_EQUAL CTF_COMMA CTF_CONST CTF_CHAR CTF_DOUBLE CTF_ENUM CTF_ENV CTF_EVENT CTF_FLOATING_POINT CTF_FLOAT CTF_INTEGER CTF_INT CTF_LONG CTF_SHORT CTF_SIGNED CTF_STREAM CTF_STRING CTF_STRUCT CTF_TRACE CTF_CALLSITE CTF_CLOCK CTF_TYPEALIAS CTF_TYPEDEF CTF_UNSIGNED CTF_VARIANT CTF_VOID CTF_BOOL CTF_COMPLEX CTF_IMAGINARY CTF_TOK_ALIGN -%token IDENTIFIER ID_TYPE -%token CTF_ERROR -%union -{ - long long ll; - unsigned long long ull; - char c; - char *s; - struct ctf_node *n; -} - -%type CTF_STRING_LITERAL CTF_CHARACTER_LITERAL - -%type keywords - -%type CTF_INTEGER_LITERAL -%type postfix_expression unary_expression unary_expression_or_range - -%type declaration -%type event_declaration -%type stream_declaration -%type env_declaration -%type trace_declaration -%type clock_declaration -%type callsite_declaration -%type integer_declaration_specifiers -%type declaration_specifiers -%type alias_declaration_specifiers - -%type field_class_declarator_list -%type integer_field_class_specifier -%type field_class_specifier -%type struct_class_specifier -%type variant_field_class_specifier -%type enum_field_class_specifier -%type struct_or_variant_declaration_list -%type struct_or_variant_declaration -%type struct_or_variant_declarator_list -%type struct_or_variant_declarator -%type enumerator_list -%type enumerator -%type abstract_declarator_list -%type abstract_declarator -%type direct_abstract_declarator -%type alias_abstract_declarator_list -%type alias_abstract_declarator -%type direct_alias_abstract_declarator -%type declarator -%type direct_declarator -%type field_class_declarator -%type direct_field_class_declarator -%type pointer -%type ctf_assignment_expression_list -%type ctf_assignment_expression - -%% - -file: - declaration - { - if (set_parent_node($1, &ctf_scanner_get_ast(scanner)->root)) - reparent_error(scanner, "error reparenting to root"); - } - | file declaration - { - if (set_parent_node($2, &ctf_scanner_get_ast(scanner)->root)) - reparent_error(scanner, "error reparenting to root"); - } - ; - -keywords: - CTF_VOID - { $$ = yylval.s; } - | CTF_CHAR - { $$ = yylval.s; } - | CTF_SHORT - { $$ = yylval.s; } - | CTF_INT - { $$ = yylval.s; } - | CTF_LONG - { $$ = yylval.s; } - | CTF_FLOAT - { $$ = yylval.s; } - | CTF_DOUBLE - { $$ = yylval.s; } - | CTF_SIGNED - { $$ = yylval.s; } - | CTF_UNSIGNED - { $$ = yylval.s; } - | CTF_BOOL - { $$ = yylval.s; } - | CTF_COMPLEX - { $$ = yylval.s; } - | CTF_IMAGINARY - { $$ = yylval.s; } - | CTF_FLOATING_POINT - { $$ = yylval.s; } - | CTF_INTEGER - { $$ = yylval.s; } - | CTF_STRING - { $$ = yylval.s; } - | CTF_ENUM - { $$ = yylval.s; } - | CTF_VARIANT - { $$ = yylval.s; } - | CTF_STRUCT - { $$ = yylval.s; } - | CTF_CONST - { $$ = yylval.s; } - | CTF_TYPEDEF - { $$ = yylval.s; } - | CTF_EVENT - { $$ = yylval.s; } - | CTF_STREAM - { $$ = yylval.s; } - | CTF_ENV - { $$ = yylval.s; } - | CTF_TRACE - { $$ = yylval.s; } - | CTF_CLOCK - { $$ = yylval.s; } - | CTF_CALLSITE - { $$ = yylval.s; } - | CTF_TOK_ALIGN - { $$ = yylval.s; } - ; - - -/* 2: Phrase structure grammar */ - -postfix_expression: - IDENTIFIER - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - } - | ID_TYPE - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - } - | keywords - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - } - | CTF_INTEGER_LITERAL - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_UNSIGNED_CONSTANT; - $$->u.unary_expression.u.unsigned_constant = $1; - } - | CTF_STRING_LITERAL - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = $1; - } - | CTF_CHARACTER_LITERAL - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = $1; - } - | CTF_LPAREN unary_expression CTF_RPAREN - { - $$ = $2; - } - | postfix_expression CTF_LSBRAC unary_expression CTF_RSBRAC - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_SBRAC; - $$->u.unary_expression.u.sbrac_exp = $3; - bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); - bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); - } - | postfix_expression CTF_DOT IDENTIFIER - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - $$->u.unary_expression.link = UNARY_DOTLINK; - bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); - bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); - } - | postfix_expression CTF_DOT ID_TYPE - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - $$->u.unary_expression.link = UNARY_DOTLINK; - bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); - bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); - } - | postfix_expression CTF_DOT keywords - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - $$->u.unary_expression.link = UNARY_DOTLINK; - bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); - bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); - } - | postfix_expression CTF_RARROW IDENTIFIER - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - $$->u.unary_expression.link = UNARY_ARROWLINK; - bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); - bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); - } - | postfix_expression CTF_RARROW ID_TYPE - { - $$ = make_node(scanner, NODE_UNARY_EXPRESSION); - $$->u.unary_expression.type = UNARY_STRING; - $$->u.unary_expression.u.string = yylval.s; - $$->u.unary_expression.link = UNARY_ARROWLINK; - bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); - bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); - } - ; - -unary_expression: - postfix_expression - { $$ = $1; } - | CTF_PLUS postfix_expression - { - $$ = $2; - if ($$->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT - && $$->u.unary_expression.type != UNARY_SIGNED_CONSTANT) { - reparent_error(scanner, "expecting numeric constant"); - } - } - | CTF_MINUS postfix_expression - { - $$ = $2; - if ($$->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT) { - $$->u.unary_expression.type = UNARY_SIGNED_CONSTANT; - $$->u.unary_expression.u.signed_constant = - -($$->u.unary_expression.u.unsigned_constant); - } else if ($$->u.unary_expression.type == UNARY_SIGNED_CONSTANT) { - $$->u.unary_expression.u.signed_constant = - -($$->u.unary_expression.u.signed_constant); - } else { - reparent_error(scanner, "expecting numeric constant"); - } - } - ; - -unary_expression_or_range: - unary_expression CTF_DOTDOTDOT unary_expression - { - $$ = $1; - _bt_list_splice_tail(&($3)->tmp_head, &($$)->tmp_head); - $3->u.unary_expression.link = UNARY_DOTDOTDOT; - } - | unary_expression - { $$ = $1; } - ; - -/* 2.2: Declarations */ - -declaration: - declaration_specifiers CTF_SEMICOLON - { $$ = $1; } - | event_declaration - { $$ = $1; } - | stream_declaration - { $$ = $1; } - | env_declaration - { $$ = $1; } - | trace_declaration - { $$ = $1; } - | clock_declaration - { $$ = $1; } - | callsite_declaration - { $$ = $1; } - | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEDEF); - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_def.field_class_specifier_list = list; - _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEDEF); - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_def.field_class_specifier_list = list; - _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEDEF); - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_def.field_class_specifier_list = list; - _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEALIAS); - $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); - $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; - _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; - _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); - } - ; - -event_declaration: - event_declaration_begin event_declaration_end - { - $$ = make_node(scanner, NODE_EVENT); - } - | event_declaration_begin ctf_assignment_expression_list event_declaration_end - { - $$ = make_node(scanner, NODE_EVENT); - if (set_parent_node($2, $$)) - reparent_error(scanner, "event_declaration"); - } - ; - -event_declaration_begin: - CTF_EVENT CTF_LBRAC - { push_scope(scanner); } - ; - -event_declaration_end: - CTF_RBRAC CTF_SEMICOLON - { pop_scope(scanner); } - ; - - -stream_declaration: - stream_declaration_begin stream_declaration_end - { - $$ = make_node(scanner, NODE_STREAM); - } - | stream_declaration_begin ctf_assignment_expression_list stream_declaration_end - { - $$ = make_node(scanner, NODE_STREAM); - if (set_parent_node($2, $$)) - reparent_error(scanner, "stream_declaration"); - } - ; - -stream_declaration_begin: - CTF_STREAM CTF_LBRAC - { push_scope(scanner); } - ; - -stream_declaration_end: - CTF_RBRAC CTF_SEMICOLON - { pop_scope(scanner); } - ; - -env_declaration: - env_declaration_begin env_declaration_end - { - $$ = make_node(scanner, NODE_ENV); - } - | env_declaration_begin ctf_assignment_expression_list env_declaration_end - { - $$ = make_node(scanner, NODE_ENV); - if (set_parent_node($2, $$)) - reparent_error(scanner, "env declaration"); - } - ; - -env_declaration_begin: - CTF_ENV CTF_LBRAC - { push_scope(scanner); } - ; - -env_declaration_end: - CTF_RBRAC CTF_SEMICOLON - { pop_scope(scanner); } - ; - -trace_declaration: - trace_declaration_begin trace_declaration_end - { - $$ = make_node(scanner, NODE_TRACE); - } - | trace_declaration_begin ctf_assignment_expression_list trace_declaration_end - { - $$ = make_node(scanner, NODE_TRACE); - if (set_parent_node($2, $$)) - reparent_error(scanner, "trace_declaration"); - } - ; - -trace_declaration_begin: - CTF_TRACE CTF_LBRAC - { push_scope(scanner); } - ; - -trace_declaration_end: - CTF_RBRAC CTF_SEMICOLON - { pop_scope(scanner); } - ; - -clock_declaration: - CTF_CLOCK clock_declaration_begin clock_declaration_end - { - $$ = make_node(scanner, NODE_CLOCK); - } - | CTF_CLOCK clock_declaration_begin ctf_assignment_expression_list clock_declaration_end - { - $$ = make_node(scanner, NODE_CLOCK); - if (set_parent_node($3, $$)) - reparent_error(scanner, "trace_declaration"); - } - ; - -clock_declaration_begin: - CTF_LBRAC - { push_scope(scanner); } - ; - -clock_declaration_end: - CTF_RBRAC CTF_SEMICOLON - { pop_scope(scanner); } - ; - -callsite_declaration: - CTF_CALLSITE callsite_declaration_begin callsite_declaration_end - { - $$ = make_node(scanner, NODE_CALLSITE); - } - | CTF_CALLSITE callsite_declaration_begin ctf_assignment_expression_list callsite_declaration_end - { - $$ = make_node(scanner, NODE_CALLSITE); - if (set_parent_node($3, $$)) - reparent_error(scanner, "trace_declaration"); - } - ; - -callsite_declaration_begin: - CTF_LBRAC - { push_scope(scanner); } - ; - -callsite_declaration_end: - CTF_RBRAC CTF_SEMICOLON - { pop_scope(scanner); } - ; - -integer_declaration_specifiers: - CTF_CONST - { - struct ctf_node *node; - - $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_CONST; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | integer_field_class_specifier - { - struct ctf_node *node; - - $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - node = $1; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | integer_declaration_specifiers CTF_CONST - { - struct ctf_node *node; - - $$ = $1; - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_CONST; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | integer_declaration_specifiers integer_field_class_specifier - { - $$ = $1; - bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); - } - ; - -declaration_specifiers: - CTF_CONST - { - struct ctf_node *node; - - $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_CONST; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | field_class_specifier - { - struct ctf_node *node; - - $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - node = $1; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | declaration_specifiers CTF_CONST - { - struct ctf_node *node; - - $$ = $1; - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_CONST; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | declaration_specifiers field_class_specifier - { - $$ = $1; - bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); - } - ; - -field_class_declarator_list: - field_class_declarator - { $$ = $1; } - | field_class_declarator_list CTF_COMMA field_class_declarator - { - $$ = $1; - bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); - } - ; - -integer_field_class_specifier: - CTF_CHAR - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_CHAR; - } - | CTF_SHORT - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_SHORT; - } - | CTF_INT - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_INT; - } - | CTF_LONG - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_LONG; - } - | CTF_SIGNED - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_SIGNED; - } - | CTF_UNSIGNED - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED; - } - | CTF_BOOL - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_BOOL; - } - | ID_TYPE - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE; - $$->u.field_class_specifier.id_type = yylval.s; - } - | CTF_INTEGER CTF_LBRAC CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_INTEGER; - $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); - } - | CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_INTEGER; - $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); - if (set_parent_node($3, $$->u.field_class_specifier.node)) - reparent_error(scanner, "integer reparent error"); - } - ; - -field_class_specifier: - CTF_VOID - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_VOID; - } - | CTF_CHAR - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_CHAR; - } - | CTF_SHORT - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_SHORT; - } - | CTF_INT - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_INT; - } - | CTF_LONG - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_LONG; - } - | CTF_FLOAT - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_FLOAT; - } - | CTF_DOUBLE - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_DOUBLE; - } - | CTF_SIGNED - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_SIGNED; - } - | CTF_UNSIGNED - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED; - } - | CTF_BOOL - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_BOOL; - } - | CTF_COMPLEX - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_COMPLEX; - } - | CTF_IMAGINARY - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_IMAGINARY; - } - | ID_TYPE - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE; - $$->u.field_class_specifier.id_type = yylval.s; - } - | CTF_FLOATING_POINT CTF_LBRAC CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT; - $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT); - } - | CTF_FLOATING_POINT CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT; - $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT); - if (set_parent_node($3, $$->u.field_class_specifier.node)) - reparent_error(scanner, "floating point reparent error"); - } - | CTF_INTEGER CTF_LBRAC CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_INTEGER; - $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); - } - | CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_INTEGER; - $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); - if (set_parent_node($3, $$->u.field_class_specifier.node)) - reparent_error(scanner, "integer reparent error"); - } - | CTF_STRING - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_STRING; - $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); - } - | CTF_STRING CTF_LBRAC CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_STRING; - $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); - } - | CTF_STRING CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_STRING; - $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); - if (set_parent_node($3, $$->u.field_class_specifier.node)) - reparent_error(scanner, "string reparent error"); - } - | CTF_ENUM enum_field_class_specifier - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_ENUM; - $$->u.field_class_specifier.node = $2; - } - | CTF_VARIANT variant_field_class_specifier - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_VARIANT; - $$->u.field_class_specifier.node = $2; - } - | CTF_STRUCT struct_class_specifier - { - $$ = make_node(scanner, NODE_TYPE_SPECIFIER); - $$->u.field_class_specifier.type = TYPESPEC_STRUCT; - $$->u.field_class_specifier.node = $2; - } - ; - -struct_class_specifier: - struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 1; - if ($2 && set_parent_node($2, $$)) - reparent_error(scanner, "struct reparent error"); - } - | IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 1; - $$->u._struct.name = $1; - if ($3 && set_parent_node($3, $$)) - reparent_error(scanner, "struct reparent error"); - } - | ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 1; - $$->u._struct.name = $1; - if ($3 && set_parent_node($3, $$)) - reparent_error(scanner, "struct reparent error"); - } - | IDENTIFIER - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 0; - $$->u._struct.name = $1; - } - | ID_TYPE - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 0; - $$->u._struct.name = $1; - } - | struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 1; - bt_list_add_tail(&($6)->siblings, &$$->u._struct.min_align); - if ($2 && set_parent_node($2, $$)) - reparent_error(scanner, "struct reparent error"); - } - | IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 1; - $$->u._struct.name = $1; - bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align); - if ($3 && set_parent_node($3, $$)) - reparent_error(scanner, "struct reparent error"); - } - | ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN - { - $$ = make_node(scanner, NODE_STRUCT); - $$->u._struct.has_body = 1; - $$->u._struct.name = $1; - bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align); - if ($3 && set_parent_node($3, $$)) - reparent_error(scanner, "struct reparent error"); - } - ; - -struct_declaration_begin: - CTF_LBRAC - { push_scope(scanner); } - ; - -struct_declaration_end: - CTF_RBRAC - { pop_scope(scanner); } - ; - -variant_field_class_specifier: - variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - if ($2 && set_parent_node($2, $$)) - reparent_error(scanner, "variant reparent error"); - } - | CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.choice = $2; - if ($5 && set_parent_node($5, $$)) - reparent_error(scanner, "variant reparent error"); - } - | CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.choice = $2; - if ($5 && set_parent_node($5, $$)) - reparent_error(scanner, "variant reparent error"); - } - | IDENTIFIER variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.name = $1; - if ($3 && set_parent_node($3, $$)) - reparent_error(scanner, "variant reparent error"); - } - | IDENTIFIER CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - if ($6 && set_parent_node($6, $$)) - reparent_error(scanner, "variant reparent error"); - } - | IDENTIFIER CTF_LT IDENTIFIER CTF_GT - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 0; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - } - | IDENTIFIER CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - if ($6 && set_parent_node($6, $$)) - reparent_error(scanner, "variant reparent error"); - } - | IDENTIFIER CTF_LT ID_TYPE CTF_GT - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 0; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - } - | ID_TYPE variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.name = $1; - if ($3 && set_parent_node($3, $$)) - reparent_error(scanner, "variant reparent error"); - } - | ID_TYPE CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - if ($6 && set_parent_node($6, $$)) - reparent_error(scanner, "variant reparent error"); - } - | ID_TYPE CTF_LT IDENTIFIER CTF_GT - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 0; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - } - | ID_TYPE CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 1; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - if ($6 && set_parent_node($6, $$)) - reparent_error(scanner, "variant reparent error"); - } - | ID_TYPE CTF_LT ID_TYPE CTF_GT - { - $$ = make_node(scanner, NODE_VARIANT); - $$->u.variant.has_body = 0; - $$->u.variant.name = $1; - $$->u.variant.choice = $3; - } - ; - -variant_declaration_begin: - CTF_LBRAC - { push_scope(scanner); } - ; - -variant_declaration_end: - CTF_RBRAC - { pop_scope(scanner); } - ; - -enum_field_class_specifier: - CTF_LBRAC enumerator_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list); - } - | CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - ($$)->u._enum.container_field_class = $2; - _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list); - } - | IDENTIFIER CTF_LBRAC enumerator_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); - } - | IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - ($$)->u._enum.container_field_class = $3; - _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); - } - | ID_TYPE CTF_LBRAC enumerator_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); - } - | ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - ($$)->u._enum.container_field_class = $3; - _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); - } - | CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list); - } - | CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - ($$)->u._enum.container_field_class = $2; - _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list); - } - | IDENTIFIER CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); - } - | IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - ($$)->u._enum.container_field_class = $3; - _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); - } - | IDENTIFIER - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 0; - $$->u._enum.enum_id = $1; - } - | ID_TYPE CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); - } - | ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 1; - $$->u._enum.enum_id = $1; - ($$)->u._enum.container_field_class = $3; - _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); - } - | ID_TYPE - { - $$ = make_node(scanner, NODE_ENUM); - $$->u._enum.has_body = 0; - $$->u._enum.enum_id = $1; - } - ; - -struct_or_variant_declaration_list: - /* empty */ - { $$ = NULL; } - | struct_or_variant_declaration_list struct_or_variant_declaration - { - if ($1) { - $$ = $1; - bt_list_add_tail(&($2)->siblings, &($$)->tmp_head); - } else { - $$ = $2; - bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); - } - } - ; - -struct_or_variant_declaration: - declaration_specifiers struct_or_variant_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - $$ = make_node(scanner, NODE_STRUCT_OR_VARIANT_DECLARATION); - ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; - _bt_list_splice_tail(&($2)->tmp_head, &($$)->u.struct_or_variant_declaration.field_class_declarators); - } - | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEDEF); - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_def.field_class_specifier_list = list; - _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEDEF); - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_def.field_class_specifier_list = list; - _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - $$ = make_node(scanner, NODE_TYPEDEF); - ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEALIAS); - $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); - $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; - _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; - _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); - } - ; - -alias_declaration_specifiers: - CTF_CONST - { - struct ctf_node *node; - - $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_CONST; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | field_class_specifier - { - struct ctf_node *node; - - $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - node = $1; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | IDENTIFIER - { - struct ctf_node *node; - - add_type(scanner, $1); - $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_ID_TYPE; - node->u.field_class_specifier.id_type = yylval.s; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | alias_declaration_specifiers CTF_CONST - { - struct ctf_node *node; - - $$ = $1; - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_CONST; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - | alias_declaration_specifiers field_class_specifier - { - $$ = $1; - bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); - } - | alias_declaration_specifiers IDENTIFIER - { - struct ctf_node *node; - - add_type(scanner, $2); - $$ = $1; - node = make_node(scanner, NODE_TYPE_SPECIFIER); - node->u.field_class_specifier.type = TYPESPEC_ID_TYPE; - node->u.field_class_specifier.id_type = yylval.s; - bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); - } - ; - -struct_or_variant_declarator_list: - struct_or_variant_declarator - { $$ = $1; } - | struct_or_variant_declarator_list CTF_COMMA struct_or_variant_declarator - { - $$ = $1; - bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); - } - ; - -struct_or_variant_declarator: - declarator - { $$ = $1; } - | CTF_COLON unary_expression - { $$ = $2; } - | declarator CTF_COLON unary_expression - { - $$ = $1; - if (set_parent_node($3, $1)) - reparent_error(scanner, "struct_or_variant_declarator"); - } - ; - -enumerator_list: - enumerator - { $$ = $1; } - | enumerator_list CTF_COMMA enumerator - { - $$ = $1; - bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); - } - ; - -enumerator: - IDENTIFIER - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - } - | ID_TYPE - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - } - | keywords - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - } - | CTF_STRING_LITERAL - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - } - | IDENTIFIER CTF_EQUAL unary_expression_or_range - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); - } - | ID_TYPE CTF_EQUAL unary_expression_or_range - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); - } - | keywords CTF_EQUAL unary_expression_or_range - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); - } - | CTF_STRING_LITERAL CTF_EQUAL unary_expression_or_range - { - $$ = make_node(scanner, NODE_ENUMERATOR); - $$->u.enumerator.id = $1; - bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); - } - ; - -abstract_declarator_list: - abstract_declarator - { $$ = $1; } - | abstract_declarator_list CTF_COMMA abstract_declarator - { - $$ = $1; - bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); - } - ; - -abstract_declarator: - direct_abstract_declarator - { $$ = $1; } - | pointer direct_abstract_declarator - { - $$ = $2; - bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); - } - ; - -direct_abstract_declarator: - /* empty */ - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_ID; - /* id is NULL */ - } - | IDENTIFIER - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_ID; - $$->u.field_class_declarator.u.id = $1; - } - | CTF_LPAREN abstract_declarator CTF_RPAREN - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $2; - } - | direct_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $1; - BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); - } - | direct_abstract_declarator CTF_LSBRAC CTF_RSBRAC - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $1; - $$->u.field_class_declarator.u.nested.abstract_array = 1; - } - ; - -alias_abstract_declarator_list: - alias_abstract_declarator - { $$ = $1; } - | alias_abstract_declarator_list CTF_COMMA alias_abstract_declarator - { - $$ = $1; - bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); - } - ; - -alias_abstract_declarator: - direct_alias_abstract_declarator - { $$ = $1; } - | pointer direct_alias_abstract_declarator - { - $$ = $2; - bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); - } - ; - -direct_alias_abstract_declarator: - /* empty */ - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_ID; - /* id is NULL */ - } - | CTF_LPAREN alias_abstract_declarator CTF_RPAREN - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $2; - } - | direct_alias_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $1; - BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); - } - | direct_alias_abstract_declarator CTF_LSBRAC CTF_RSBRAC - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $1; - $$->u.field_class_declarator.u.nested.abstract_array = 1; - } - ; - -declarator: - direct_declarator - { $$ = $1; } - | pointer direct_declarator - { - $$ = $2; - bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); - } - ; - -direct_declarator: - IDENTIFIER - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_ID; - $$->u.field_class_declarator.u.id = $1; - } - | CTF_LPAREN declarator CTF_RPAREN - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $2; - } - | direct_declarator CTF_LSBRAC unary_expression CTF_RSBRAC - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $1; - BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); - } - ; - -field_class_declarator: - direct_field_class_declarator - { $$ = $1; } - | pointer direct_field_class_declarator - { - $$ = $2; - bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); - } - ; - -direct_field_class_declarator: - IDENTIFIER - { - add_type(scanner, $1); - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_ID; - $$->u.field_class_declarator.u.id = $1; - } - | CTF_LPAREN field_class_declarator CTF_RPAREN - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $2; - } - | direct_field_class_declarator CTF_LSBRAC unary_expression CTF_RSBRAC - { - $$ = make_node(scanner, NODE_TYPE_DECLARATOR); - $$->u.field_class_declarator.type = TYPEDEC_NESTED; - $$->u.field_class_declarator.u.nested.field_class_declarator = $1; - BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); - } - ; - -pointer: - CTF_STAR - { - $$ = make_node(scanner, NODE_POINTER); - } - | CTF_STAR pointer - { - $$ = make_node(scanner, NODE_POINTER); - bt_list_splice(&($2)->tmp_head, &($$)->tmp_head); - } - | CTF_STAR type_qualifier_list pointer - { - $$ = make_node(scanner, NODE_POINTER); - $$->u.pointer.const_qualifier = 1; - bt_list_splice(&($3)->tmp_head, &($$)->tmp_head); - } - ; - -type_qualifier_list: - /* pointer assumes only const type qualifier */ - CTF_CONST - | type_qualifier_list CTF_CONST - ; - -/* 2.3: CTF-specific declarations */ - -ctf_assignment_expression_list: - ctf_assignment_expression CTF_SEMICOLON - { $$ = $1; } - | ctf_assignment_expression_list ctf_assignment_expression CTF_SEMICOLON - { - $$ = $1; - bt_list_add_tail(&($2)->siblings, &($$)->tmp_head); - } - ; - -ctf_assignment_expression: - unary_expression CTF_EQUAL unary_expression - { - /* - * Because we have left and right, cannot use - * set_parent_node. - */ - $$ = make_node(scanner, NODE_CTF_EXPRESSION); - _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left); - if ($1->u.unary_expression.type != UNARY_STRING) - reparent_error(scanner, "ctf_assignment_expression left expects string"); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.ctf_expression.right); - } - | unary_expression CTF_TYPEASSIGN declaration_specifiers /* Only allow struct */ - { - /* - * Because we have left and right, cannot use - * set_parent_node. - */ - $$ = make_node(scanner, NODE_CTF_EXPRESSION); - _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left); - if ($1->u.unary_expression.type != UNARY_STRING) - reparent_error(scanner, "ctf_assignment_expression left expects string"); - bt_list_add_tail(&($3)->siblings, &($$)->u.ctf_expression.right); - } - | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list - { - struct ctf_node *list; - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - $$ = make_node(scanner, NODE_TYPEDEF); - ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; - _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | CTF_TYPEDEF declaration_specifiers field_class_declarator_list - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEDEF); - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_def.field_class_specifier_list = list; - _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | declaration_specifiers CTF_TYPEDEF field_class_declarator_list - { - struct ctf_node *list; - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - $$ = make_node(scanner, NODE_TYPEDEF); - ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); - } - | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list - { - struct ctf_node *list; - - $$ = make_node(scanner, NODE_TYPEALIAS); - $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); - $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; - _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); - - list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); - $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; - _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); - _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); - } - ; diff --git a/src/plugins/ctf/common/metadata/scanner-symbols.hpp b/src/plugins/ctf/common/metadata/scanner-symbols.hpp deleted file mode 100644 index 1f6f144d..00000000 --- a/src/plugins/ctf/common/metadata/scanner-symbols.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011-2012 Mathieu Desnoyers - */ - -#ifndef _CTF_SCANNER_SYMBOLS -#define _CTF_SCANNER_SYMBOLS - -#define yy_create_buffer bt_yy_create_buffer -#define yy_delete_buffer bt_yy_delete_buffer -#define yy_flush_buffer bt_yy_flush_buffer -#define yy_scan_buffer bt_yy_scan_buffer -#define yy_scan_bytes bt_yy_scan_bytes -#define yy_scan_string bt_yy_scan_string -#define yy_switch_to_buffer bt_yy_switch_to_buffer -#define yyalloc bt_yyalloc -#define yyfree bt_yyfree -#define yyget_column bt_yyget_column -#define yyget_debug bt_yyget_debug -#define yyget_extra bt_yyget_extra -#define yyget_in bt_yyget_in -#define yyget_leng bt_yyget_leng -#define yyget_lineno bt_yyget_lineno -#define yyget_lval bt_yyget_lval -#define yyget_out bt_yyget_out -#define yyget_text bt_yyget_text -#define yylex_init bt_yylex_init -#define yypop_buffer_state bt_yypop_buffer_state -#define yypush_buffer_state bt_yypush_buffer_state -#define yyrealloc bt_yyrealloc -#define yyset_column bt_yyset_column -#define yyset_debug bt_yyset_debug -#define yyset_extra bt_yyset_extra -#define yyset_in bt_yyset_in -#define yyset_lineno bt_yyset_lineno -#define yyset_lval bt_yyset_lval -#define yyset_out bt_yyset_out - -#endif /* _CTF_SCANNER_SYMBOLS */ diff --git a/src/plugins/ctf/common/metadata/scanner.hpp b/src/plugins/ctf/common/metadata/scanner.hpp deleted file mode 100644 index dd16e977..00000000 --- a/src/plugins/ctf/common/metadata/scanner.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011-2012 Mathieu Desnoyers - */ - -#ifndef _CTF_SCANNER_H -#define _CTF_SCANNER_H - -#include - -#include "ast.hpp" - -#ifndef YY_TYPEDEF_YY_SCANNER_T -# define YY_TYPEDEF_YY_SCANNER_T -typedef void *yyscan_t; -#endif - -struct ctf_scanner_scope; -struct ctf_scanner_scope -{ - struct ctf_scanner_scope *parent; - GHashTable *classes; -}; - -struct ctf_scanner -{ - yyscan_t scanner; - struct ctf_ast *ast; - struct ctf_scanner_scope root_scope; - struct ctf_scanner_scope *cs; - struct objstack *objstack; -}; - -struct ctf_scanner *ctf_scanner_alloc(void); - -void ctf_scanner_free(struct ctf_scanner *scanner); - -int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input); - -static inline struct ctf_ast *ctf_scanner_get_ast(struct ctf_scanner *scanner) -{ - return scanner->ast; -} - -int is_type(struct ctf_scanner *scanner, const char *id); - -#endif /* _CTF_SCANNER_H */ diff --git a/src/plugins/ctf/common/metadata/visitor-generate-ir.cpp b/src/plugins/ctf/common/metadata/visitor-generate-ir.cpp deleted file mode 100644 index c53c4d8a..00000000 --- a/src/plugins/ctf/common/metadata/visitor-generate-ir.cpp +++ /dev/null @@ -1,4744 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * Copyright 2015-2018 Philippe Proulx - * - * Common Trace Format metadata visitor (generates CTF IR objects). - */ - -#include - -#include -#include -#include -#include -#include - -#include - -#define BT_COMP_LOG_SELF_COMP (ctx->log_cfg.self_comp) -#define BT_COMP_LOG_SELF_COMP_CLASS (ctx->log_cfg.self_comp_class) -#define BT_LOG_OUTPUT_LEVEL (ctx->log_cfg.log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/IR-VISITOR" -#include "logging.hpp" -#include "logging/comp-logging.h" - -#include "common/assert.h" -#include "common/common.h" -#include "common/uuid.h" -#include "compat/endian.h" /* IWYU pragma: keep */ - -#include "ast.hpp" -#include "ctf-meta-visitors.hpp" -#include "ctf-meta.hpp" -#include "decoder.hpp" - -/* Bit value (left shift) */ -#define _BV(_val) (1 << (_val)) - -/* Bit is set in a set of bits */ -#define _IS_SET(_set, _mask) (*(_set) & (_mask)) - -/* Set bit in a set of bits */ -#define _SET(_set, _mask) (*(_set) |= (_mask)) - -/* Try to push scope, or go to the `error` label */ -#define _TRY_PUSH_SCOPE_OR_GOTO_ERROR() \ - do { \ - ret = ctx_push_scope(ctx); \ - if (ret) { \ - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot push scope."); \ - goto error; \ - } \ - } while (0) - -/* Bits for verifying existing attributes in various declarations */ -enum -{ - _CLOCK_NAME_SET = _BV(0), - _CLOCK_UUID_SET = _BV(1), - _CLOCK_FREQ_SET = _BV(2), - _CLOCK_PRECISION_SET = _BV(3), - _CLOCK_OFFSET_S_SET = _BV(4), - _CLOCK_OFFSET_SET = _BV(5), - _CLOCK_ABSOLUTE_SET = _BV(6), - _CLOCK_DESCRIPTION_SET = _BV(7), -}; - -enum -{ - _INTEGER_ALIGN_SET = _BV(0), - _INTEGER_SIZE_SET = _BV(1), - _INTEGER_BASE_SET = _BV(2), - _INTEGER_ENCODING_SET = _BV(3), - _INTEGER_BYTE_ORDER_SET = _BV(4), - _INTEGER_SIGNED_SET = _BV(5), - _INTEGER_MAP_SET = _BV(6), -}; - -enum -{ - _FLOAT_ALIGN_SET = _BV(0), - _FLOAT_MANT_DIG_SET = _BV(1), - _FLOAT_EXP_DIG_SET = _BV(2), - _FLOAT_BYTE_ORDER_SET = _BV(3), -}; - -enum -{ - _STRING_ENCODING_SET = _BV(0), -}; - -enum -{ - _TRACE_MINOR_SET = _BV(0), - _TRACE_MAJOR_SET = _BV(1), - _TRACE_BYTE_ORDER_SET = _BV(2), - _TRACE_UUID_SET = _BV(3), - _TRACE_PACKET_HEADER_SET = _BV(4), -}; - -enum -{ - _STREAM_ID_SET = _BV(0), - _STREAM_PACKET_CONTEXT_SET = _BV(1), - _STREAM_EVENT_HEADER_SET = _BV(2), - _STREAM_EVENT_CONTEXT_SET = _BV(3), -}; - -enum -{ - _EVENT_NAME_SET = _BV(0), - _EVENT_ID_SET = _BV(1), - _EVENT_MODEL_EMF_URI_SET = _BV(2), - _EVENT_STREAM_ID_SET = _BV(3), - _EVENT_LOG_LEVEL_SET = _BV(4), - _EVENT_CONTEXT_SET = _BV(5), - _EVENT_FIELDS_SET = _BV(6), -}; - -enum loglevel -{ - LOG_LEVEL_EMERG = 0, - LOG_LEVEL_ALERT = 1, - LOG_LEVEL_CRIT = 2, - LOG_LEVEL_ERR = 3, - LOG_LEVEL_WARNING = 4, - LOG_LEVEL_NOTICE = 5, - LOG_LEVEL_INFO = 6, - LOG_LEVEL_DEBUG_SYSTEM = 7, - LOG_LEVEL_DEBUG_PROGRAM = 8, - LOG_LEVEL_DEBUG_PROCESS = 9, - LOG_LEVEL_DEBUG_MODULE = 10, - LOG_LEVEL_DEBUG_UNIT = 11, - LOG_LEVEL_DEBUG_FUNCTION = 12, - LOG_LEVEL_DEBUG_LINE = 13, - LOG_LEVEL_DEBUG = 14, - _NR_LOGLEVELS = 15, -}; - -/* Prefixes of class aliases */ -#define _PREFIX_ALIAS 'a' -#define _PREFIX_ENUM 'e' -#define _PREFIX_STRUCT 's' -#define _PREFIX_VARIANT 'v' - -/* First entry in a BT list */ -#define _BT_LIST_FIRST_ENTRY(_ptr, _class, _member) bt_list_entry((_ptr)->next, _class, _member) - -#define _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(_node, _attr, _entity) \ - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( \ - (_node)->lineno, "Duplicate attribute in %s: attr-name=\"%s\"", _entity, _attr) - -#define _BT_COMP_LOGE_NODE(_node, _msg, args...) _BT_COMP_LOGE_LINENO((_node)->lineno, _msg, ##args) - -#define _BT_COMP_LOGE_APPEND_CAUSE_NODE(_node, _msg, args...) \ - _BT_COMP_LOGE_APPEND_CAUSE_LINENO((_node)->lineno, _msg, ##args) - -#define _BT_COMP_LOGW_NODE(_node, _msg, args...) _BT_COMP_LOGW_LINENO((_node)->lineno, _msg, ##args) - -#define _BT_COMP_LOGT_NODE(_node, _msg, args...) _BT_COMP_LOGT_LINENO((_node)->lineno, _msg, ##args) - -/* - * Declaration scope of a visitor context. This represents a TSDL - * lexical scope, so that aliases and named structures, variants, - * and enumerations may be registered and looked up hierarchically. - */ -struct ctx_decl_scope -{ - /* - * Alias name to field class. - * - * GQuark -> struct ctf_field_class * (owned by this) - */ - GHashTable *decl_map; - - /* Parent scope; NULL if this is the root declaration scope */ - struct ctx_decl_scope *parent_scope; -}; - -/* - * Visitor context (private). - */ -struct ctf_visitor_generate_ir -{ - struct meta_log_config log_cfg; - - /* Trace IR trace class being filled (owned by this) */ - bt_trace_class *trace_class; - - /* CTF meta trace being filled (owned by this) */ - struct ctf_trace_class *ctf_tc; - - /* Current declaration scope (top of the stack) (owned by this) */ - struct ctx_decl_scope *current_scope; - - /* True if trace declaration is visited */ - bool is_trace_visited; - - /* True if this is an LTTng trace */ - bool is_lttng; - - /* Config passed by the user */ - struct ctf_metadata_decoder_config decoder_config; -}; - -/* - * Visitor (public). - */ -struct ctf_visitor_generate_ir; - -/** - * Creates a new declaration scope. - * - * @param par_scope Parent scope (NULL if creating a root scope) - * @returns New declaration scope, or NULL on error - */ -static struct ctx_decl_scope *ctx_decl_scope_create(struct ctf_visitor_generate_ir *ctx, - struct ctx_decl_scope *par_scope) -{ - struct ctx_decl_scope *scope; - - scope = g_new(struct ctx_decl_scope, 1); - if (!scope) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one declaration scope."); - goto end; - } - - scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) ctf_field_class_destroy); - scope->parent_scope = par_scope; - -end: - return scope; -} - -/** - * Destroys a declaration scope. - * - * This function does not destroy the parent scope. - * - * @param scope Scope to destroy - */ -static void ctx_decl_scope_destroy(struct ctx_decl_scope *scope) -{ - if (!scope) { - goto end; - } - - g_hash_table_destroy(scope->decl_map); - g_free(scope); - -end: - return; -} - -/** - * Returns the GQuark of a prefixed alias. - * - * @param prefix Prefix character - * @param name Name - * @returns Associated GQuark, or 0 on error - */ -static GQuark get_prefixed_named_quark(char prefix, const char *name) -{ - BT_ASSERT(name); - std::string prname = std::string {prefix} + name; - return g_quark_from_string(prname.c_str()); -} - -/** - * Looks up a prefixed class alias within a declaration scope. - * - * @param scope Declaration scope - * @param prefix Prefix character - * @param name Alias name - * @param levels Number of levels to dig into (-1 means infinite) - * @param copy True to return a copy - * @returns Declaration (owned by caller if \p copy is true), - * or NULL if not found - */ -static struct ctf_field_class *ctx_decl_scope_lookup_prefix_alias(struct ctx_decl_scope *scope, - char prefix, const char *name, - int levels, bool copy) -{ - GQuark qname = 0; - int cur_levels = 0; - struct ctf_field_class *decl = NULL; - struct ctx_decl_scope *cur_scope = scope; - - BT_ASSERT(scope); - BT_ASSERT(name); - qname = get_prefixed_named_quark(prefix, name); - if (!qname) { - goto end; - } - - if (levels < 0) { - levels = INT_MAX; - } - - while (cur_scope && cur_levels < levels) { - decl = (ctf_field_class *) g_hash_table_lookup(cur_scope->decl_map, - (gconstpointer) GUINT_TO_POINTER(qname)); - if (decl) { - /* Caller's reference */ - if (copy) { - decl = ctf_field_class_copy(decl); - BT_ASSERT(decl); - } - - goto end; - } - - cur_scope = cur_scope->parent_scope; - cur_levels++; - } - -end: - return decl; -} - -/** - * Looks up a class alias within a declaration scope. - * - * @param scope Declaration scope - * @param name Alias name - * @param levels Number of levels to dig into (-1 means infinite) - * @param copy True to return a copy - * @returns Declaration (owned by caller if \p copy is true), - * or NULL if not found - */ -static struct ctf_field_class *ctx_decl_scope_lookup_alias(struct ctx_decl_scope *scope, - const char *name, int levels, bool copy) -{ - return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS, name, levels, copy); -} - -/** - * Looks up an enumeration within a declaration scope. - * - * @param scope Declaration scope - * @param name Enumeration name - * @param levels Number of levels to dig into (-1 means infinite) - * @param copy True to return a copy - * @returns Declaration (owned by caller if \p copy is true), - * or NULL if not found - */ -static struct ctf_field_class_enum * -ctx_decl_scope_lookup_enum(struct ctx_decl_scope *scope, const char *name, int levels, bool copy) -{ - return ctf_field_class_as_enum( - ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM, name, levels, copy)); -} - -/** - * Looks up a structure within a declaration scope. - * - * @param scope Declaration scope - * @param name Structure name - * @param levels Number of levels to dig into (-1 means infinite) - * @param copy True to return a copy - * @returns Declaration (owned by caller if \p copy is true), - * or NULL if not found - */ -static struct ctf_field_class_struct * -ctx_decl_scope_lookup_struct(struct ctx_decl_scope *scope, const char *name, int levels, bool copy) -{ - return ctf_field_class_as_struct( - ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_STRUCT, name, levels, copy)); -} - -/** - * Looks up a variant within a declaration scope. - * - * @param scope Declaration scope - * @param name Variant name - * @param levels Number of levels to dig into (-1 means infinite) - * @param copy True to return a copy - * @returns Declaration (owned by caller if \p copy is true), - * or NULL if not found - */ -static struct ctf_field_class_variant * -ctx_decl_scope_lookup_variant(struct ctx_decl_scope *scope, const char *name, int levels, bool copy) -{ - return ctf_field_class_as_variant( - ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_VARIANT, name, levels, copy)); -} - -/** - * Registers a prefixed class alias within a declaration scope. - * - * @param scope Declaration scope - * @param prefix Prefix character - * @param name Alias name (non-NULL) - * @param decl Field class to register (copied) - * @returns 0 if registration went okay, negative value otherwise - */ -static int ctx_decl_scope_register_prefix_alias(struct ctx_decl_scope *scope, char prefix, - const char *name, struct ctf_field_class *decl) -{ - int ret = 0; - GQuark qname = 0; - - BT_ASSERT(scope); - BT_ASSERT(name); - BT_ASSERT(decl); - qname = get_prefixed_named_quark(prefix, name); - if (!qname) { - ret = -ENOMEM; - goto end; - } - - /* Make sure alias does not exist in local scope */ - if (ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1, false)) { - ret = -EEXIST; - goto end; - } - - decl = ctf_field_class_copy(decl); - BT_ASSERT(decl); - g_hash_table_insert(scope->decl_map, GUINT_TO_POINTER(qname), decl); - -end: - return ret; -} - -/** - * Registers a class alias within a declaration scope. - * - * @param scope Declaration scope - * @param name Alias name (non-NULL) - * @param decl Field class to register (copied) - * @returns 0 if registration went okay, negative value otherwise - */ -static int ctx_decl_scope_register_alias(struct ctx_decl_scope *scope, const char *name, - struct ctf_field_class *decl) -{ - return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ALIAS, name, decl); -} - -/** - * Registers an enumeration declaration within a declaration scope. - * - * @param scope Declaration scope - * @param name Enumeration name (non-NULL) - * @param decl Enumeration field class to register (copied) - * @returns 0 if registration went okay, negative value otherwise - */ -static int ctx_decl_scope_register_enum(struct ctx_decl_scope *scope, const char *name, - struct ctf_field_class_enum *decl) -{ - return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM, name, &decl->base.base.base); -} - -/** - * Registers a structure declaration within a declaration scope. - * - * @param scope Declaration scope - * @param name Structure name (non-NULL) - * @param decl Structure field class to register (copied) - * @returns 0 if registration went okay, negative value otherwise - */ -static int ctx_decl_scope_register_struct(struct ctx_decl_scope *scope, const char *name, - struct ctf_field_class_struct *decl) -{ - return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT, name, &decl->base); -} - -/** - * Registers a variant declaration within a declaration scope. - * - * @param scope Declaration scope - * @param name Variant name (non-NULL) - * @param decl Variant field class to register - * @returns 0 if registration went okay, negative value otherwise - */ -static int ctx_decl_scope_register_variant(struct ctx_decl_scope *scope, const char *name, - struct ctf_field_class_variant *decl) -{ - return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT, name, &decl->base); -} - -/** - * Destroys a visitor context. - * - * @param ctx Visitor context to destroy - */ -static void ctx_destroy(struct ctf_visitor_generate_ir *ctx) -{ - struct ctx_decl_scope *scope; - - if (!ctx) { - goto end; - } - - scope = ctx->current_scope; - - /* - * Destroy all scopes, from current one to the root scope. - */ - while (scope) { - struct ctx_decl_scope *parent_scope = scope->parent_scope; - - ctx_decl_scope_destroy(scope); - scope = parent_scope; - } - - bt_trace_class_put_ref(ctx->trace_class); - - if (ctx->ctf_tc) { - ctf_trace_class_destroy(ctx->ctf_tc); - } - - g_free(ctx); - -end: - return; -} - -/** - * Creates a new visitor context. - * - * @param trace Associated trace - * @returns New visitor context, or NULL on error - */ -static struct ctf_visitor_generate_ir * -ctx_create(const struct ctf_metadata_decoder_config *decoder_config) -{ - struct ctf_visitor_generate_ir *ctx = NULL; - - BT_ASSERT(decoder_config); - - ctx = g_new0(struct ctf_visitor_generate_ir, 1); - if (!ctx) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, decoder_config->log_level, decoder_config->self_comp, - "Failed to allocate one visitor context."); - goto error; - } - - ctx->log_cfg.log_level = decoder_config->log_level; - ctx->log_cfg.self_comp = decoder_config->self_comp; - ctx->log_cfg.self_comp_class = decoder_config->self_comp_class; - - if (decoder_config->self_comp) { - ctx->trace_class = bt_trace_class_create(decoder_config->self_comp); - if (!ctx->trace_class) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create empty trace class."); - goto error; - } - } - - ctx->ctf_tc = ctf_trace_class_create(); - if (!ctx->ctf_tc) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create CTF trace class."); - goto error; - } - - /* Root declaration scope */ - ctx->current_scope = ctx_decl_scope_create(ctx, NULL); - if (!ctx->current_scope) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create declaration scope."); - goto error; - } - - ctx->decoder_config = *decoder_config; - goto end; - -error: - ctx_destroy(ctx); - ctx = NULL; - -end: - return ctx; -} - -/** - * Pushes a new declaration scope on top of a visitor context's - * declaration scope stack. - * - * @param ctx Visitor context - * @returns 0 on success, or a negative value on error - */ -static int ctx_push_scope(struct ctf_visitor_generate_ir *ctx) -{ - int ret = 0; - struct ctx_decl_scope *new_scope; - - BT_ASSERT(ctx); - new_scope = ctx_decl_scope_create(ctx, ctx->current_scope); - if (!new_scope) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create declaration scope."); - ret = -ENOMEM; - goto end; - } - - ctx->current_scope = new_scope; - -end: - return ret; -} - -static void ctx_pop_scope(struct ctf_visitor_generate_ir *ctx) -{ - struct ctx_decl_scope *parent_scope = NULL; - - BT_ASSERT(ctx); - - if (!ctx->current_scope) { - goto end; - } - - parent_scope = ctx->current_scope->parent_scope; - ctx_decl_scope_destroy(ctx->current_scope); - ctx->current_scope = parent_scope; - -end: - return; -} - -static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *ts_list, - struct ctf_field_class **decl); - -static int is_unary_string(struct bt_list_head *head) -{ - int ret = TRUE; - struct ctf_node *node; - - bt_list_for_each_entry (node, head, siblings) { - if (node->type != NODE_UNARY_EXPRESSION) { - ret = FALSE; - } - - if (node->u.unary_expression.type != UNARY_STRING) { - ret = FALSE; - } - } - - return ret; -} - -static const char *get_map_clock_name_value(struct bt_list_head *head) -{ - int i = 0; - struct ctf_node *node; - const char *name = NULL; - - bt_list_for_each_entry (node, head, siblings) { - char *src_string; - int uexpr_type = node->u.unary_expression.type; - int uexpr_link = node->u.unary_expression.link; - int cond = node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_STRING || - !((uexpr_link != UNARY_LINK_UNKNOWN) ^ (i == 0)); - if (cond) { - goto error; - } - - /* Needs to be chained with . */ - switch (node->u.unary_expression.link) { - case UNARY_DOTLINK: - break; - case UNARY_ARROWLINK: - case UNARY_DOTDOTDOT: - goto error; - default: - break; - } - - src_string = node->u.unary_expression.u.string; - - switch (i) { - case 0: - if (strcmp("clock", src_string)) { - goto error; - } - break; - case 1: - name = src_string; - break; - case 2: - if (strcmp("value", src_string)) { - goto error; - } - break; - default: - /* Extra identifier, unknown */ - goto error; - } - - i++; - } - - return name; - -error: - return NULL; -} - -static int is_unary_unsigned(struct bt_list_head *head) -{ - int ret = TRUE; - struct ctf_node *node; - - bt_list_for_each_entry (node, head, siblings) { - if (node->type != NODE_UNARY_EXPRESSION) { - ret = FALSE; - } - - if (node->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { - ret = FALSE; - } - } - - return ret; -} - -static int get_unary_unsigned(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *head, - uint64_t *value) -{ - int i = 0; - int ret = 0; - struct ctf_node *node; - - *value = 0; - - if (bt_list_empty(head)) { - ret = -1; - goto end; - } - - bt_list_for_each_entry (node, head, siblings) { - int uexpr_type = node->u.unary_expression.type; - int uexpr_link = node->u.unary_expression.link; - int cond = node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_UNSIGNED_CONSTANT || - uexpr_link != UNARY_LINK_UNKNOWN || i != 0; - if (cond) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Invalid constant unsigned integer."); - ret = -EINVAL; - goto end; - } - - *value = node->u.unary_expression.u.unsigned_constant; - i++; - } - -end: - return ret; -} - -static int is_unary_signed(struct bt_list_head *head) -{ - int ret = TRUE; - struct ctf_node *node; - - bt_list_for_each_entry (node, head, siblings) { - if (node->type != NODE_UNARY_EXPRESSION) { - ret = FALSE; - } - - if (node->u.unary_expression.type != UNARY_SIGNED_CONSTANT) { - ret = FALSE; - } - } - - return ret; -} - -static int get_unary_signed(struct bt_list_head *head, int64_t *value) -{ - int i = 0; - int ret = 0; - struct ctf_node *node; - - bt_list_for_each_entry (node, head, siblings) { - int uexpr_type = node->u.unary_expression.type; - int uexpr_link = node->u.unary_expression.link; - int cond = node->type != NODE_UNARY_EXPRESSION || - (uexpr_type != UNARY_UNSIGNED_CONSTANT && uexpr_type != UNARY_SIGNED_CONSTANT) || - uexpr_link != UNARY_LINK_UNKNOWN || i != 0; - if (cond) { - ret = -EINVAL; - goto end; - } - - switch (uexpr_type) { - case UNARY_UNSIGNED_CONSTANT: - *value = (int64_t) node->u.unary_expression.u.unsigned_constant; - break; - case UNARY_SIGNED_CONSTANT: - *value = node->u.unary_expression.u.signed_constant; - break; - default: - ret = -EINVAL; - goto end; - } - - i++; - } - -end: - return ret; -} - -static int get_unary_uuid(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *head, - bt_uuid_t uuid) -{ - return ctf_ast_get_unary_uuid(head, uuid, ctx->log_cfg.log_level, ctx->log_cfg.self_comp); -} - -static int get_boolean(struct ctf_visitor_generate_ir *ctx, struct ctf_node *unary_expr) -{ - int ret = 0; - - if (unary_expr->type != NODE_UNARY_EXPRESSION) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(unary_expr, "Expecting unary expression: node-type=%d", - unary_expr->type); - ret = -EINVAL; - goto end; - } - - switch (unary_expr->u.unary_expression.type) { - case UNARY_UNSIGNED_CONSTANT: - ret = (unary_expr->u.unary_expression.u.unsigned_constant != 0); - break; - case UNARY_SIGNED_CONSTANT: - ret = (unary_expr->u.unary_expression.u.signed_constant != 0); - break; - case UNARY_STRING: - { - const char *str = unary_expr->u.unary_expression.u.string; - - if (strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0) { - ret = TRUE; - } else if (strcmp(str, "false") == 0 || strcmp(str, "FALSE") == 0) { - ret = FALSE; - } else { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(unary_expr, "Unexpected boolean value: value=\"%s\"", - str); - ret = -EINVAL; - goto end; - } - break; - } - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(unary_expr, - "Unexpected unary expression type: node-type=%d", - unary_expr->u.unary_expression.type); - ret = -EINVAL; - goto end; - } - -end: - return ret; -} - -static enum ctf_byte_order byte_order_from_unary_expr(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *unary_expr) -{ - const char *str; - enum ctf_byte_order bo = CTF_BYTE_ORDER_UNKNOWN; - - if (unary_expr->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - unary_expr, "\"byte_order\" attribute: expecting `be`, `le`, `network`, or `native`."); - goto end; - } - - str = unary_expr->u.unary_expression.u.string; - - if (strcmp(str, "be") == 0 || strcmp(str, "network") == 0) { - bo = CTF_BYTE_ORDER_BIG; - } else if (strcmp(str, "le") == 0) { - bo = CTF_BYTE_ORDER_LITTLE; - } else if (strcmp(str, "native") == 0) { - bo = CTF_BYTE_ORDER_DEFAULT; - } else { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - unary_expr, - "Unexpected \"byte_order\" attribute value: " - "expecting `be`, `le`, `network`, or `native`: value=\"%s\"", - str); - goto end; - } - -end: - return bo; -} - -static enum ctf_byte_order get_real_byte_order(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *uexpr) -{ - enum ctf_byte_order bo = byte_order_from_unary_expr(ctx, uexpr); - - if (bo == CTF_BYTE_ORDER_DEFAULT) { - bo = ctx->ctf_tc->default_byte_order; - } - - return bo; -} - -static int is_align_valid(uint64_t align) -{ - return (align != 0) && !(align & (align - UINT64_C(1))); -} - -static int get_class_specifier_name(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *cls_specifier, GString *str) -{ - int ret = 0; - - if (cls_specifier->type != NODE_TYPE_SPECIFIER) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier, "Unexpected node type: node-type=%d", - cls_specifier->type); - ret = -EINVAL; - goto end; - } - - switch (cls_specifier->u.field_class_specifier.type) { - case TYPESPEC_VOID: - g_string_append(str, "void"); - break; - case TYPESPEC_CHAR: - g_string_append(str, "char"); - break; - case TYPESPEC_SHORT: - g_string_append(str, "short"); - break; - case TYPESPEC_INT: - g_string_append(str, "int"); - break; - case TYPESPEC_LONG: - g_string_append(str, "long"); - break; - case TYPESPEC_FLOAT: - g_string_append(str, "float"); - break; - case TYPESPEC_DOUBLE: - g_string_append(str, "double"); - break; - case TYPESPEC_SIGNED: - g_string_append(str, "signed"); - break; - case TYPESPEC_UNSIGNED: - g_string_append(str, "unsigned"); - break; - case TYPESPEC_BOOL: - g_string_append(str, "bool"); - break; - case TYPESPEC_COMPLEX: - g_string_append(str, "_Complex"); - break; - case TYPESPEC_IMAGINARY: - g_string_append(str, "_Imaginary"); - break; - case TYPESPEC_CONST: - g_string_append(str, "const"); - break; - case TYPESPEC_ID_TYPE: - if (cls_specifier->u.field_class_specifier.id_type) { - g_string_append(str, cls_specifier->u.field_class_specifier.id_type); - } - break; - case TYPESPEC_STRUCT: - { - struct ctf_node *node = cls_specifier->u.field_class_specifier.node; - - if (!node->u._struct.name) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unexpected empty structure field class name."); - ret = -EINVAL; - goto end; - } - - g_string_append(str, "struct "); - g_string_append(str, node->u._struct.name); - break; - } - case TYPESPEC_VARIANT: - { - struct ctf_node *node = cls_specifier->u.field_class_specifier.node; - - if (!node->u.variant.name) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unexpected empty variant field class name."); - ret = -EINVAL; - goto end; - } - - g_string_append(str, "variant "); - g_string_append(str, node->u.variant.name); - break; - } - case TYPESPEC_ENUM: - { - struct ctf_node *node = cls_specifier->u.field_class_specifier.node; - - if (!node->u._enum.enum_id) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Unexpected empty enumeration field class (`enum`) name."); - ret = -EINVAL; - goto end; - } - - g_string_append(str, "enum "); - g_string_append(str, node->u._enum.enum_id); - break; - } - case TYPESPEC_FLOATING_POINT: - case TYPESPEC_INTEGER: - case TYPESPEC_STRING: - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier->u.field_class_specifier.node, - "Unexpected field class specifier type: %d", - cls_specifier->u.field_class_specifier.type); - ret = -EINVAL; - goto end; - } - -end: - return ret; -} - -static int get_class_specifier_list_name(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *cls_specifier_list, GString *str) -{ - int ret = 0; - struct ctf_node *iter; - int alias_item_nr = 0; - struct bt_list_head *head = &cls_specifier_list->u.field_class_specifier_list.head; - - bt_list_for_each_entry (iter, head, siblings) { - if (alias_item_nr != 0) { - g_string_append(str, " "); - } - - alias_item_nr++; - ret = get_class_specifier_name(ctx, iter, str); - if (ret) { - goto end; - } - } - -end: - return ret; -} - -static GQuark create_class_alias_identifier(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *cls_specifier_list, - struct ctf_node *node_field_class_declarator) -{ - int ret; - char *str_c; - GString *str; - GQuark qalias = 0; - struct ctf_node *iter; - struct bt_list_head *pointers = &node_field_class_declarator->u.field_class_declarator.pointers; - - str = g_string_new(""); - ret = get_class_specifier_list_name(ctx, cls_specifier_list, str); - if (ret) { - g_string_free(str, TRUE); - goto end; - } - - bt_list_for_each_entry (iter, pointers, siblings) { - g_string_append(str, " *"); - - if (iter->u.pointer.const_qualifier) { - g_string_append(str, " const"); - } - } - - str_c = g_string_free(str, FALSE); - qalias = g_quark_from_string(str_c); - g_free(str_c); - -end: - return qalias; -} - -static int visit_field_class_declarator(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *cls_specifier_list, GQuark *field_name, - struct ctf_node *node_field_class_declarator, - struct ctf_field_class **field_decl, - struct ctf_field_class *nested_decl) -{ - /* - * During this whole function, nested_decl is always OURS, - * whereas field_decl is an output which we create, but - * belongs to the caller (it is moved). - */ - int ret = 0; - *field_decl = NULL; - - /* Validate field class declarator node */ - if (node_field_class_declarator) { - if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_UNKNOWN) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node_field_class_declarator, "Unexpected field class declarator type: type=%d", - node_field_class_declarator->u.field_class_declarator.type); - ret = -EINVAL; - goto error; - } - - /* TODO: GCC bitfields not supported yet */ - if (node_field_class_declarator->u.field_class_declarator.bitfield_len != NULL) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, - "GCC bitfields are not supported as of this version."); - ret = -EPERM; - goto error; - } - } - - /* Find the right nested declaration if not provided */ - if (!nested_decl) { - if (node_field_class_declarator && - !bt_list_empty(&node_field_class_declarator->u.field_class_declarator.pointers)) { - GQuark qalias; - - /* - * If we have a pointer declarator, it HAS to - * be present in the field class aliases (else - * fail). - */ - qalias = - create_class_alias_identifier(ctx, cls_specifier_list, node_field_class_declarator); - nested_decl = ctx_decl_scope_lookup_alias(ctx->current_scope, g_quark_to_string(qalias), - -1, true); - if (!nested_decl) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, - "Cannot find class alias: name=\"%s\"", - g_quark_to_string(qalias)); - ret = -EINVAL; - goto error; - } - - if (nested_decl->type == CTF_FIELD_CLASS_TYPE_INT) { - /* Pointer: force integer's base to 16 */ - struct ctf_field_class_int *int_fc = ctf_field_class_as_int(nested_decl); - - int_fc->disp_base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL; - } - } else { - ret = visit_field_class_specifier_list(ctx, cls_specifier_list, &nested_decl); - if (ret) { - BT_ASSERT(!nested_decl); - goto error; - } - } - } - - BT_ASSERT(nested_decl); - - if (!node_field_class_declarator) { - *field_decl = nested_decl; - nested_decl = NULL; - goto end; - } - - if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_ID) { - if (node_field_class_declarator->u.field_class_declarator.u.id) { - const char *id = node_field_class_declarator->u.field_class_declarator.u.id; - - *field_name = g_quark_from_string(id); - } else { - *field_name = 0; - } - - *field_decl = nested_decl; - nested_decl = NULL; - goto end; - } else { - struct ctf_node *first; - struct ctf_field_class *decl = NULL; - struct ctf_field_class *outer_field_decl = NULL; - struct bt_list_head *length = - &node_field_class_declarator->u.field_class_declarator.u.nested.length; - - /* Create array/sequence, pass nested_decl as child */ - if (bt_list_empty(length)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, - "Expecting length field reference or value."); - ret = -EINVAL; - goto error; - } - - first = _BT_LIST_FIRST_ENTRY(length, struct ctf_node, siblings); - if (first->type != NODE_UNARY_EXPRESSION) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type=%d", - first->type); - ret = -EINVAL; - goto error; - } - - switch (first->u.unary_expression.type) { - case UNARY_UNSIGNED_CONSTANT: - { - struct ctf_field_class_array *array_decl = NULL; - - array_decl = ctf_field_class_array_create(); - BT_ASSERT(array_decl); - array_decl->length = first->u.unary_expression.u.unsigned_constant; - array_decl->base.elem_fc = nested_decl; - nested_decl = NULL; - decl = &array_decl->base.base; - break; - } - case UNARY_STRING: - { - /* Lookup unsigned integer definition, create seq. */ - struct ctf_field_class_sequence *seq_decl = NULL; - char *length_name = ctf_ast_concatenate_unary_strings(length); - - if (!length_name) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, - "Cannot concatenate unary strings."); - ret = -EINVAL; - goto error; - } - - if (strncmp(length_name, "env.", 4) == 0) { - /* This is, in fact, an array */ - const char *env_entry_name = &length_name[4]; - struct ctf_trace_class_env_entry *env_entry = - ctf_trace_class_borrow_env_entry_by_name(ctx->ctf_tc, env_entry_name); - struct ctf_field_class_array *array_decl; - - if (!env_entry) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, - "Cannot find environment entry: " - "name=\"%s\"", - env_entry_name); - ret = -EINVAL; - goto error; - } - - if (env_entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, - "Wrong environment entry type " - "(expecting integer): " - "name=\"%s\"", - env_entry_name); - ret = -EINVAL; - goto error; - } - - if (env_entry->value.i < 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, - "Invalid, negative array length: " - "env-entry-name=\"%s\", " - "value=%" PRId64, - env_entry_name, env_entry->value.i); - ret = -EINVAL; - goto error; - } - - array_decl = ctf_field_class_array_create(); - BT_ASSERT(array_decl); - array_decl->length = (uint64_t) env_entry->value.i; - array_decl->base.elem_fc = nested_decl; - nested_decl = NULL; - decl = &array_decl->base.base; - } else { - seq_decl = ctf_field_class_sequence_create(); - BT_ASSERT(seq_decl); - seq_decl->base.elem_fc = nested_decl; - nested_decl = NULL; - g_string_assign(seq_decl->length_ref, length_name); - decl = &seq_decl->base.base; - } - - g_free(length_name); - break; - } - default: - ret = -EINVAL; - goto error; - } - - BT_ASSERT(!nested_decl); - BT_ASSERT(decl); - BT_ASSERT(!*field_decl); - - /* - * At this point, we found the next nested declaration. - * We currently own this (and lost the ownership of - * nested_decl in the meantime). Pass this next - * nested declaration as the content of the outer - * container, MOVING its ownership. - */ - ret = visit_field_class_declarator( - ctx, cls_specifier_list, field_name, - node_field_class_declarator->u.field_class_declarator.u.nested.field_class_declarator, - &outer_field_decl, decl); - decl = NULL; - if (ret) { - BT_ASSERT(!outer_field_decl); - ret = -EINVAL; - goto error; - } - - BT_ASSERT(outer_field_decl); - *field_decl = outer_field_decl; - outer_field_decl = NULL; - } - - BT_ASSERT(*field_decl); - goto end; - -error: - ctf_field_class_destroy(*field_decl); - *field_decl = NULL; - - if (ret >= 0) { - ret = -1; - } - -end: - ctf_field_class_destroy(nested_decl); - nested_decl = NULL; - return ret; -} - -static int visit_struct_decl_field(struct ctf_visitor_generate_ir *ctx, - struct ctf_field_class_struct *struct_decl, - struct ctf_node *cls_specifier_list, - struct bt_list_head *field_class_declarators) -{ - int ret = 0; - struct ctf_node *iter; - struct ctf_field_class *field_decl = NULL; - - bt_list_for_each_entry (iter, field_class_declarators, siblings) { - field_decl = NULL; - GQuark qfield_name; - const char *field_name; - - ret = visit_field_class_declarator(ctx, cls_specifier_list, &qfield_name, iter, &field_decl, - NULL); - if (ret) { - BT_ASSERT(!field_decl); - _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, - "Cannot visit field class declarator: ret=%d", ret); - goto error; - } - - BT_ASSERT(field_decl); - field_name = g_quark_to_string(qfield_name); - - /* Check if field with same name already exists */ - if (ctf_field_class_struct_borrow_member_by_name(struct_decl, field_name)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, - "Duplicate field in structure field class: " - "field-name=\"%s\"", - field_name); - ret = -EINVAL; - goto error; - } - - /* Add field to structure */ - ctf_field_class_struct_append_member(struct_decl, field_name, field_decl); - field_decl = NULL; - } - - return 0; - -error: - ctf_field_class_destroy(field_decl); - field_decl = NULL; - return ret; -} - -static int visit_variant_decl_field(struct ctf_visitor_generate_ir *ctx, - struct ctf_field_class_variant *variant_decl, - struct ctf_node *cls_specifier_list, - struct bt_list_head *field_class_declarators) -{ - int ret = 0; - struct ctf_node *iter; - struct ctf_field_class *field_decl = NULL; - - bt_list_for_each_entry (iter, field_class_declarators, siblings) { - field_decl = NULL; - GQuark qfield_name; - const char *field_name; - - ret = visit_field_class_declarator(ctx, cls_specifier_list, &qfield_name, iter, &field_decl, - NULL); - if (ret) { - BT_ASSERT(!field_decl); - _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, - "Cannot visit field class declarator: ret=%d", ret); - goto error; - } - - BT_ASSERT(field_decl); - field_name = g_quark_to_string(qfield_name); - - /* Check if field with same name already exists */ - if (ctf_field_class_variant_borrow_option_by_name(variant_decl, field_name)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, - "Duplicate field in variant field class: " - "field-name=\"%s\"", - field_name); - ret = -EINVAL; - goto error; - } - - /* Add field to structure */ - ctf_field_class_variant_append_option(variant_decl, field_name, field_decl); - field_decl = NULL; - } - - return 0; - -error: - ctf_field_class_destroy(field_decl); - field_decl = NULL; - return ret; -} - -static int visit_field_class_def(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *cls_specifier_list, - struct bt_list_head *field_class_declarators) -{ - int ret = 0; - GQuark qidentifier; - struct ctf_node *iter; - struct ctf_field_class *class_decl = NULL; - - bt_list_for_each_entry (iter, field_class_declarators, siblings) { - ret = visit_field_class_declarator(ctx, cls_specifier_list, &qidentifier, iter, &class_decl, - NULL); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit field class declarator: ret=%d", - ret); - ret = -EINVAL; - goto end; - } - - /* Do not allow field class def and alias of untagged variants */ - if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(class_decl); - - if (var_fc->tag_path.path->len == 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - iter, "Type definition of untagged variant field class is not allowed."); - ret = -EPERM; - goto end; - } - } - - ret = ctx_decl_scope_register_alias(ctx->current_scope, g_quark_to_string(qidentifier), - class_decl); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot register field class alias: name=\"%s\"", - g_quark_to_string(qidentifier)); - goto end; - } - } - -end: - ctf_field_class_destroy(class_decl); - class_decl = NULL; - return ret; -} - -static int visit_field_class_alias(struct ctf_visitor_generate_ir *ctx, struct ctf_node *target, - struct ctf_node *alias) -{ - int ret = 0; - GQuark qalias; - struct ctf_node *node; - GQuark qdummy_field_name; - struct ctf_field_class *class_decl = NULL; - - /* Create target field class */ - if (bt_list_empty(&target->u.field_class_alias_target.field_class_declarators)) { - node = NULL; - } else { - node = _BT_LIST_FIRST_ENTRY(&target->u.field_class_alias_target.field_class_declarators, - struct ctf_node, siblings); - } - - ret = visit_field_class_declarator( - ctx, target->u.field_class_alias_target.field_class_specifier_list, &qdummy_field_name, - node, &class_decl, NULL); - if (ret) { - BT_ASSERT(!class_decl); - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot visit field class declarator: ret=%d", ret); - goto end; - } - - /* Do not allow field class def and alias of untagged variants */ - if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) { - struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(class_decl); - - if (var_fc->tag_path.path->len == 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - target, "Type definition of untagged variant field class is not allowed."); - ret = -EPERM; - goto end; - } - } - - /* - * The semantic validator does not check whether the target is - * abstract or not (if it has an identifier). Check it here. - */ - if (qdummy_field_name != 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(target, "Expecting empty identifier: id=\"%s\"", - g_quark_to_string(qdummy_field_name)); - ret = -EINVAL; - goto end; - } - - /* Create alias identifier */ - node = _BT_LIST_FIRST_ENTRY(&alias->u.field_class_alias_name.field_class_declarators, - struct ctf_node, siblings); - qalias = create_class_alias_identifier( - ctx, alias->u.field_class_alias_name.field_class_specifier_list, node); - ret = ctx_decl_scope_register_alias(ctx->current_scope, g_quark_to_string(qalias), class_decl); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot register class alias: name=\"%s\"", - g_quark_to_string(qalias)); - goto end; - } - -end: - ctf_field_class_destroy(class_decl); - class_decl = NULL; - return ret; -} - -static int visit_struct_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *entry_node, - struct ctf_field_class_struct *struct_decl) -{ - int ret = 0; - - switch (entry_node->type) { - case NODE_TYPEDEF: - ret = visit_field_class_def(ctx, entry_node->u.field_class_def.field_class_specifier_list, - &entry_node->u.field_class_def.field_class_declarators); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Cannot add field class found in structure field class: ret=%d", ret); - goto end; - } - break; - case NODE_TYPEALIAS: - ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target, - entry_node->u.field_class_alias.alias); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Cannot add field class alias found in structure field class: ret=%d", - ret); - goto end; - } - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - /* Field */ - ret = visit_struct_decl_field( - ctx, struct_decl, - entry_node->u.struct_or_variant_declaration.field_class_specifier_list, - &entry_node->u.struct_or_variant_declaration.field_class_declarators); - if (ret) { - goto end; - } - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type=%d", - entry_node->type); - ret = -EINVAL; - goto end; - } - -end: - return ret; -} - -static int visit_variant_decl_entry(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *entry_node, - struct ctf_field_class_variant *variant_decl) -{ - int ret = 0; - - switch (entry_node->type) { - case NODE_TYPEDEF: - ret = visit_field_class_def(ctx, entry_node->u.field_class_def.field_class_specifier_list, - &entry_node->u.field_class_def.field_class_declarators); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Cannot add field class found in variant field class: ret=%d", ret); - goto end; - } - break; - case NODE_TYPEALIAS: - ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target, - entry_node->u.field_class_alias.alias); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Cannot add field class alias found in variant field class: ret=%d", - ret); - goto end; - } - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - /* Field */ - ret = visit_variant_decl_field( - ctx, variant_decl, - entry_node->u.struct_or_variant_declaration.field_class_specifier_list, - &entry_node->u.struct_or_variant_declaration.field_class_declarators); - if (ret) { - goto end; - } - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type=%d", - entry_node->type); - ret = -EINVAL; - goto end; - } - -end: - return ret; -} - -static int visit_struct_decl(struct ctf_visitor_generate_ir *ctx, const char *name, - struct bt_list_head *decl_list, int has_body, - struct bt_list_head *min_align, - struct ctf_field_class_struct **struct_decl) -{ - int ret = 0; - - BT_ASSERT(struct_decl); - *struct_decl = NULL; - - /* For named struct (without body), lookup in declaration scope */ - if (!has_body) { - if (!name) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Bodyless structure field class: missing name."); - ret = -EPERM; - goto error; - } - - *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope, name, -1, true); - if (!*struct_decl) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot find structure field class: name=\"struct %s\"", name); - ret = -EINVAL; - goto error; - } - } else { - struct ctf_node *entry_node; - uint64_t min_align_value = 0; - - if (name) { - if (ctx_decl_scope_lookup_struct(ctx->current_scope, name, 1, false)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Structure field class already declared in local scope: " - "name=\"struct %s\"", - name); - ret = -EINVAL; - goto error; - } - } - - if (!bt_list_empty(min_align)) { - ret = get_unary_unsigned(ctx, min_align, &min_align_value); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Unexpected unary expression for structure field class's `align` attribute: " - "ret=%d", - ret); - goto error; - } - } - - *struct_decl = ctf_field_class_struct_create(); - BT_ASSERT(*struct_decl); - - if (min_align_value != 0) { - (*struct_decl)->base.alignment = min_align_value; - } - - _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); - - bt_list_for_each_entry (entry_node, decl_list, siblings) { - ret = visit_struct_decl_entry(ctx, entry_node, *struct_decl); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, - "Cannot visit structure field class entry: " - "ret=%d", - ret); - ctx_pop_scope(ctx); - goto error; - } - } - - ctx_pop_scope(ctx); - - if (name) { - ret = ctx_decl_scope_register_struct(ctx->current_scope, name, *struct_decl); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot register structure field class in declaration scope: " - "name=\"struct %s\", ret=%d", - name, ret); - goto error; - } - } - } - - return 0; - -error: - ctf_field_class_destroy(&(*struct_decl)->base); - *struct_decl = NULL; - return ret; -} - -static int visit_variant_decl(struct ctf_visitor_generate_ir *ctx, const char *name, - const char *tag, struct bt_list_head *decl_list, int has_body, - struct ctf_field_class_variant **variant_decl) -{ - int ret = 0; - struct ctf_field_class_variant *untagged_variant_decl = NULL; - - BT_ASSERT(variant_decl); - *variant_decl = NULL; - - /* For named variant (without body), lookup in declaration scope */ - if (!has_body) { - if (!name) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Bodyless variant field class: missing name."); - ret = -EPERM; - goto error; - } - - untagged_variant_decl = ctx_decl_scope_lookup_variant(ctx->current_scope, name, -1, true); - if (!untagged_variant_decl) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot find variant field class: name=\"variant %s\"", name); - ret = -EINVAL; - goto error; - } - } else { - struct ctf_node *entry_node; - - if (name) { - if (ctx_decl_scope_lookup_variant(ctx->current_scope, name, 1, false)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Variant field class already declared in local scope: " - "name=\"variant %s\"", - name); - ret = -EINVAL; - goto error; - } - } - - untagged_variant_decl = ctf_field_class_variant_create(); - BT_ASSERT(untagged_variant_decl); - _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); - - bt_list_for_each_entry (entry_node, decl_list, siblings) { - ret = visit_variant_decl_entry(ctx, entry_node, untagged_variant_decl); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, - "Cannot visit variant field class entry: " - "ret=%d", - ret); - ctx_pop_scope(ctx); - goto error; - } - } - - ctx_pop_scope(ctx); - - if (name) { - ret = ctx_decl_scope_register_variant(ctx->current_scope, name, untagged_variant_decl); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot register variant field class in declaration scope: " - "name=\"variant %s\", ret=%d", - name, ret); - goto error; - } - } - } - - /* - * If tagged, create tagged variant and return; otherwise - * return untagged variant. - */ - if (!tag) { - *variant_decl = untagged_variant_decl; - untagged_variant_decl = NULL; - } else { - /* - * At this point, we have a fresh untagged variant; nobody - * else owns it. Set its tag now. - */ - g_string_assign(untagged_variant_decl->tag_ref, tag); - *variant_decl = untagged_variant_decl; - untagged_variant_decl = NULL; - } - - BT_ASSERT(!untagged_variant_decl); - BT_ASSERT(*variant_decl); - return 0; - -error: - ctf_field_class_destroy(&untagged_variant_decl->base); - untagged_variant_decl = NULL; - ctf_field_class_destroy(&(*variant_decl)->base); - *variant_decl = NULL; - return ret; -} - -struct uori -{ - bool is_signed; - union - { - uint64_t u; - uint64_t i; - } value; -}; - -static int visit_enum_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *enumerator, - struct ctf_field_class_enum *enum_decl, struct uori *last) -{ - int ret = 0; - int nr_vals = 0; - struct ctf_node *iter; - struct uori start = { - .is_signed = false, - .value = - { - .u = 0, - }, - }; - struct uori end = { - .is_signed = false, - .value = - { - .u = 0, - }, - }; - const char *label = enumerator->u.enumerator.id; - struct bt_list_head *values = &enumerator->u.enumerator.values; - - bt_list_for_each_entry (iter, values, siblings) { - struct uori *target; - - if (iter->type != NODE_UNARY_EXPRESSION) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, - "Wrong expression for enumeration field class label: " - "node-type=%d, label=\"%s\"", - iter->type, label); - ret = -EINVAL; - goto error; - } - - if (nr_vals == 0) { - target = &start; - } else { - target = &end; - } - - switch (iter->u.unary_expression.type) { - case UNARY_SIGNED_CONSTANT: - target->is_signed = true; - target->value.i = iter->u.unary_expression.u.signed_constant; - break; - case UNARY_UNSIGNED_CONSTANT: - target->is_signed = false; - target->value.u = iter->u.unary_expression.u.unsigned_constant; - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, - "Invalid enumeration field class entry: " - "expecting constant signed or unsigned integer: " - "node-type=%d, label=\"%s\"", - iter->u.unary_expression.type, label); - ret = -EINVAL; - goto error; - } - - if (nr_vals > 1) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - iter, "Invalid enumeration field class entry: label=\"%s\"", label); - ret = -EINVAL; - goto error; - } - - nr_vals++; - } - - if (nr_vals == 0) { - start = *last; - } - - if (nr_vals <= 1) { - end = start; - } - - if (end.is_signed) { - last->value.i = end.value.i + 1; - } else { - last->value.u = end.value.u + 1; - } - - ctf_field_class_enum_map_range(enum_decl, label, start.value.u, end.value.u); - return 0; - -error: - return ret; -} - -static int visit_enum_decl(struct ctf_visitor_generate_ir *ctx, const char *name, - struct ctf_node *container_cls, struct bt_list_head *enumerator_list, - int has_body, struct ctf_field_class_enum **enum_decl) -{ - int ret = 0; - GQuark qdummy_id; - struct ctf_field_class_int *integer_decl = NULL; - - BT_ASSERT(enum_decl); - *enum_decl = NULL; - - /* For named enum (without body), lookup in declaration scope */ - if (!has_body) { - if (!name) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Bodyless enumeration field class: missing name."); - ret = -EPERM; - goto error; - } - - *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope, name, -1, true); - if (!*enum_decl) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot find enumeration field class: " - "name=\"enum %s\"", - name); - ret = -EINVAL; - goto error; - } - } else { - struct ctf_node *iter; - struct uori last_value = { - .is_signed = false, - .value = - { - .u = 0, - }, - }; - - if (name) { - if (ctx_decl_scope_lookup_enum(ctx->current_scope, name, 1, false)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Enumeration field class already declared in local scope: " - "name=\"enum %s\"", - name); - ret = -EINVAL; - goto error; - } - } - - if (!container_cls) { - integer_decl = ctf_field_class_as_int( - ctx_decl_scope_lookup_alias(ctx->current_scope, "int", -1, true)); - if (!integer_decl) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot find implicit `int` field class alias for enumeration field class."); - ret = -EINVAL; - goto error; - } - } else { - ctf_field_class *decl; - - ret = visit_field_class_declarator(ctx, container_cls, &qdummy_id, NULL, &decl, NULL); - if (ret) { - BT_ASSERT(!decl); - ret = -EINVAL; - goto error; - } - - integer_decl = ctf_field_class_as_int(decl); - } - - BT_ASSERT(integer_decl); - - if (integer_decl->base.base.type != CTF_FIELD_CLASS_TYPE_INT) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Container field class for enumeration field class is not an integer field class: " - "fc-type=%d", - integer_decl->base.base.type); - ret = -EINVAL; - goto error; - } - - *enum_decl = ctf_field_class_enum_create(); - BT_ASSERT(*enum_decl); - (*enum_decl)->base.base.base.alignment = integer_decl->base.base.alignment; - ctf_field_class_int_copy_content(&(*enum_decl)->base, integer_decl); - last_value.is_signed = (*enum_decl)->base.is_signed; - - bt_list_for_each_entry (iter, enumerator_list, siblings) { - ret = visit_enum_decl_entry(ctx, iter, *enum_decl, &last_value); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, - "Cannot visit enumeration field class entry: " - "ret=%d", - ret); - goto error; - } - } - - if (name) { - ret = ctx_decl_scope_register_enum(ctx->current_scope, name, *enum_decl); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot register enumeration field class in declaration scope: " - "ret=%d", - ret); - goto error; - } - } - } - - goto end; - -error: - ctf_field_class_destroy(&(*enum_decl)->base.base.base); - *enum_decl = NULL; - -end: - ctf_field_class_destroy(&integer_decl->base.base); - integer_decl = NULL; - return ret; -} - -static int visit_field_class_specifier(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *cls_specifier_list, - struct ctf_field_class **decl) -{ - int ret = 0; - GString *str = NULL; - - *decl = NULL; - str = g_string_new(""); - ret = get_class_specifier_list_name(ctx, cls_specifier_list, str); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - cls_specifier_list, "Cannot get field class specifier list's name: ret=%d", ret); - goto error; - } - - *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1, true); - if (!*decl) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, - "Cannot find field class alias: name=\"%s\"", str->str); - ret = -EINVAL; - goto error; - } - - goto end; - -error: - ctf_field_class_destroy(*decl); - *decl = NULL; - -end: - if (str) { - g_string_free(str, TRUE); - } - - return ret; -} - -static int visit_integer_decl(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *expressions, - struct ctf_field_class_int **integer_decl) -{ - int set = 0; - int ret = 0; - int signedness = 0; - struct ctf_node *expression; - uint64_t alignment = 0, size = 0; - struct ctf_clock_class *mapped_clock_class = NULL; - enum ctf_encoding encoding = CTF_ENCODING_NONE; - bt_field_class_integer_preferred_display_base base = - BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL; - enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order; - - *integer_decl = NULL; - - bt_list_for_each_entry (expression, expressions, siblings) { - struct ctf_node *left, *right; - - left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings); - right = - _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings); - - if (left->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type=%d", - left->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - if (strcmp(left->u.unary_expression.u.string, "signed") == 0) { - if (_IS_SET(&set, _INTEGER_SIGNED_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "signed", "integer field class"); - ret = -EPERM; - goto error; - } - - signedness = get_boolean(ctx, right); - if (signedness < 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid boolean value for integer field class's `signed` attribute: " - "ret=%d", - ret); - ret = -EINVAL; - goto error; - } - - _SET(&set, _INTEGER_SIGNED_SET); - } else if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) { - if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order", "integer field class"); - ret = -EPERM; - goto error; - } - - byte_order = get_real_byte_order(ctx, right); - if (byte_order == CTF_BYTE_ORDER_UNKNOWN) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `byte_order` attribute in integer field class: " - "ret=%d", - ret); - ret = -EINVAL; - goto error; - } - - _SET(&set, _INTEGER_BYTE_ORDER_SET); - } else if (strcmp(left->u.unary_expression.u.string, "size") == 0) { - if (_IS_SET(&set, _INTEGER_SIZE_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "size", "integer field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, - "Invalid `size` attribute in integer field class: " - "expecting unsigned constant integer: " - "node-type=%d", - right->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - size = right->u.unary_expression.u.unsigned_constant; - if (size == 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, - "Invalid `size` attribute in integer field class: " - "expecting positive constant integer: " - "size=%" PRIu64, - size); - ret = -EINVAL; - goto error; - } else if (size > 64) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `size` attribute in integer field class: " - "integer fields over 64 bits are not supported as of this version: " - "size=%" PRIu64, - size); - ret = -EINVAL; - goto error; - } - - _SET(&set, _INTEGER_SIZE_SET); - } else if (strcmp(left->u.unary_expression.u.string, "align") == 0) { - if (_IS_SET(&set, _INTEGER_ALIGN_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "align", "integer field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, - "Invalid `align` attribute in integer field class: " - "expecting unsigned constant integer: " - "node-type=%d", - right->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - alignment = right->u.unary_expression.u.unsigned_constant; - if (!is_align_valid(alignment)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, - "Invalid `align` attribute in integer field class: " - "expecting power of two: " - "align=%" PRIu64, - alignment); - ret = -EINVAL; - goto error; - } - - _SET(&set, _INTEGER_ALIGN_SET); - } else if (strcmp(left->u.unary_expression.u.string, "base") == 0) { - if (_IS_SET(&set, _INTEGER_BASE_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "base", "integer field class"); - ret = -EPERM; - goto error; - } - - switch (right->u.unary_expression.type) { - case UNARY_UNSIGNED_CONSTANT: - { - uint64_t constant = right->u.unary_expression.u.unsigned_constant; - - switch (constant) { - case 2: - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY; - break; - case 8: - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL; - break; - case 10: - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL; - break; - case 16: - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL; - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `base` attribute in integer field class: " - "base=%" PRIu64, - right->u.unary_expression.u.unsigned_constant); - ret = -EINVAL; - goto error; - } - break; - } - case UNARY_STRING: - { - char *s_right = - ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); - if (!s_right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Unexpected unary expression for integer field class's `base` attribute."); - ret = -EINVAL; - goto error; - } - - if (strcmp(s_right, "decimal") == 0 || strcmp(s_right, "dec") == 0 || - strcmp(s_right, "d") == 0 || strcmp(s_right, "i") == 0 || - strcmp(s_right, "u") == 0) { - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL; - } else if (strcmp(s_right, "hexadecimal") == 0 || strcmp(s_right, "hex") == 0 || - strcmp(s_right, "x") == 0 || strcmp(s_right, "X") == 0 || - strcmp(s_right, "p") == 0) { - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL; - } else if (strcmp(s_right, "octal") == 0 || strcmp(s_right, "oct") == 0 || - strcmp(s_right, "o") == 0) { - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL; - } else if (strcmp(s_right, "binary") == 0 || strcmp(s_right, "b") == 0) { - base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY; - } else { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Unexpected unary expression for integer field class's `base` attribute: " - "base=\"%s\"", - s_right); - g_free(s_right); - ret = -EINVAL; - goto error; - } - - g_free(s_right); - break; - } - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, "Invalid `base` attribute in integer field class: " - "expecting unsigned constant integer or unary string."); - ret = -EINVAL; - goto error; - } - - _SET(&set, _INTEGER_BASE_SET); - } else if (strcmp(left->u.unary_expression.u.string, "encoding") == 0) { - char *s_right; - - if (_IS_SET(&set, _INTEGER_ENCODING_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "integer field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, "Invalid `encoding` attribute in integer field class: " - "expecting unary string."); - ret = -EINVAL; - goto error; - } - - s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); - if (!s_right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Unexpected unary expression for integer field class's `encoding` attribute."); - ret = -EINVAL; - goto error; - } - - if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 || - strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 || - strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) { - encoding = CTF_ENCODING_UTF8; - } else if (strcmp(s_right, "none") == 0) { - encoding = CTF_ENCODING_NONE; - } else { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `encoding` attribute in integer field class: " - "unknown encoding: encoding=\"%s\"", - s_right); - g_free(s_right); - ret = -EINVAL; - goto error; - } - - g_free(s_right); - _SET(&set, _INTEGER_ENCODING_SET); - } else if (strcmp(left->u.unary_expression.u.string, "map") == 0) { - const char *clock_name; - - if (_IS_SET(&set, _INTEGER_MAP_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "map", "integer field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, - "Invalid `map` attribute in integer field class: " - "expecting unary string."); - ret = -EINVAL; - goto error; - } - - clock_name = get_map_clock_name_value(&expression->u.ctf_expression.right); - if (!clock_name) { - char *s_right = - ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); - - if (!s_right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Unexpected unary expression for integer field class's `map` attribute."); - ret = -EINVAL; - goto error; - } - - _BT_COMP_LOGE_NODE(right, - "Invalid `map` attribute in integer field class: " - "cannot find clock class at this point: name=\"%s\"", - s_right); - _SET(&set, _INTEGER_MAP_SET); - g_free(s_right); - continue; - } - - mapped_clock_class = - ctf_trace_class_borrow_clock_class_by_name(ctx->ctf_tc, clock_name); - if (!mapped_clock_class) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `map` attribute in integer field class: " - "cannot find clock class at this point: name=\"%s\"", - clock_name); - ret = -EINVAL; - goto error; - } - - _SET(&set, _INTEGER_MAP_SET); - } else { - _BT_COMP_LOGW_NODE(left, - "Unknown attribute in integer field class: " - "attr-name=\"%s\"", - left->u.unary_expression.u.string); - } - } - - if (!_IS_SET(&set, _INTEGER_SIZE_SET)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Missing `size` attribute in integer field class."); - ret = -EPERM; - goto error; - } - - if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) { - if (size % CHAR_BIT) { - /* Bit-packed alignment */ - alignment = 1; - } else { - /* Byte-packed alignment */ - alignment = CHAR_BIT; - } - } - - *integer_decl = ctf_field_class_int_create(); - BT_ASSERT(*integer_decl); - (*integer_decl)->base.base.alignment = alignment; - (*integer_decl)->base.byte_order = byte_order; - (*integer_decl)->base.size = size; - (*integer_decl)->is_signed = (signedness > 0); - (*integer_decl)->disp_base = base; - (*integer_decl)->encoding = encoding; - (*integer_decl)->mapped_clock_class = mapped_clock_class; - return 0; - -error: - ctf_field_class_destroy(&(*integer_decl)->base.base); - *integer_decl = NULL; - return ret; -} - -static int visit_floating_point_number_decl(struct ctf_visitor_generate_ir *ctx, - struct bt_list_head *expressions, - struct ctf_field_class_float **float_decl) -{ - int set = 0; - int ret = 0; - struct ctf_node *expression; - uint64_t alignment = 1, exp_dig = 0, mant_dig = 0; - enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order; - - *float_decl = NULL; - - bt_list_for_each_entry (expression, expressions, siblings) { - struct ctf_node *left, *right; - - left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings); - right = - _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings); - - if (left->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type=%d", - left->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) { - if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order", - "floating point number field class"); - ret = -EPERM; - goto error; - } - - byte_order = get_real_byte_order(ctx, right); - if (byte_order == CTF_BYTE_ORDER_UNKNOWN) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `byte_order` attribute in floating point number field class: " - "ret=%d", - ret); - ret = -EINVAL; - goto error; - } - - _SET(&set, _FLOAT_BYTE_ORDER_SET); - } else if (strcmp(left->u.unary_expression.u.string, "exp_dig") == 0) { - if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "exp_dig", - "floating point number field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `exp_dig` attribute in floating point number field class: " - "expecting unsigned constant integer: " - "node-type=%d", - right->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - exp_dig = right->u.unary_expression.u.unsigned_constant; - _SET(&set, _FLOAT_EXP_DIG_SET); - } else if (strcmp(left->u.unary_expression.u.string, "mant_dig") == 0) { - if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "mant_dig", - "floating point number field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `mant_dig` attribute in floating point number field class: " - "expecting unsigned constant integer: " - "node-type=%d", - right->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - mant_dig = right->u.unary_expression.u.unsigned_constant; - _SET(&set, _FLOAT_MANT_DIG_SET); - } else if (strcmp(left->u.unary_expression.u.string, "align") == 0) { - if (_IS_SET(&set, _FLOAT_ALIGN_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "align", - "floating point number field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `align` attribute in floating point number field class: " - "expecting unsigned constant integer: " - "node-type=%d", - right->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - alignment = right->u.unary_expression.u.unsigned_constant; - - if (!is_align_valid(alignment)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `align` attribute in floating point number field class: " - "expecting power of two: " - "align=%" PRIu64, - alignment); - ret = -EINVAL; - goto error; - } - - _SET(&set, _FLOAT_ALIGN_SET); - } else { - _BT_COMP_LOGW_NODE(left, - "Unknown attribute in floating point number field class: " - "attr-name=\"%s\"", - left->u.unary_expression.u.string); - } - } - - if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Missing `mant_dig` attribute in floating point number field class."); - ret = -EPERM; - goto error; - } - - if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Missing `exp_dig` attribute in floating point number field class."); - ret = -EPERM; - goto error; - } - - if (mant_dig != 24 && mant_dig != 53) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("`mant_dig` attribute: expecting 24 or 53."); - ret = -EPERM; - goto error; - } - - if (mant_dig == 24 && exp_dig != 8) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "`exp_dig` attribute: expecting 8 because `mant_dig` is 24."); - ret = -EPERM; - goto error; - } - - if (mant_dig == 53 && exp_dig != 11) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "`exp_dig` attribute: expecting 11 because `mant_dig` is 53."); - ret = -EPERM; - goto error; - } - - if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) { - if ((mant_dig + exp_dig) % CHAR_BIT) { - /* Bit-packed alignment */ - alignment = 1; - } else { - /* Byte-packed alignment */ - alignment = CHAR_BIT; - } - } - - *float_decl = ctf_field_class_float_create(); - BT_ASSERT(*float_decl); - (*float_decl)->base.base.alignment = alignment; - (*float_decl)->base.byte_order = byte_order; - (*float_decl)->base.size = mant_dig + exp_dig; - return 0; - -error: - ctf_field_class_destroy(&(*float_decl)->base.base); - *float_decl = NULL; - return ret; -} - -static int visit_string_decl(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *expressions, - struct ctf_field_class_string **string_decl) -{ - int set = 0; - int ret = 0; - struct ctf_node *expression; - enum ctf_encoding encoding = CTF_ENCODING_UTF8; - - *string_decl = NULL; - - bt_list_for_each_entry (expression, expressions, siblings) { - struct ctf_node *left, *right; - - left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings); - right = - _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings); - - if (left->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type=%d", - left->u.unary_expression.type); - ret = -EINVAL; - goto error; - } - - if (strcmp(left->u.unary_expression.u.string, "encoding") == 0) { - char *s_right; - - if (_IS_SET(&set, _STRING_ENCODING_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "string field class"); - ret = -EPERM; - goto error; - } - - if (right->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, "Invalid `encoding` attribute in string field class: " - "expecting unary string."); - ret = -EINVAL; - goto error; - } - - s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); - if (!s_right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Unexpected unary expression for string field class's `encoding` attribute."); - ret = -EINVAL; - goto error; - } - - if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 || - strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 || - strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) { - encoding = CTF_ENCODING_UTF8; - } else if (strcmp(s_right, "none") == 0) { - encoding = CTF_ENCODING_NONE; - } else { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - right, - "Invalid `encoding` attribute in string field class: " - "unknown encoding: encoding=\"%s\"", - s_right); - g_free(s_right); - ret = -EINVAL; - goto error; - } - - g_free(s_right); - _SET(&set, _STRING_ENCODING_SET); - } else { - _BT_COMP_LOGW_NODE(left, - "Unknown attribute in string field class: " - "attr-name=\"%s\"", - left->u.unary_expression.u.string); - } - } - - *string_decl = ctf_field_class_string_create(); - BT_ASSERT(*string_decl); - (*string_decl)->encoding = encoding; - return 0; - -error: - ctf_field_class_destroy(&(*string_decl)->base); - *string_decl = NULL; - return ret; -} - -static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *ctx, - struct ctf_node *ts_list, struct ctf_field_class **decl) -{ - int ret = 0; - struct ctf_node *first, *node; - - *decl = NULL; - - if (ts_list->type != NODE_TYPE_SPECIFIER_LIST) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(ts_list, "Unexpected node type: node-type=%d", - ts_list->type); - ret = -EINVAL; - goto error; - } - - first = _BT_LIST_FIRST_ENTRY(&ts_list->u.field_class_specifier_list.head, struct ctf_node, - siblings); - if (first->type != NODE_TYPE_SPECIFIER) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type=%d", first->type); - ret = -EINVAL; - goto error; - } - - node = first->u.field_class_specifier.node; - - switch (first->u.field_class_specifier.type) { - case TYPESPEC_INTEGER: - { - ctf_field_class_int *int_decl; - - ret = visit_integer_decl(ctx, &node->u.integer.expressions, &int_decl); - if (ret) { - BT_ASSERT(!int_decl); - goto error; - } - - *decl = &int_decl->base.base; - break; - } - case TYPESPEC_FLOATING_POINT: - { - ctf_field_class_float *float_decl; - - ret = - visit_floating_point_number_decl(ctx, &node->u.floating_point.expressions, &float_decl); - if (ret) { - BT_ASSERT(!float_decl); - goto error; - } - - *decl = &float_decl->base.base; - break; - } - case TYPESPEC_STRING: - { - ctf_field_class_string *string_decl; - - ret = visit_string_decl(ctx, &node->u.string.expressions, &string_decl); - if (ret) { - BT_ASSERT(!string_decl); - goto error; - } - - *decl = &string_decl->base; - break; - } - case TYPESPEC_STRUCT: - { - ctf_field_class_struct *struct_decl; - - ret = visit_struct_decl(ctx, node->u._struct.name, &node->u._struct.declaration_list, - node->u._struct.has_body, &node->u._struct.min_align, &struct_decl); - if (ret) { - BT_ASSERT(!struct_decl); - goto error; - } - - *decl = &struct_decl->base; - break; - } - case TYPESPEC_VARIANT: - { - ctf_field_class_variant *variant_decl; - - ret = visit_variant_decl(ctx, node->u.variant.name, node->u.variant.choice, - &node->u.variant.declaration_list, node->u.variant.has_body, - &variant_decl); - if (ret) { - BT_ASSERT(!variant_decl); - goto error; - } - - *decl = &variant_decl->base; - break; - } - case TYPESPEC_ENUM: - { - ctf_field_class_enum *enum_decl; - - ret = visit_enum_decl(ctx, node->u._enum.enum_id, node->u._enum.container_field_class, - &node->u._enum.enumerator_list, node->u._enum.has_body, &enum_decl); - if (ret) { - BT_ASSERT(!enum_decl); - goto error; - } - - *decl = &enum_decl->base.base.base; - break; - } - case TYPESPEC_VOID: - case TYPESPEC_CHAR: - case TYPESPEC_SHORT: - case TYPESPEC_INT: - case TYPESPEC_LONG: - case TYPESPEC_FLOAT: - case TYPESPEC_DOUBLE: - case TYPESPEC_SIGNED: - case TYPESPEC_UNSIGNED: - case TYPESPEC_BOOL: - case TYPESPEC_COMPLEX: - case TYPESPEC_IMAGINARY: - case TYPESPEC_CONST: - case TYPESPEC_ID_TYPE: - ret = visit_field_class_specifier(ctx, ts_list, decl); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, "Cannot visit field class specifier: ret=%d", - ret); - BT_ASSERT(!*decl); - goto error; - } - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, - "Unexpected field class specifier type: node-type=%d", - first->u.field_class_specifier.type); - ret = -EINVAL; - goto error; - } - - BT_ASSERT(*decl); - return 0; - -error: - ctf_field_class_destroy(*decl); - *decl = NULL; - return ret; -} - -static int visit_event_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node, - struct ctf_event_class *event_class, uint64_t *stream_id, - int *set) -{ - int ret = 0; - char *left = NULL; - - switch (node->type) { - case NODE_TYPEDEF: - ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list, - &node->u.field_class_def.field_class_declarators); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot add field class found in event class."); - goto error; - } - break; - case NODE_TYPEALIAS: - ret = visit_field_class_alias(ctx, node->u.field_class_alias.target, - node->u.field_class_alias.alias); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Cannot add field class alias found in event class."); - goto error; - } - break; - case NODE_CTF_EXPRESSION: - { - left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); - if (!left) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); - ret = -EINVAL; - goto error; - } - - if (strcmp(left, "name") == 0) { - /* This is already known at this stage */ - if (_IS_SET(set, _EVENT_NAME_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "name", "event class"); - ret = -EPERM; - goto error; - } - - _SET(set, _EVENT_NAME_SET); - } else if (strcmp(left, "id") == 0) { - int64_t id = -1; - - if (_IS_SET(set, _EVENT_ID_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "event class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id); - /* Only read "id" if get_unary_unsigned() succeeded. */ - if (ret || (!ret && id < 0)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Unexpected unary expression for event class's `id` attribute."); - ret = -EINVAL; - goto error; - } - - event_class->id = id; - _SET(set, _EVENT_ID_SET); - } else if (strcmp(left, "stream_id") == 0) { - if (_IS_SET(set, _EVENT_STREAM_ID_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "stream_id", "event class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, stream_id); - - /* - * Only read "stream_id" if get_unary_unsigned() - * succeeded. - */ - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Unexpected unary expression for event class's `stream_id` attribute."); - ret = -EINVAL; - goto error; - } - - _SET(set, _EVENT_STREAM_ID_SET); - } else if (strcmp(left, "context") == 0) { - if (_IS_SET(set, _EVENT_CONTEXT_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate `context` entry in event class."); - ret = -EPERM; - goto error; - } - - ret = visit_field_class_specifier_list( - ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), - &event_class->spec_context_fc); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Cannot create event class's context field class."); - goto error; - } - - BT_ASSERT(event_class->spec_context_fc); - _SET(set, _EVENT_CONTEXT_SET); - } else if (strcmp(left, "fields") == 0) { - if (_IS_SET(set, _EVENT_FIELDS_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate `fields` entry in event class."); - ret = -EPERM; - goto error; - } - - ret = visit_field_class_specifier_list( - ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), - &event_class->payload_fc); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Cannot create event class's payload field class."); - goto error; - } - - BT_ASSERT(event_class->payload_fc); - _SET(set, _EVENT_FIELDS_SET); - } else if (strcmp(left, "loglevel") == 0) { - uint64_t loglevel_value; - bool is_log_level_known = true; - bt_event_class_log_level log_level; - - if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "loglevel", "event class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &loglevel_value); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Unexpected unary expression for event class's `loglevel` attribute."); - ret = -EINVAL; - goto error; - } - - switch (loglevel_value) { - case 0: - log_level = BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY; - break; - case 1: - log_level = BT_EVENT_CLASS_LOG_LEVEL_ALERT; - break; - case 2: - log_level = BT_EVENT_CLASS_LOG_LEVEL_CRITICAL; - break; - case 3: - log_level = BT_EVENT_CLASS_LOG_LEVEL_ERROR; - break; - case 4: - log_level = BT_EVENT_CLASS_LOG_LEVEL_WARNING; - break; - case 5: - log_level = BT_EVENT_CLASS_LOG_LEVEL_NOTICE; - break; - case 6: - log_level = BT_EVENT_CLASS_LOG_LEVEL_INFO; - break; - case 7: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM; - break; - case 8: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM; - break; - case 9: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS; - break; - case 10: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE; - break; - case 11: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT; - break; - case 12: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION; - break; - case 13: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE; - break; - case 14: - log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG; - break; - default: - is_log_level_known = false; - _BT_COMP_LOGW_NODE( - node, - "Not setting event class's log level because its value is unknown: " - "log-level=%" PRIu64, - loglevel_value); - } - - if (is_log_level_known) { - ctf_event_class_set_log_level(event_class, log_level); - } - - _SET(set, _EVENT_LOG_LEVEL_SET); - } else if (strcmp(left, "model.emf.uri") == 0) { - char *right; - - if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "model.emf.uri", "event class"); - ret = -EPERM; - goto error; - } - - right = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.right); - if (!right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, - "Unexpected unary expression for event class's `model.emf.uri` attribute."); - ret = -EINVAL; - goto error; - } - - if (strlen(right) == 0) { - _BT_COMP_LOGW_NODE(node, "Not setting event class's EMF URI because it's empty."); - } else { - g_string_assign(event_class->emf_uri, right); - } - - g_free(right); - _SET(set, _EVENT_MODEL_EMF_URI_SET); - } else { - _BT_COMP_LOGW_NODE(node, - "Unknown attribute in event class: " - "attr-name=\"%s\"", - left); - } - - g_free(left); - left = NULL; - break; - } - default: - ret = -EPERM; - goto error; - } - - goto end; - -error: - g_free(left); - -end: - return ret; -} - -static char *get_event_decl_name(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) -{ - char *left = NULL; - char *name = NULL; - struct ctf_node *iter; - struct bt_list_head *decl_list = &node->u.event.declaration_list; - - bt_list_for_each_entry (iter, decl_list, siblings) { - if (iter->type != NODE_CTF_EXPRESSION) { - continue; - } - - left = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.left); - if (!left) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot concatenate unary strings."); - goto error; - } - - if (strcmp(left, "name") == 0) { - name = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.right); - if (!name) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - iter, "Unexpected unary expression for event class's `name` attribute."); - goto error; - } - } - - g_free(left); - left = NULL; - - if (name) { - break; - } - } - - return name; - -error: - g_free(left); - return NULL; -} - -static int visit_event_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) -{ - int ret = 0; - int set = 0; - struct ctf_node *iter; - uint64_t stream_id = 0; - char *event_name = NULL; - struct ctf_event_class *event_class = NULL; - struct 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; - } - - node->visited = TRUE; - event_name = get_event_decl_name(ctx, node); - if (!event_name) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Missing `name` attribute in event class."); - ret = -EPERM; - goto error; - } - - event_class = ctf_event_class_create(); - BT_ASSERT(event_class); - g_string_assign(event_class->name, event_name); - _TRY_PUSH_SCOPE_OR_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 (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, - "Cannot visit event class's entry: " - "ret=%d", - ret); - goto error; - } - } - - if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) { - /* - * Allow missing stream_id if there is only a single - * stream class. - */ - switch (ctx->ctf_tc->stream_classes->len) { - case 0: - /* Create implicit stream class if there's none */ - stream_id = 0; - stream_class = ctf_stream_class_create(); - BT_ASSERT(stream_class); - stream_class->id = stream_id; - g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class); - break; - case 1: - /* Single stream class: get its ID */ - stream_class = (ctf_stream_class *) ctx->ctf_tc->stream_classes->pdata[0]; - stream_id = stream_class->id; - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Missing `stream_id` attribute in event class."); - ret = -EPERM; - goto error; - } - } - - /* We have the stream ID now; get the stream class if found */ - if (!stream_class) { - stream_class = ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, stream_id); - if (!stream_class) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Cannot find stream class at this point: " - "id=%" PRId64, - stream_id); - ret = -EINVAL; - goto error; - } - } - - BT_ASSERT(stream_class); - - if (!_IS_SET(&set, _EVENT_ID_SET)) { - /* Allow only one event without ID per stream */ - if (stream_class->event_classes->len != 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Missing `id` attribute in event class."); - ret = -EPERM; - goto error; - } - - /* Automatic ID */ - event_class->id = 0; - } - - if (ctf_stream_class_borrow_event_class_by_id(stream_class, event_class->id)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Duplicate event class (same ID) in the same stream class: " - "id=%" PRId64, - event_class->id); - ret = -EEXIST; - goto error; - } - - ctf_stream_class_append_event_class(stream_class, event_class); - event_class = NULL; - goto end; - -error: - ctf_event_class_destroy(event_class); - event_class = NULL; - - if (ret >= 0) { - ret = -1; - } - -end: - if (pop_scope) { - ctx_pop_scope(ctx); - } - - g_free(event_name); - - return ret; -} - -static int auto_map_field_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx, - struct ctf_field_class *fc) -{ - struct ctf_clock_class *clock_class_to_map_to = NULL; - uint64_t clock_class_count; - - if (!fc) { - return 0; - } - - if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - return 0; - } - - ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - - if (int_fc->mapped_clock_class) { - /* Already mapped */ - return 0; - } - - clock_class_count = ctx->ctf_tc->clock_classes->len; - - switch (clock_class_count) { - case 0: - /* - * No clock class exists in the trace at this point. Create an - * implicit one at 1 GHz, named `default`, and use this clock - * class. - */ - clock_class_to_map_to = ctf_clock_class_create(); - BT_ASSERT(clock_class_to_map_to); - clock_class_to_map_to->frequency = UINT64_C(1000000000); - g_string_assign(clock_class_to_map_to->name, "default"); - g_ptr_array_add(ctx->ctf_tc->clock_classes, clock_class_to_map_to); - break; - case 1: - /* - * Only one clock class exists in the trace at this point: use - * this one. - */ - clock_class_to_map_to = (ctf_clock_class *) ctx->ctf_tc->clock_classes->pdata[0]; - break; - default: - /* - * Timestamp field not mapped to a clock class and there's more - * than one clock class in the trace: this is an error. - */ - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Timestamp field found with no mapped clock class, " - "but there's more than one clock class in the trace at this point."); - return -1; - } - - BT_ASSERT(clock_class_to_map_to); - int_fc->mapped_clock_class = clock_class_to_map_to; - - return 0; -} - -static int auto_map_fields_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx, - struct ctf_field_class *root_fc, - const char *field_name) -{ - int ret = 0; - uint64_t i, count; - struct ctf_field_class_struct *struct_fc = (ctf_field_class_struct *) root_fc; - struct ctf_field_class_variant *var_fc = (ctf_field_class_variant *) root_fc; - - if (!root_fc) { - goto end; - } - - if (root_fc->type != CTF_FIELD_CLASS_TYPE_STRUCT && - root_fc->type != CTF_FIELD_CLASS_TYPE_VARIANT) { - goto end; - } - - if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) { - count = struct_fc->members->len; - } else { - count = var_fc->options->len; - } - - for (i = 0; i < count; i++) { - struct ctf_named_field_class *named_fc = NULL; - - if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) { - named_fc = ctf_field_class_struct_borrow_member_by_index(struct_fc, i); - } else if (root_fc->type == CTF_FIELD_CLASS_TYPE_VARIANT) { - named_fc = ctf_field_class_variant_borrow_option_by_index(var_fc, i); - } else { - bt_common_abort(); - } - - if (strcmp(named_fc->name->str, field_name) == 0) { - ret = auto_map_field_to_trace_clock_class(ctx, named_fc->fc); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot automatically map field to trace's clock class: " - "field-name=\"%s\"", - field_name); - goto end; - } - } - - ret = auto_map_fields_to_trace_clock_class(ctx, named_fc->fc, field_name); - if (ret) { - _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( - "Cannot automatically map structure or variant field class's fields to trace's clock class: " - "field-name=\"%s\", root-field-name=\"%s\"", - field_name, named_fc->name->str); - goto end; - } - } - -end: - return ret; -} - -static int visit_stream_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node, - struct ctf_stream_class *stream_class, int *set) -{ - int ret = 0; - char *left = NULL; - - switch (node->type) { - case NODE_TYPEDEF: - ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list, - &node->u.field_class_def.field_class_declarators); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot add field class found in stream class."); - goto error; - } - break; - case NODE_TYPEALIAS: - ret = visit_field_class_alias(ctx, node->u.field_class_alias.target, - node->u.field_class_alias.alias); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Cannot add field class alias found in stream class."); - goto error; - } - break; - case NODE_CTF_EXPRESSION: - { - left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); - if (!left) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); - ret = -EINVAL; - goto error; - } - - if (strcmp(left, "id") == 0) { - int64_t id; - - if (_IS_SET(set, _STREAM_ID_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "stream declaration"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id); - - /* Only read "id" if get_unary_unsigned() succeeded. */ - if (ret || (!ret && id < 0)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Unexpected unary expression for stream class's `id` attribute."); - ret = -EINVAL; - goto error; - } - - if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, id)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Duplicate stream class (same ID): id=%" PRId64, id); - ret = -EEXIST; - goto error; - } - - stream_class->id = id; - _SET(set, _STREAM_ID_SET); - } else if (strcmp(left, "event.header") == 0) { - if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Duplicate `event.header` entry in stream class."); - ret = -EPERM; - goto error; - } - - ret = visit_field_class_specifier_list( - ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), - &stream_class->event_header_fc); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Cannot create stream class's event header field class."); - goto error; - } - - BT_ASSERT(stream_class->event_header_fc); - ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->event_header_fc, - "timestamp"); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, - "Cannot automatically map specific event header field class fields named `timestamp` to trace's clock class."); - goto error; - } - - _SET(set, _STREAM_EVENT_HEADER_SET); - } else if (strcmp(left, "event.context") == 0) { - if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Duplicate `event.context` entry in stream class."); - ret = -EPERM; - goto error; - } - - ret = visit_field_class_specifier_list( - ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), - &stream_class->event_common_context_fc); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Cannot create stream class's event context field class."); - goto error; - } - - BT_ASSERT(stream_class->event_common_context_fc); - _SET(set, _STREAM_EVENT_CONTEXT_SET); - } else if (strcmp(left, "packet.context") == 0) { - if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Duplicate `packet.context` entry in stream class."); - ret = -EPERM; - goto error; - } - - ret = visit_field_class_specifier_list( - ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), - &stream_class->packet_context_fc); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Cannot create stream class's packet context field class."); - goto error; - } - - BT_ASSERT(stream_class->packet_context_fc); - ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->packet_context_fc, - "timestamp_begin"); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, - "Cannot automatically map specific packet context field class fields named `timestamp_begin` to trace's clock class."); - goto error; - } - - ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->packet_context_fc, - "timestamp_end"); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, - "Cannot automatically map specific packet context field class fields named `timestamp_end` to trace's clock class."); - goto error; - } - - _SET(set, _STREAM_PACKET_CONTEXT_SET); - } else { - _BT_COMP_LOGW_NODE(node, - "Unknown attribute in stream class: " - "attr-name=\"%s\"", - left); - } - - g_free(left); - left = NULL; - break; - } - - default: - ret = -EPERM; - goto error; - } - - return 0; - -error: - g_free(left); - return ret; -} - -static int visit_stream_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) -{ - int set = 0; - int ret = 0; - struct ctf_node *iter; - struct ctf_stream_class *stream_class = NULL; - struct bt_list_head *decl_list = &node->u.stream.declaration_list; - - if (node->visited) { - goto end; - } - - node->visited = TRUE; - stream_class = ctf_stream_class_create(); - BT_ASSERT(stream_class); - _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); - - bt_list_for_each_entry (iter, decl_list, siblings) { - ret = visit_stream_decl_entry(ctx, iter, stream_class, &set); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, - "Cannot visit stream class's entry: " - "ret=%d", - ret); - ctx_pop_scope(ctx); - goto error; - } - } - - ctx_pop_scope(ctx); - - if (_IS_SET(&set, _STREAM_ID_SET)) { - /* Check that packet header has `stream_id` field */ - struct ctf_named_field_class *named_fc = NULL; - - if (!ctx->ctf_tc->packet_header_fc) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Stream class has a `id` attribute, " - "but trace has no packet header field class."); - ret = -EINVAL; - goto error; - } - - named_fc = ctf_field_class_struct_borrow_member_by_name( - ctf_field_class_as_struct(ctx->ctf_tc->packet_header_fc), "stream_id"); - if (!named_fc) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Stream class has a `id` attribute, " - "but trace's packet header field class has no `stream_id` field."); - ret = -EINVAL; - goto error; - } - - if (named_fc->fc->type != CTF_FIELD_CLASS_TYPE_INT && - named_fc->fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, - "Stream class has a `id` attribute, " - "but trace's packet header field class's `stream_id` field is not an integer field class."); - ret = -EINVAL; - goto error; - } - } else { - /* Allow only _one_ ID-less stream */ - if (ctx->ctf_tc->stream_classes->len != 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, - "Missing `id` attribute in stream class as there's more than one stream class in the trace."); - ret = -EPERM; - goto error; - } - - /* Automatic ID: 0 */ - stream_class->id = 0; - } - - /* - * Make sure that this stream class's ID is currently unique in - * the trace. - */ - if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, stream_class->id)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate stream class (same ID): id=%" PRId64, - stream_class->id); - ret = -EINVAL; - goto error; - } - - g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class); - stream_class = NULL; - goto end; - -error: - ctf_stream_class_destroy(stream_class); - stream_class = NULL; - -end: - return ret; -} - -static int visit_trace_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node, - int *set) -{ - int ret = 0; - char *left = NULL; - uint64_t val; - - switch (node->type) { - case NODE_TYPEDEF: - ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list, - &node->u.field_class_def.field_class_declarators); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Cannot add field class found in trace (`trace` block)."); - goto error; - } - break; - case NODE_TYPEALIAS: - ret = visit_field_class_alias(ctx, node->u.field_class_alias.target, - node->u.field_class_alias.alias); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Cannot add field class alias found in trace (`trace` block)."); - goto error; - } - break; - case NODE_CTF_EXPRESSION: - { - left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); - if (!left) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); - ret = -EINVAL; - goto error; - } - - if (strcmp(left, "major") == 0) { - if (_IS_SET(set, _TRACE_MAJOR_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "major", "trace"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Unexpected unary expression for trace's `major` attribute."); - ret = -EINVAL; - goto error; - } - - if (val != 1) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Invalid trace's `minor` attribute: expecting 1."); - ret = -EINVAL; - goto error; - } - - ctx->ctf_tc->major = val; - _SET(set, _TRACE_MAJOR_SET); - } else if (strcmp(left, "minor") == 0) { - if (_IS_SET(set, _TRACE_MINOR_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "minor", "trace"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Unexpected unary expression for trace's `minor` attribute."); - ret = -EINVAL; - goto error; - } - - if (val != 8) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Invalid trace's `minor` attribute: expecting 8."); - ret = -EINVAL; - goto error; - } - - ctx->ctf_tc->minor = val; - _SET(set, _TRACE_MINOR_SET); - } else if (strcmp(left, "uuid") == 0) { - if (_IS_SET(set, _TRACE_UUID_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "uuid", "trace"); - ret = -EPERM; - goto error; - } - - ret = get_unary_uuid(ctx, &node->u.ctf_expression.right, ctx->ctf_tc->uuid); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Invalid trace's `uuid` attribute."); - goto error; - } - - ctx->ctf_tc->is_uuid_set = true; - _SET(set, _TRACE_UUID_SET); - } else if (strcmp(left, "byte_order") == 0) { - /* Default byte order is already known at this stage */ - if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace"); - ret = -EPERM; - goto error; - } - - BT_ASSERT(ctx->ctf_tc->default_byte_order != CTF_BYTE_ORDER_UNKNOWN); - _SET(set, _TRACE_BYTE_ORDER_SET); - } else if (strcmp(left, "packet.header") == 0) { - if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate `packet.header` entry in trace."); - ret = -EPERM; - goto error; - } - - ret = visit_field_class_specifier_list( - ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), - &ctx->ctf_tc->packet_header_fc); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Cannot create trace's packet header field class."); - goto error; - } - - BT_ASSERT(ctx->ctf_tc->packet_header_fc); - _SET(set, _TRACE_PACKET_HEADER_SET); - } else { - _BT_COMP_LOGW_NODE(node, - "Unknown attribute in stream class: " - "attr-name=\"%s\"", - left); - } - - g_free(left); - left = NULL; - break; - } - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unknown expression in trace."); - ret = -EINVAL; - goto error; - } - - return 0; - -error: - g_free(left); - return ret; -} - -static int visit_trace_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) -{ - int ret = 0; - int set = 0; - struct ctf_node *iter; - struct bt_list_head *decl_list = &node->u.trace.declaration_list; - - if (node->visited) { - goto end; - } - - node->visited = TRUE; - - if (ctx->is_trace_visited) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block)."); - ret = -EEXIST; - goto error; - } - - _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); - - bt_list_for_each_entry (iter, decl_list, siblings) { - ret = visit_trace_decl_entry(ctx, iter, &set); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, - "Cannot visit trace's entry (`trace` block): " - "ret=%d", - ret); - ctx_pop_scope(ctx); - goto error; - } - } - - ctx_pop_scope(ctx); - - if (!_IS_SET(&set, _TRACE_MAJOR_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Missing `major` attribute in trace (`trace` block)."); - ret = -EPERM; - goto error; - } - - if (!_IS_SET(&set, _TRACE_MINOR_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Missing `minor` attribute in trace (`trace` block)."); - ret = -EPERM; - goto error; - } - - if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Missing `byte_order` attribute in trace (`trace` block)."); - ret = -EPERM; - goto error; - } - - ctx->is_trace_visited = true; - -end: - return 0; - -error: - return ret; -} - -static int visit_env(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) -{ - int ret = 0; - char *left = NULL; - struct ctf_node *entry_node; - struct bt_list_head *decl_list = &node->u.env.declaration_list; - - if (node->visited) { - goto end; - } - - node->visited = TRUE; - - bt_list_for_each_entry (entry_node, decl_list, siblings) { - struct bt_list_head *right_head = &entry_node->u.ctf_expression.right; - - if (entry_node->type != NODE_CTF_EXPRESSION) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, - "Wrong expression in environment entry: " - "node-type=%d", - entry_node->type); - ret = -EPERM; - goto error; - } - - left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left); - if (!left) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot get environment entry's name."); - ret = -EINVAL; - goto error; - } - - if (is_unary_string(right_head)) { - char *right = ctf_ast_concatenate_unary_strings(right_head); - - if (!right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, - "Unexpected unary expression for environment entry's value: " - "name=\"%s\"", - left); - ret = -EINVAL; - goto error; - } - - if (strcmp(left, "tracer_name") == 0) { - if (strncmp(right, "lttng", 5) == 0) { - BT_COMP_LOGI("Detected LTTng trace from `%s` environment value: " - "tracer-name=\"%s\"", - left, right); - ctx->is_lttng = true; - } - } - - ctf_trace_class_append_env_entry(ctx->ctf_tc, left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR, - right, 0); - g_free(right); - } else if (is_unary_unsigned(right_head) || is_unary_signed(right_head)) { - int64_t v; - - if (is_unary_unsigned(right_head)) { - ret = get_unary_unsigned(ctx, right_head, (uint64_t *) &v); - } else { - ret = get_unary_signed(right_head, &v); - } - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, - "Unexpected unary expression for environment entry's value: " - "name=\"%s\"", - left); - ret = -EINVAL; - goto error; - } - - ctf_trace_class_append_env_entry(ctx->ctf_tc, left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT, - NULL, v); - } else { - _BT_COMP_LOGW_NODE(entry_node, - "Environment entry has unknown type: " - "name=\"%s\"", - left); - } - - g_free(left); - left = NULL; - } - -end: - return 0; - -error: - g_free(left); - return ret; -} - -static int set_trace_byte_order(struct ctf_visitor_generate_ir *ctx, struct ctf_node *trace_node) -{ - int ret = 0; - int set = 0; - char *left = NULL; - struct ctf_node *node; - struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list; - - bt_list_for_each_entry (node, decl_list, siblings) { - if (node->type == NODE_CTF_EXPRESSION) { - struct ctf_node *right_node; - - left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); - if (!left) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); - ret = -EINVAL; - goto error; - } - - if (strcmp(left, "byte_order") == 0) { - enum ctf_byte_order bo; - - if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace"); - ret = -EPERM; - goto error; - } - - _SET(&set, _TRACE_BYTE_ORDER_SET); - right_node = - _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings); - bo = byte_order_from_unary_expr(ctx, right_node); - if (bo == CTF_BYTE_ORDER_UNKNOWN) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Invalid `byte_order` attribute in trace (`trace` block): " - "expecting `le`, `be`, or `network`."); - ret = -EINVAL; - goto error; - } else if (bo == CTF_BYTE_ORDER_DEFAULT) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - node, "Invalid `byte_order` attribute in trace (`trace` block): " - "cannot be set to `native` here."); - ret = -EPERM; - goto error; - } - - ctx->ctf_tc->default_byte_order = bo; - } - - g_free(left); - left = NULL; - } - } - - if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(trace_node, - "Missing `byte_order` attribute in trace (`trace` block)."); - ret = -EINVAL; - goto error; - } - - return 0; - -error: - g_free(left); - return ret; -} - -static int visit_clock_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *entry_node, - struct ctf_clock_class *clock, int *set, int64_t *offset_seconds, - uint64_t *offset_cycles) -{ - int ret = 0; - char *left = NULL; - - if (entry_node->type != NODE_CTF_EXPRESSION) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type=%d", - entry_node->type); - ret = -EPERM; - goto error; - } - - left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left); - if (!left) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot concatenate unary strings."); - ret = -EINVAL; - goto error; - } - - if (strcmp(left, "name") == 0) { - char *right; - - if (_IS_SET(set, _CLOCK_NAME_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "name", "clock class"); - ret = -EPERM; - goto error; - } - - right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right); - if (!right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Unexpected unary expression for clock class's `name` attribute."); - ret = -EINVAL; - goto error; - } - - g_string_assign(clock->name, right); - g_free(right); - _SET(set, _CLOCK_NAME_SET); - } else if (strcmp(left, "uuid") == 0) { - bt_uuid_t uuid; - - if (_IS_SET(set, _CLOCK_UUID_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "uuid", "clock class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_uuid(ctx, &entry_node->u.ctf_expression.right, uuid); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Invalid clock class's `uuid` attribute."); - goto error; - } - - clock->has_uuid = true; - bt_uuid_copy(clock->uuid, uuid); - _SET(set, _CLOCK_UUID_SET); - } else if (strcmp(left, "description") == 0) { - char *right; - - if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "description", "clock class"); - ret = -EPERM; - goto error; - } - - right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right); - if (!right) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, - "Unexpected unary expression for clock class's `description` attribute."); - ret = -EINVAL; - goto error; - } - - g_string_assign(clock->description, right); - g_free(right); - _SET(set, _CLOCK_DESCRIPTION_SET); - } else if (strcmp(left, "freq") == 0) { - uint64_t freq = UINT64_C(-1); - - if (_IS_SET(set, _CLOCK_FREQ_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "freq", "clock class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &freq); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Unexpected unary expression for clock class's `freq` attribute."); - ret = -EINVAL; - goto error; - } - - if (freq == UINT64_C(-1) || freq == 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, - "Invalid clock class frequency: freq=%" PRIu64, freq); - ret = -EINVAL; - goto error; - } - - clock->frequency = freq; - _SET(set, _CLOCK_FREQ_SET); - } else if (strcmp(left, "precision") == 0) { - uint64_t precision; - - if (_IS_SET(set, _CLOCK_PRECISION_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "precision", "clock class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &precision); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Unexpected unary expression for clock class's `precision` attribute."); - ret = -EINVAL; - goto error; - } - - clock->precision = precision; - _SET(set, _CLOCK_PRECISION_SET); - } else if (strcmp(left, "offset_s") == 0) { - if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset_s", "clock class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_signed(&entry_node->u.ctf_expression.right, offset_seconds); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Unexpected unary expression for clock class's `offset_s` attribute."); - ret = -EINVAL; - goto error; - } - - _SET(set, _CLOCK_OFFSET_S_SET); - } else if (strcmp(left, "offset") == 0) { - if (_IS_SET(set, _CLOCK_OFFSET_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset", "clock class"); - ret = -EPERM; - goto error; - } - - ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, offset_cycles); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Unexpected unary expression for clock class's `offset` attribute."); - ret = -EINVAL; - goto error; - } - - _SET(set, _CLOCK_OFFSET_SET); - } else if (strcmp(left, "absolute") == 0) { - struct ctf_node *right; - - if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "absolute", "clock class"); - ret = -EPERM; - goto error; - } - - right = - _BT_LIST_FIRST_ENTRY(&entry_node->u.ctf_expression.right, struct ctf_node, siblings); - ret = get_boolean(ctx, right); - if (ret < 0) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - entry_node, "Unexpected unary expression for clock class's `absolute` attribute."); - ret = -EINVAL; - goto error; - } - - clock->is_absolute = ret; - _SET(set, _CLOCK_ABSOLUTE_SET); - } else { - _BT_COMP_LOGW_NODE(entry_node, "Unknown attribute in clock class: attr-name=\"%s\"", left); - } - - g_free(left); - left = NULL; - return 0; - -error: - g_free(left); - return ret; -} - -static inline uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns) -{ - uint64_t cycles; - - /* 1GHz */ - if (frequency == UINT64_C(1000000000)) { - cycles = ns; - } else { - cycles = (uint64_t) (((double) ns * (double) frequency) / 1e9); - } - - return cycles; -} - -static void calibrate_clock_class_offsets(int64_t *offset_seconds, uint64_t *offset_cycles, - uint64_t freq) -{ - if (*offset_cycles >= freq) { - const uint64_t s_in_offset_cycles = *offset_cycles / freq; - - *offset_seconds += (int64_t) s_in_offset_cycles; - *offset_cycles -= (s_in_offset_cycles * freq); - } -} - -static void apply_clock_class_is_absolute(struct ctf_visitor_generate_ir *ctx, - struct ctf_clock_class *clock) -{ - if (ctx->decoder_config.force_clock_class_origin_unix_epoch) { - clock->is_absolute = true; - } - - return; -} - -static void apply_clock_class_offset(struct ctf_visitor_generate_ir *ctx, - struct ctf_clock_class *clock) -{ - uint64_t freq; - int64_t offset_s_to_apply = ctx->decoder_config.clock_class_offset_s; - uint64_t offset_ns_to_apply; - int64_t cur_offset_s; - uint64_t cur_offset_cycles; - - if (ctx->decoder_config.clock_class_offset_s == 0 && - ctx->decoder_config.clock_class_offset_ns == 0) { - goto end; - } - - /* Transfer nanoseconds to seconds as much as possible */ - if (ctx->decoder_config.clock_class_offset_ns < 0) { - const int64_t abs_ns = -ctx->decoder_config.clock_class_offset_ns; - const int64_t abs_extra_s = abs_ns / INT64_C(1000000000) + 1; - const int64_t extra_s = -abs_extra_s; - const int64_t offset_ns = - ctx->decoder_config.clock_class_offset_ns - (extra_s * INT64_C(1000000000)); - - BT_ASSERT(offset_ns > 0); - offset_ns_to_apply = (uint64_t) offset_ns; - offset_s_to_apply += extra_s; - } else { - const int64_t extra_s = ctx->decoder_config.clock_class_offset_ns / INT64_C(1000000000); - const int64_t offset_ns = - ctx->decoder_config.clock_class_offset_ns - (extra_s * INT64_C(1000000000)); - - BT_ASSERT(offset_ns >= 0); - offset_ns_to_apply = (uint64_t) offset_ns; - offset_s_to_apply += extra_s; - } - - freq = clock->frequency; - cur_offset_s = clock->offset_seconds; - cur_offset_cycles = clock->offset_cycles; - - /* Apply offsets */ - cur_offset_s += offset_s_to_apply; - cur_offset_cycles += cycles_from_ns(freq, offset_ns_to_apply); - - /* - * Recalibrate offsets because the part in cycles can be greater - * than the frequency at this point. - */ - calibrate_clock_class_offsets(&cur_offset_s, &cur_offset_cycles, freq); - - /* Set final offsets */ - clock->offset_seconds = cur_offset_s; - clock->offset_cycles = cur_offset_cycles; - -end: - return; -} - -static int visit_clock_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *clock_node) -{ - int ret = 0; - int set = 0; - struct ctf_clock_class *clock; - struct ctf_node *entry_node; - struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list; - const char *clock_class_name; - int64_t offset_seconds = 0; - uint64_t offset_cycles = 0; - uint64_t freq; - - if (clock_node->visited) { - return 0; - } - - clock_node->visited = TRUE; - - /* CTF 1.8's default frequency for a clock class is 1 GHz */ - clock = ctf_clock_class_create(); - if (!clock) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(clock_node, "Cannot create default clock class."); - ret = -ENOMEM; - goto end; - } - - bt_list_for_each_entry (entry_node, decl_list, siblings) { - ret = visit_clock_decl_entry(ctx, entry_node, clock, &set, &offset_seconds, &offset_cycles); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot visit clock class's entry: ret=%d", - ret); - goto end; - } - } - - if (!_IS_SET(&set, _CLOCK_NAME_SET)) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(clock_node, "Missing `name` attribute in clock class."); - ret = -EPERM; - goto end; - } - - clock_class_name = clock->name->str; - BT_ASSERT(clock_class_name); - if (ctx->is_lttng && strcmp(clock_class_name, "monotonic") == 0) { - /* - * Old versions of LTTng forgot to set its clock class - * as absolute, even if it is. This is important because - * it's a condition to be able to sort messages - * from different sources. - */ - clock->is_absolute = true; - } - - /* - * Adjust offsets so that the part in cycles is less than the - * frequency (move to the part in seconds). - */ - freq = clock->frequency; - calibrate_clock_class_offsets(&offset_seconds, &offset_cycles, freq); - BT_ASSERT(offset_cycles < clock->frequency); - clock->offset_seconds = offset_seconds; - clock->offset_cycles = offset_cycles; - apply_clock_class_offset(ctx, clock); - apply_clock_class_is_absolute(ctx, clock); - g_ptr_array_add(ctx->ctf_tc->clock_classes, clock); - clock = NULL; - -end: - if (clock) { - ctf_clock_class_destroy(clock); - } - - return ret; -} - -static int visit_root_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *root_decl_node) -{ - int ret = 0; - - if (root_decl_node->visited) { - goto end; - } - - root_decl_node->visited = TRUE; - - switch (root_decl_node->type) { - case NODE_TYPEDEF: - ret = - visit_field_class_def(ctx, root_decl_node->u.field_class_def.field_class_specifier_list, - &root_decl_node->u.field_class_def.field_class_declarators); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, - "Cannot add field class found in root scope."); - goto end; - } - break; - case NODE_TYPEALIAS: - ret = visit_field_class_alias(ctx, root_decl_node->u.field_class_alias.target, - root_decl_node->u.field_class_alias.alias); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, - "Cannot add field class alias found in root scope."); - goto end; - } - break; - case NODE_TYPE_SPECIFIER_LIST: - { - struct ctf_field_class *decl = NULL; - - /* - * Just add the field class specifier to the root - * declaration scope. Put local reference. - */ - ret = visit_field_class_specifier_list(ctx, root_decl_node, &decl); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, - "Cannot visit root scope's field class: " - "ret=%d", - ret); - BT_ASSERT(!decl); - goto end; - } - - ctf_field_class_destroy(decl); - decl = NULL; - break; - } - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, "Unexpected node type: node-type=%d", - root_decl_node->type); - ret = -EPERM; - goto end; - } - -end: - return ret; -} - -struct ctf_visitor_generate_ir * -ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *decoder_config) -{ - struct ctf_visitor_generate_ir *ctx = NULL; - - /* Create visitor's context */ - ctx = ctx_create(decoder_config); - if (!ctx) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, decoder_config->log_level, decoder_config->self_comp, - "Cannot create visitor's context."); - goto error; - } - - goto end; - -error: - ctx_destroy(ctx); - ctx = NULL; - -end: - return ctx; -} - -void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor) -{ - ctx_destroy(visitor); -} - -bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *ctx) -{ - BT_ASSERT_DBG(ctx); - - if (ctx->trace_class) { - bt_trace_class_get_ref(ctx->trace_class); - } - - return ctx->trace_class; -} - -struct ctf_trace_class * -ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *ctx) -{ - BT_ASSERT_DBG(ctx); - BT_ASSERT_DBG(ctx->ctf_tc); - return ctx->ctf_tc; -} - -int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) -{ - int ret = 0; - - BT_COMP_LOGI_STR("Visiting metadata's AST to generate CTF IR objects."); - - switch (node->type) { - case NODE_ROOT: - { - struct ctf_node *iter; - bool got_trace_decl = false; - - /* - * The first thing we need is the native byte order of - * the trace block, because early class 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. - */ - if (ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_UNKNOWN) { - bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { - if (got_trace_decl) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block)."); - ret = -1; - goto end; - } - - ret = set_trace_byte_order(ctx, iter); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, - "Cannot set trace's native byte order: " - "ret=%d", - ret); - goto end; - } - - got_trace_decl = true; - } - - if (!got_trace_decl) { - BT_COMP_LOGD_STR("Incomplete AST: need trace (`trace` block)."); - ret = -EINCOMPLETE; - goto end; - } - } - - BT_ASSERT(ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_LITTLE || - ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_BIG); - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - - /* Environment */ - bt_list_for_each_entry (iter, &node->u.root.env, siblings) { - ret = visit_env(ctx, iter); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE( - iter, - "Cannot visit trace's environment (`env` block) entry: " - "ret=%d", - ret); - goto end; - } - } - - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - - /* - * Visit clock blocks. - */ - bt_list_for_each_entry (iter, &node->u.root.clock, siblings) { - ret = visit_clock_decl(ctx, iter); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit clock class: ret=%d", ret); - goto end; - } - } - - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - - /* - * Visit root declarations next, as they can be used by any - * following entity. - */ - bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) { - ret = visit_root_decl(ctx, iter); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit root entry: ret=%d", ret); - goto end; - } - } - - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - - /* Callsite blocks are not supported */ - bt_list_for_each_entry (iter, &node->u.root.callsite, siblings) { - _BT_COMP_LOGW_NODE(iter, "\"callsite\" blocks are not supported as of this version."); - } - - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - - /* Trace */ - bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { - ret = visit_trace_decl(ctx, iter); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, - "Cannot visit trace (`trace` block): " - "ret=%d", - ret); - goto end; - } - } - - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - - /* Streams */ - bt_list_for_each_entry (iter, &node->u.root.stream, siblings) { - ret = visit_stream_decl(ctx, iter); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit stream class: ret=%d", ret); - goto end; - } - } - - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - - /* Events */ - bt_list_for_each_entry (iter, &node->u.root.event, siblings) { - ret = visit_event_decl(ctx, iter); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit event class: ret=%d", ret); - goto end; - } - } - - BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); - break; - } - default: - _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unexpected node type: node-type=%d", node->type); - ret = -EINVAL; - goto end; - } - - /* Update default clock classes */ - ret = ctf_trace_class_update_default_clock_classes(ctx->ctf_tc, &ctx->log_cfg); - if (ret) { - ret = -EINVAL; - goto end; - } - - /* Update trace class meanings */ - ret = ctf_trace_class_update_meanings(ctx->ctf_tc); - if (ret) { - ret = -EINVAL; - goto end; - } - - /* Update stream class configuration */ - ret = ctf_trace_class_update_stream_class_config(ctx->ctf_tc); - if (ret) { - ret = -EINVAL; - goto end; - } - - /* Update text arrays and sequences */ - ret = ctf_trace_class_update_text_array_sequence(ctx->ctf_tc); - if (ret) { - ret = -EINVAL; - goto end; - } - - /* Update structure/array/sequence alignments */ - ret = ctf_trace_class_update_alignments(ctx->ctf_tc); - if (ret) { - ret = -EINVAL; - goto end; - } - - /* Resolve sequence lengths and variant tags */ - ret = ctf_trace_class_resolve_field_classes(ctx->ctf_tc, &ctx->log_cfg); - if (ret) { - ret = -EINVAL; - goto end; - } - - if (ctx->trace_class) { - /* - * Update "in IR" for field classes. - * - * If we have no IR trace class, then we'll have no way - * to create IR fields anyway, so we leave all the - * `in_ir` members false. - */ - ret = ctf_trace_class_update_in_ir(ctx->ctf_tc); - if (ret) { - ret = -EINVAL; - goto end; - } - } - - /* Update saved value indexes */ - ret = ctf_trace_class_update_value_storing_indexes(ctx->ctf_tc); - if (ret) { - ret = -EINVAL; - goto end; - } - - /* Validate what we have so far */ - ret = ctf_trace_class_validate(ctx->ctf_tc, &ctx->log_cfg); - if (ret) { - ret = -EINVAL; - goto end; - } - - /* - * If there are fields which are not related to the CTF format - * itself in the packet header and in event header field - * classes, warn about it because they are never translated. - */ - ctf_trace_class_warn_meaningless_header_fields(ctx->ctf_tc, &ctx->log_cfg); - - if (ctx->trace_class) { - /* Copy new CTF metadata -> new IR metadata */ - ret = ctf_trace_class_translate(ctx->log_cfg.self_comp, ctx->trace_class, ctx->ctf_tc); - if (ret) { - ret = -EINVAL; - goto end; - } - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/metadata/visitor-parent-links.cpp b/src/plugins/ctf/common/metadata/visitor-parent-links.cpp deleted file mode 100644 index 84c504f9..00000000 --- a/src/plugins/ctf/common/metadata/visitor-parent-links.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * - * Common Trace Format Metadata Parent Link Creator. - */ - -#include - -#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) -#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/PARENT-LINKS-VISITOR" -#include "logging.hpp" - -#include "common/list.h" - -#include "ast.hpp" - -static int ctf_visitor_unary_expression(int depth, struct ctf_node *node, - struct meta_log_config *log_cfg) -{ - int ret = 0; - - switch (node->u.unary_expression.link) { - case UNARY_LINK_UNKNOWN: - case UNARY_DOTLINK: - case UNARY_ARROWLINK: - case UNARY_DOTDOTDOT: - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown expression link type: type=%d\n", - node->u.unary_expression.link); - return -EINVAL; - } - - switch (node->u.unary_expression.type) { - case UNARY_STRING: - case UNARY_SIGNED_CONSTANT: - case UNARY_UNSIGNED_CONSTANT: - break; - case UNARY_SBRAC: - node->u.unary_expression.u.sbrac_exp->parent = node; - ret = - ctf_visitor_unary_expression(depth + 1, node->u.unary_expression.u.sbrac_exp, log_cfg); - if (ret) - return ret; - break; - - case UNARY_UNKNOWN: - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown expression link type: type=%d\n", - node->u.unary_expression.link); - return -EINVAL; - } - return 0; -} - -static int ctf_visitor_type_specifier(int depth, struct ctf_node *node, - struct meta_log_config *log_cfg) -{ - int ret; - - switch (node->u.field_class_specifier.type) { - case TYPESPEC_VOID: - case TYPESPEC_CHAR: - case TYPESPEC_SHORT: - case TYPESPEC_INT: - case TYPESPEC_LONG: - case TYPESPEC_FLOAT: - case TYPESPEC_DOUBLE: - case TYPESPEC_SIGNED: - case TYPESPEC_UNSIGNED: - case TYPESPEC_BOOL: - case TYPESPEC_COMPLEX: - case TYPESPEC_IMAGINARY: - case TYPESPEC_CONST: - case TYPESPEC_ID_TYPE: - break; - case TYPESPEC_FLOATING_POINT: - case TYPESPEC_INTEGER: - case TYPESPEC_STRING: - case TYPESPEC_STRUCT: - case TYPESPEC_VARIANT: - case TYPESPEC_ENUM: - node->u.field_class_specifier.node->parent = node; - ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_specifier.node, log_cfg); - if (ret) - return ret; - break; - - case TYPESPEC_UNKNOWN: - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown type specifier: type=%d\n", - node->u.field_class_specifier.type); - return -EINVAL; - } - return 0; -} - -static int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node, - struct meta_log_config *log_cfg) -{ - int ret = 0; - struct ctf_node *iter; - - depth++; - - bt_list_for_each_entry (iter, &node->u.field_class_declarator.pointers, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - - switch (node->u.field_class_declarator.type) { - case TYPEDEC_ID: - break; - case TYPEDEC_NESTED: - if (node->u.field_class_declarator.u.nested.field_class_declarator) { - node->u.field_class_declarator.u.nested.field_class_declarator->parent = node; - ret = ctf_visitor_parent_links( - depth + 1, node->u.field_class_declarator.u.nested.field_class_declarator, log_cfg); - if (ret) - return ret; - } - if (!node->u.field_class_declarator.u.nested.abstract_array) { - bt_list_for_each_entry (iter, &node->u.field_class_declarator.u.nested.length, - siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - } - if (node->u.field_class_declarator.bitfield_len) { - node->u.field_class_declarator.bitfield_len = node; - ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_declarator.bitfield_len, - log_cfg); - if (ret) - return ret; - } - break; - case TYPEDEC_UNKNOWN: - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown type declarator: type=%d\n", - node->u.field_class_declarator.type); - return -EINVAL; - } - depth--; - return 0; -} - -int ctf_visitor_parent_links(int depth, struct ctf_node *node, struct meta_log_config *log_cfg) -{ - int ret = 0; - struct ctf_node *iter; - - if (node->visited) - return 0; - - switch (node->type) { - case NODE_ROOT: - bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.stream, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.event, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.clock, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.callsite, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_EVENT: - bt_list_for_each_entry (iter, &node->u.event.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_STREAM: - bt_list_for_each_entry (iter, &node->u.stream.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_ENV: - bt_list_for_each_entry (iter, &node->u.env.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_TRACE: - bt_list_for_each_entry (iter, &node->u.trace.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_CLOCK: - bt_list_for_each_entry (iter, &node->u.clock.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_CALLSITE: - bt_list_for_each_entry (iter, &node->u.callsite.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_CTF_EXPRESSION: - depth++; - bt_list_for_each_entry (iter, &node->u.ctf_expression.left, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.ctf_expression.right, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_UNARY_EXPRESSION: - return ctf_visitor_unary_expression(depth, node, log_cfg); - - case NODE_TYPEDEF: - depth++; - node->u.field_class_def.field_class_specifier_list->parent = node; - ret = ctf_visitor_parent_links(depth + 1, - node->u.field_class_def.field_class_specifier_list, log_cfg); - if (ret) - return ret; - bt_list_for_each_entry (iter, &node->u.field_class_def.field_class_declarators, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_TYPEALIAS_TARGET: - depth++; - node->u.field_class_alias_target.field_class_specifier_list->parent = node; - ret = ctf_visitor_parent_links( - depth + 1, node->u.field_class_alias_target.field_class_specifier_list, log_cfg); - if (ret) - return ret; - bt_list_for_each_entry (iter, &node->u.field_class_alias_target.field_class_declarators, - siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_TYPEALIAS_ALIAS: - depth++; - node->u.field_class_alias_name.field_class_specifier_list->parent = node; - ret = ctf_visitor_parent_links( - depth + 1, node->u.field_class_alias_name.field_class_specifier_list, log_cfg); - if (ret) - return ret; - bt_list_for_each_entry (iter, &node->u.field_class_alias_name.field_class_declarators, - siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_TYPEALIAS: - node->u.field_class_alias.target->parent = node; - ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.target, log_cfg); - if (ret) - return ret; - node->u.field_class_alias.alias->parent = node; - ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.alias, log_cfg); - if (ret) - return ret; - break; - - case NODE_TYPE_SPECIFIER_LIST: - bt_list_for_each_entry (iter, &node->u.field_class_specifier_list.head, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_TYPE_SPECIFIER: - ret = ctf_visitor_type_specifier(depth, node, log_cfg); - if (ret) - return ret; - break; - case NODE_POINTER: - break; - case NODE_TYPE_DECLARATOR: - ret = ctf_visitor_field_class_declarator(depth, node, log_cfg); - if (ret) - return ret; - break; - - case NODE_FLOATING_POINT: - bt_list_for_each_entry (iter, &node->u.floating_point.expressions, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_INTEGER: - bt_list_for_each_entry (iter, &node->u.integer.expressions, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_STRING: - bt_list_for_each_entry (iter, &node->u.string.expressions, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_ENUMERATOR: - bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_ENUM: - depth++; - if (node->u._enum.container_field_class) { - ret = ctf_visitor_parent_links(depth + 1, node->u._enum.container_field_class, log_cfg); - if (ret) - return ret; - } - - bt_list_for_each_entry (iter, &node->u._enum.enumerator_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - node->u.struct_or_variant_declaration.field_class_specifier_list->parent = node; - ret = ctf_visitor_parent_links( - depth + 1, node->u.struct_or_variant_declaration.field_class_specifier_list, log_cfg); - if (ret) - return ret; - bt_list_for_each_entry ( - iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_VARIANT: - bt_list_for_each_entry (iter, &node->u.variant.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_STRUCT: - bt_list_for_each_entry (iter, &node->u._struct.declaration_list, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u._struct.min_align, siblings) { - iter->parent = node; - ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_UNKNOWN: - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown node type: type=%d\n", node->type); - return -EINVAL; - } - return ret; -} diff --git a/src/plugins/ctf/common/metadata/visitor-semantic-validator.cpp b/src/plugins/ctf/common/metadata/visitor-semantic-validator.cpp deleted file mode 100644 index 4fad1360..00000000 --- a/src/plugins/ctf/common/metadata/visitor-semantic-validator.cpp +++ /dev/null @@ -1,996 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * - * Common Trace Format Metadata Semantic Validator. - */ - -#include - -#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) -#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/META/SEMANTIC-VALIDATOR-VISITOR" -#include "logging.hpp" - -#include "common/list.h" - -#include "ast.hpp" - -#define _bt_list_first_entry(ptr, type, member) bt_list_entry((ptr)->next, type, member) - -static int _ctf_visitor_semantic_check(int depth, struct ctf_node *node, - struct meta_log_config *log_cfg); - -static int ctf_visitor_unary_expression(int, struct ctf_node *node, struct meta_log_config *log_cfg) -{ - struct ctf_node *iter; - int is_ctf_exp = 0, is_ctf_exp_left = 0; - - switch (node->parent->type) { - case NODE_CTF_EXPRESSION: - is_ctf_exp = 1; - bt_list_for_each_entry (iter, &node->parent->u.ctf_expression.left, siblings) { - if (iter == node) { - is_ctf_exp_left = 1; - /* - * We are a left child of a ctf expression. - * We are only allowed to be a string. - */ - if (node->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Left child of a CTF expression is only allowed to be a string."); - goto errperm; - } - break; - } - } - /* Right child of a ctf expression can be any type of unary exp. */ - break; /* OK */ - case NODE_TYPE_DECLARATOR: - /* - * We are the length of a type declarator. - */ - switch (node->u.unary_expression.type) { - case UNARY_UNSIGNED_CONSTANT: - case UNARY_STRING: - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Children of field class declarator and `enum` can only be unsigned numeric constants or references to fields (e.g., `a.b.c`)."); - goto errperm; - } - break; /* OK */ - - case NODE_STRUCT: - /* - * We are the size of a struct align attribute. - */ - switch (node->u.unary_expression.type) { - case UNARY_UNSIGNED_CONSTANT: - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Structure alignment attribute can only be an unsigned numeric constant."); - goto errperm; - } - break; - - case NODE_ENUMERATOR: - /* The enumerator's parent has validated its validity already. */ - break; /* OK */ - - case NODE_UNARY_EXPRESSION: - /* - * We disallow nested unary expressions and "sbrac" unary - * expressions. - */ - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, - "Nested unary expressions not allowed (`()` and `[]`)."); - goto errperm; - - case NODE_ROOT: - case NODE_EVENT: - case NODE_STREAM: - case NODE_ENV: - case NODE_TRACE: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_POINTER: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_ENUM: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_VARIANT: - default: - goto errinval; - } - - switch (node->u.unary_expression.link) { - case UNARY_LINK_UNKNOWN: - /* We don't allow empty link except on the first node of the list */ - if (is_ctf_exp && - _bt_list_first_entry(is_ctf_exp_left ? &node->parent->u.ctf_expression.left : - &node->parent->u.ctf_expression.right, - struct ctf_node, siblings) != node) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Empty link is not allowed except on first node of unary expression (need to separate nodes with `.` or `->`)."); - goto errperm; - } - break; /* OK */ - case UNARY_DOTLINK: - case UNARY_ARROWLINK: - /* We only allow -> and . links between children of ctf_expression. */ - if (node->parent->type != NODE_CTF_EXPRESSION) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, "Links `.` and `->` are only allowed as children of CTF expression."); - goto errperm; - } - /* - * Only strings can be separated linked by . or ->. - * This includes "", '' and non-quoted identifiers. - */ - if (node->u.unary_expression.type != UNARY_STRING) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Links `.` and `->` are only allowed to separate strings and identifiers."); - goto errperm; - } - /* We don't allow link on the first node of the list */ - if (is_ctf_exp && - _bt_list_first_entry(is_ctf_exp_left ? &node->parent->u.ctf_expression.left : - &node->parent->u.ctf_expression.right, - struct ctf_node, siblings) == node) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Links `.` and `->` are not allowed before first node of the unary expression list."); - goto errperm; - } - break; - case UNARY_DOTDOTDOT: - /* We only allow ... link between children of enumerator. */ - if (node->parent->type != NODE_ENUMERATOR) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, - "Link `...` is only allowed within enumerator."); - goto errperm; - } - /* We don't allow link on the first node of the list */ - if (_bt_list_first_entry(&node->parent->u.enumerator.values, struct ctf_node, siblings) == - node) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Link `...` is not allowed on the first node of the unary expression list."); - goto errperm; - } - break; - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown expression link type: type=%d", - node->u.unary_expression.link); - return -EINVAL; - } - return 0; - -errinval: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EINVAL; /* Incoherent structure */ - -errperm: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, - "Semantic error: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EPERM; /* Structure not allowed */ -} - -static int ctf_visitor_field_class_specifier_list(int, struct ctf_node *node, - struct meta_log_config *log_cfg) -{ - switch (node->parent->type) { - case NODE_CTF_EXPRESSION: - case NODE_TYPE_DECLARATOR: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_ENUM: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_ROOT: - break; /* OK */ - - case NODE_EVENT: - case NODE_STREAM: - case NODE_ENV: - case NODE_TRACE: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_UNARY_EXPRESSION: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_ENUMERATOR: - case NODE_VARIANT: - case NODE_STRUCT: - default: - goto errinval; - } - return 0; -errinval: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EINVAL; /* Incoherent structure */ -} - -static int ctf_visitor_field_class_specifier(int, struct ctf_node *node, - struct meta_log_config *log_cfg) -{ - switch (node->parent->type) { - case NODE_TYPE_SPECIFIER_LIST: - break; /* OK */ - - case NODE_CTF_EXPRESSION: - case NODE_TYPE_DECLARATOR: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_ENUM: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_ROOT: - case NODE_EVENT: - case NODE_STREAM: - case NODE_ENV: - case NODE_TRACE: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_UNARY_EXPRESSION: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_POINTER: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_ENUMERATOR: - case NODE_VARIANT: - case NODE_STRUCT: - default: - goto errinval; - } - return 0; -errinval: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EINVAL; /* Incoherent structure */ -} - -static int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node, - struct meta_log_config *log_cfg) -{ - int ret = 0; - struct ctf_node *iter; - - depth++; - - switch (node->parent->type) { - case NODE_TYPE_DECLARATOR: - /* - * A nested field class declarator is not allowed to - * contain pointers. - */ - if (!bt_list_empty(&node->u.field_class_declarator.pointers)) - goto errperm; - break; /* OK */ - case NODE_TYPEALIAS_TARGET: - break; /* OK */ - case NODE_TYPEALIAS_ALIAS: - /* - * Only accept alias name containing: - * - identifier - * - identifier * (any number of pointers) - * NOT accepting alias names containing [] (would otherwise - * cause semantic clash for later declarations of - * arrays/sequences of elements, where elements could be - * arrays/sequences themselves (if allowed in field class alias). - * NOT accepting alias with identifier. The declarator should - * be either empty or contain pointer(s). - */ - if (node->u.field_class_declarator.type == TYPEDEC_NESTED) - goto errperm; - bt_list_for_each_entry (iter, - &node->parent->u.field_class_alias_name.field_class_specifier_list - ->u.field_class_specifier_list.head, - siblings) { - switch (iter->u.field_class_specifier.type) { - case TYPESPEC_FLOATING_POINT: - case TYPESPEC_INTEGER: - case TYPESPEC_STRING: - case TYPESPEC_STRUCT: - case TYPESPEC_VARIANT: - case TYPESPEC_ENUM: - if (bt_list_empty(&node->u.field_class_declarator.pointers)) - goto errperm; - break; - default: - break; - } - } - if (node->u.field_class_declarator.type == TYPEDEC_ID && - node->u.field_class_declarator.u.id) - goto errperm; - break; /* OK */ - case NODE_TYPEDEF: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - break; /* OK */ - - case NODE_ROOT: - case NODE_EVENT: - case NODE_STREAM: - case NODE_ENV: - case NODE_TRACE: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_CTF_EXPRESSION: - case NODE_UNARY_EXPRESSION: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_POINTER: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_ENUMERATOR: - case NODE_ENUM: - case NODE_VARIANT: - case NODE_STRUCT: - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.field_class_declarator.pointers, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - - switch (node->u.field_class_declarator.type) { - case TYPEDEC_ID: - break; - case TYPEDEC_NESTED: - { - if (node->u.field_class_declarator.u.nested.field_class_declarator) { - ret = _ctf_visitor_semantic_check( - depth + 1, node->u.field_class_declarator.u.nested.field_class_declarator, log_cfg); - if (ret) - return ret; - } - if (!node->u.field_class_declarator.u.nested.abstract_array) { - bt_list_for_each_entry (iter, &node->u.field_class_declarator.u.nested.length, - siblings) { - if (iter->type != NODE_UNARY_EXPRESSION) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, "Expecting unary expression as length: node-type=%s", - node_type(iter)); - return -EINVAL; - } - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - } else { - if (node->parent->type == NODE_TYPEALIAS_TARGET) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Abstract array declarator not permitted as target of field class alias."); - return -EINVAL; - } - } - if (node->u.field_class_declarator.bitfield_len) { - ret = _ctf_visitor_semantic_check(depth + 1, - node->u.field_class_declarator.bitfield_len, log_cfg); - if (ret) - return ret; - } - break; - } - case TYPEDEC_UNKNOWN: - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown field class declarator: type=%d", - node->u.field_class_declarator.type); - return -EINVAL; - } - depth--; - return 0; - -errinval: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EINVAL; /* Incoherent structure */ - -errperm: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, - "Semantic error: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EPERM; /* Structure not allowed */ -} - -static int _ctf_visitor_semantic_check(int depth, struct ctf_node *node, - struct meta_log_config *log_cfg) -{ - int ret = 0; - struct ctf_node *iter; - - if (node->visited) - return 0; - - switch (node->type) { - case NODE_ROOT: - bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.stream, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.root.event, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_EVENT: - switch (node->parent->type) { - case NODE_ROOT: - break; /* OK */ - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.event.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_STREAM: - switch (node->parent->type) { - case NODE_ROOT: - break; /* OK */ - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.stream.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_ENV: - switch (node->parent->type) { - case NODE_ROOT: - break; /* OK */ - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.env.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_TRACE: - switch (node->parent->type) { - case NODE_ROOT: - break; /* OK */ - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.trace.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_CLOCK: - switch (node->parent->type) { - case NODE_ROOT: - break; /* OK */ - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.clock.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_CALLSITE: - switch (node->parent->type) { - case NODE_ROOT: - break; /* OK */ - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.callsite.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_CTF_EXPRESSION: - switch (node->parent->type) { - case NODE_ROOT: - case NODE_EVENT: - case NODE_STREAM: - case NODE_ENV: - case NODE_TRACE: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - break; /* OK */ - - case NODE_CTF_EXPRESSION: - case NODE_UNARY_EXPRESSION: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_TYPEALIAS: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_TYPE_DECLARATOR: - case NODE_ENUMERATOR: - case NODE_ENUM: - case NODE_VARIANT: - case NODE_STRUCT: - default: - goto errinval; - } - - depth++; - bt_list_for_each_entry (iter, &node->u.ctf_expression.left, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - bt_list_for_each_entry (iter, &node->u.ctf_expression.right, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_UNARY_EXPRESSION: - return ctf_visitor_unary_expression(depth, node, log_cfg); - - case NODE_TYPEDEF: - switch (node->parent->type) { - case NODE_ROOT: - case NODE_EVENT: - case NODE_STREAM: - case NODE_TRACE: - case NODE_VARIANT: - case NODE_STRUCT: - break; /* OK */ - - case NODE_CTF_EXPRESSION: - case NODE_UNARY_EXPRESSION: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_TYPEALIAS: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_TYPE_DECLARATOR: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_ENUMERATOR: - case NODE_ENUM: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_ENV: - default: - goto errinval; - } - - depth++; - ret = _ctf_visitor_semantic_check( - depth + 1, node->u.field_class_def.field_class_specifier_list, log_cfg); - if (ret) - return ret; - bt_list_for_each_entry (iter, &node->u.field_class_def.field_class_declarators, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_TYPEALIAS_TARGET: - { - int nr_declarators; - - switch (node->parent->type) { - case NODE_TYPEALIAS: - break; /* OK */ - default: - goto errinval; - } - - depth++; - ret = _ctf_visitor_semantic_check( - depth + 1, node->u.field_class_alias_target.field_class_specifier_list, log_cfg); - if (ret) - return ret; - nr_declarators = 0; - bt_list_for_each_entry (iter, &node->u.field_class_alias_target.field_class_declarators, - siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - nr_declarators++; - } - if (nr_declarators > 1) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Too many declarators in field class alias's name (maximum is 1): count=%d", - nr_declarators); - return -EINVAL; - } - depth--; - break; - } - case NODE_TYPEALIAS_ALIAS: - { - int nr_declarators; - - switch (node->parent->type) { - case NODE_TYPEALIAS: - break; /* OK */ - default: - goto errinval; - } - - depth++; - ret = _ctf_visitor_semantic_check( - depth + 1, node->u.field_class_alias_name.field_class_specifier_list, log_cfg); - if (ret) - return ret; - nr_declarators = 0; - bt_list_for_each_entry (iter, &node->u.field_class_alias_name.field_class_declarators, - siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - nr_declarators++; - } - if (nr_declarators > 1) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, - "Too many declarators in field class alias's name (maximum is 1): count=%d", - nr_declarators); - return -EINVAL; - } - depth--; - break; - } - case NODE_TYPEALIAS: - switch (node->parent->type) { - case NODE_ROOT: - case NODE_EVENT: - case NODE_STREAM: - case NODE_TRACE: - case NODE_VARIANT: - case NODE_STRUCT: - break; /* OK */ - - case NODE_CTF_EXPRESSION: - case NODE_UNARY_EXPRESSION: - case NODE_TYPEDEF: - case NODE_TYPEALIAS_TARGET: - case NODE_TYPEALIAS_ALIAS: - case NODE_TYPEALIAS: - case NODE_STRUCT_OR_VARIANT_DECLARATION: - case NODE_TYPE_SPECIFIER: - case NODE_TYPE_SPECIFIER_LIST: - case NODE_POINTER: - case NODE_TYPE_DECLARATOR: - case NODE_FLOATING_POINT: - case NODE_INTEGER: - case NODE_STRING: - case NODE_ENUMERATOR: - case NODE_ENUM: - case NODE_CLOCK: - case NODE_CALLSITE: - case NODE_ENV: - default: - goto errinval; - } - - ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.target, log_cfg); - if (ret) - return ret; - ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.alias, log_cfg); - if (ret) - return ret; - break; - - case NODE_TYPE_SPECIFIER_LIST: - ret = ctf_visitor_field_class_specifier_list(depth, node, log_cfg); - if (ret) - return ret; - break; - case NODE_TYPE_SPECIFIER: - ret = ctf_visitor_field_class_specifier(depth, node, log_cfg); - if (ret) - return ret; - break; - case NODE_POINTER: - switch (node->parent->type) { - case NODE_TYPE_DECLARATOR: - break; /* OK */ - default: - goto errinval; - } - break; - case NODE_TYPE_DECLARATOR: - ret = ctf_visitor_field_class_declarator(depth, node, log_cfg); - if (ret) - return ret; - break; - - case NODE_FLOATING_POINT: - switch (node->parent->type) { - case NODE_TYPE_SPECIFIER: - break; /* OK */ - default: - goto errinval; - - case NODE_UNARY_EXPRESSION: - goto errperm; - } - bt_list_for_each_entry (iter, &node->u.floating_point.expressions, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_INTEGER: - switch (node->parent->type) { - case NODE_TYPE_SPECIFIER: - break; /* OK */ - default: - goto errinval; - } - - bt_list_for_each_entry (iter, &node->u.integer.expressions, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_STRING: - switch (node->parent->type) { - case NODE_TYPE_SPECIFIER: - break; /* OK */ - default: - goto errinval; - - case NODE_UNARY_EXPRESSION: - goto errperm; - } - - bt_list_for_each_entry (iter, &node->u.string.expressions, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_ENUMERATOR: - switch (node->parent->type) { - case NODE_ENUM: - break; - default: - goto errinval; - } - /* - * Enumerators are only allows to contain: - * numeric unary expression - * or num. unary exp. ... num. unary exp - */ - { - int count = 0; - - bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { - switch (count++) { - case 0: - if (iter->type != NODE_UNARY_EXPRESSION || - (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT && - iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) || - iter->u.unary_expression.link != UNARY_LINK_UNKNOWN) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - iter->lineno, "First unary expression of enumerator is unexpected."); - goto errperm; - } - break; - case 1: - if (iter->type != NODE_UNARY_EXPRESSION || - (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT && - iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) || - iter->u.unary_expression.link != UNARY_DOTDOTDOT) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - iter->lineno, "Second unary expression of enumerator is unexpected."); - goto errperm; - } - break; - default: - goto errperm; - } - } - } - - bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_ENUM: - switch (node->parent->type) { - case NODE_TYPE_SPECIFIER: - break; /* OK */ - default: - goto errinval; - - case NODE_UNARY_EXPRESSION: - goto errperm; - } - - depth++; - ret = _ctf_visitor_semantic_check(depth + 1, node->u._enum.container_field_class, log_cfg); - if (ret) - return ret; - - bt_list_for_each_entry (iter, &node->u._enum.enumerator_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - depth--; - break; - case NODE_STRUCT_OR_VARIANT_DECLARATION: - switch (node->parent->type) { - case NODE_STRUCT: - case NODE_VARIANT: - break; - default: - goto errinval; - } - ret = _ctf_visitor_semantic_check( - depth + 1, node->u.struct_or_variant_declaration.field_class_specifier_list, log_cfg); - if (ret) - return ret; - bt_list_for_each_entry ( - iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - case NODE_VARIANT: - switch (node->parent->type) { - case NODE_TYPE_SPECIFIER: - break; /* OK */ - default: - goto errinval; - - case NODE_UNARY_EXPRESSION: - goto errperm; - } - bt_list_for_each_entry (iter, &node->u.variant.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_STRUCT: - switch (node->parent->type) { - case NODE_TYPE_SPECIFIER: - break; /* OK */ - default: - goto errinval; - - case NODE_UNARY_EXPRESSION: - goto errperm; - } - bt_list_for_each_entry (iter, &node->u._struct.declaration_list, siblings) { - ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); - if (ret) - return ret; - } - break; - - case NODE_UNKNOWN: - default: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown node type: type=%d", node->type); - return -EINVAL; - } - return ret; - -errinval: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO( - node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EINVAL; /* Incoherent structure */ - -errperm: - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, - "Semantic error: node-type=%s, parent-node-type=%s", - node_type(node), node_type(node->parent)); - return -EPERM; /* Structure not allowed */ -} - -int ctf_visitor_semantic_check(int depth, struct ctf_node *node, struct meta_log_config *log_cfg) -{ - int ret = 0; - - /* - * First make sure we create the parent links for all children. Let's - * take the safe route and recreate them at each validation, just in - * case the structure has changed. - */ - ret = ctf_visitor_parent_links(depth, node, log_cfg); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, - "Cannot create parent links in metadata's AST: " - "ret=%d", - ret); - goto end; - } - - ret = _ctf_visitor_semantic_check(depth, node, log_cfg); - if (ret) { - _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, - "Cannot check metadata's AST semantics: " - "ret=%d", - ret); - goto end; - } - -end: - return ret; -} diff --git a/src/plugins/ctf/common/msg-iter/msg-iter.cpp b/src/plugins/ctf/common/msg-iter/msg-iter.cpp deleted file mode 100644 index 33ad4a27..00000000 --- a/src/plugins/ctf/common/msg-iter/msg-iter.cpp +++ /dev/null @@ -1,3008 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015-2018 Philippe Proulx - * - * Babeltrace - CTF message iterator - */ - -#include -#include -#include -#include -#include - -#include - -#define BT_COMP_LOG_SELF_COMP (msg_it->self_comp) -#define BT_LOG_OUTPUT_LEVEL (msg_it->log_level) -#define BT_LOG_TAG "PLUGIN/CTF/MSG-ITER" -#include "logging/comp-logging.h" - -#include "common/assert.h" -#include "common/common.h" - -#include "../bfcr/bfcr.hpp" -#include "msg-iter.hpp" -#include "plugins/ctf/common/metadata/ctf-meta.hpp" - -/* A visit stack entry */ -struct stack_entry -{ - /* - * Current base field, one of: - * - * * string - * * structure - * * array - * * sequence - * * variant - * - * Field is borrowed. - */ - bt_field *base; - - /* Index of next field to set */ - size_t index; -}; - -/* Visit stack */ -struct stack -{ - struct ctf_msg_iter *msg_it; - - /* Entries (struct stack_entry) */ - GArray *entries; - - /* Number of active entries */ - size_t size; -}; - -/* State */ -enum state -{ - STATE_INIT, - STATE_SWITCH_PACKET, - STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN, - STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, - STATE_AFTER_TRACE_PACKET_HEADER, - STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN, - STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE, - STATE_AFTER_STREAM_PACKET_CONTEXT, - STATE_EMIT_MSG_STREAM_BEGINNING, - STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS, - STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS, - STATE_EMIT_MSG_DISCARDED_EVENTS, - STATE_EMIT_MSG_DISCARDED_PACKETS, - STATE_EMIT_MSG_PACKET_BEGINNING, - STATE_DSCOPE_EVENT_HEADER_BEGIN, - STATE_DSCOPE_EVENT_HEADER_CONTINUE, - STATE_AFTER_EVENT_HEADER, - STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN, - STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, - STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN, - STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, - STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, - STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, - STATE_EMIT_MSG_EVENT, - STATE_EMIT_QUEUED_MSG_EVENT, - STATE_SKIP_PACKET_PADDING, - STATE_EMIT_MSG_PACKET_END_MULTI, - STATE_EMIT_MSG_PACKET_END_SINGLE, - STATE_EMIT_QUEUED_MSG_PACKET_END, - STATE_CHECK_EMIT_MSG_STREAM_END, - STATE_EMIT_MSG_STREAM_END, - STATE_DONE, -}; - -struct end_of_packet_snapshots -{ - uint64_t discarded_events; - uint64_t packets; - uint64_t beginning_clock; - uint64_t end_clock; -}; - -/* CTF message iterator */ -struct ctf_msg_iter -{ - /* Visit stack */ - struct stack *stack; - - /* Current message iterator to create messages (weak) */ - bt_self_message_iterator *self_msg_iter; - - /* - * True if library objects are unavailable during the decoding and - * should not be created/used. - */ - bool dry_run; - - /* - * Current dynamic scope field pointer. - * - * This is set by read_dscope_begin_state() and contains the - * value of one of the pointers in `dscopes` below. - */ - bt_field *cur_dscope_field; - - /* - * True if we're done filling a string field from a text - * array/sequence payload. - */ - bool done_filling_string; - - /* Trace and classes */ - /* True to set IR fields */ - bool set_ir_fields; - - struct - { - struct ctf_trace_class *tc; - struct ctf_stream_class *sc; - struct ctf_event_class *ec; - } meta; - - /* Current packet (NULL if not created yet) */ - bt_packet *packet; - - /* Current stream (NULL if not set yet) */ - bt_stream *stream; - - /* Current event (NULL if not created yet) */ - bt_event *event; - - /* Current event message (NULL if not created yet) */ - bt_message *event_msg; - - /* - * True if we need to emit a packet beginning message before we emit - * the next event message or the packet end message. - */ - bool emit_delayed_packet_beginning_msg; - - /* - * True if this is the first packet we are reading, and therefore if we - * should emit a stream beginning message. - */ - bool emit_stream_beginning_message; - - /* - * True if we need to emit a stream end message at the end of the - * current stream. A live stream may never receive any data and thus - * never send a stream beginning message which removes the need to emit - * a stream end message. - */ - bool emit_stream_end_message; - - /* Database of current dynamic scopes */ - struct - { - bt_field *stream_packet_context; - bt_field *event_common_context; - bt_field *event_spec_context; - bt_field *event_payload; - } dscopes; - - /* Current state */ - enum state state; - - /* Current medium buffer data */ - struct - { - /* Last address provided by medium */ - const uint8_t *addr; - - /* Buffer size provided by medium (bytes) */ - size_t sz; - - /* Offset within whole packet of addr (bits) */ - size_t packet_offset; - - /* Current position from addr (bits) */ - size_t at; - - /* Position of the last event header from addr (bits) */ - size_t last_eh_at; - } buf; - - /* Binary type reader */ - struct bt_bfcr *bfcr; - - /* Current medium data */ - struct - { - struct ctf_msg_iter_medium_ops medops; - size_t max_request_sz; - void *data; - } medium; - - /* Current packet size (bits) (-1 if unknown) */ - int64_t cur_exp_packet_total_size; - - /* Current content size (bits) (-1 if unknown) */ - int64_t cur_exp_packet_content_size; - - /* Current stream class ID */ - int64_t cur_stream_class_id; - - /* Current event class ID */ - int64_t cur_event_class_id; - - /* Current data stream ID */ - int64_t cur_data_stream_id; - - /* - * Offset, in the underlying media, of the current packet's - * start (-1 if unknown). - */ - off_t cur_packet_offset; - - /* Default clock's current value */ - uint64_t default_clock_snapshot; - - /* End of current packet snapshots */ - struct end_of_packet_snapshots snapshots; - - /* End of previous packet snapshots */ - struct end_of_packet_snapshots prev_packet_snapshots; - - /* Stored values (for sequence lengths, variant tags) */ - GArray *stored_values; - - /* Iterator's current log level */ - bt_logging_level log_level; - - /* Iterator's owning self component, or `NULL` if none (query) */ - bt_self_component *self_comp; -}; - -static inline const char *state_string(enum state state) -{ - switch (state) { - case STATE_INIT: - return "INIT"; - case STATE_SWITCH_PACKET: - return "SWITCH_PACKET"; - case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN: - return "DSCOPE_TRACE_PACKET_HEADER_BEGIN"; - case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE: - return "DSCOPE_TRACE_PACKET_HEADER_CONTINUE"; - case STATE_AFTER_TRACE_PACKET_HEADER: - return "AFTER_TRACE_PACKET_HEADER"; - case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN: - return "DSCOPE_STREAM_PACKET_CONTEXT_BEGIN"; - case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE: - return "DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE"; - case STATE_AFTER_STREAM_PACKET_CONTEXT: - return "AFTER_STREAM_PACKET_CONTEXT"; - case STATE_EMIT_MSG_STREAM_BEGINNING: - return "EMIT_MSG_STREAM_BEGINNING"; - case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS: - return "CHECK_EMIT_MSG_DISCARDED_EVENTS"; - case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS: - return "CHECK_EMIT_MSG_DISCARDED_PACKETS"; - case STATE_EMIT_MSG_PACKET_BEGINNING: - return "EMIT_MSG_PACKET_BEGINNING"; - case STATE_EMIT_MSG_DISCARDED_EVENTS: - return "EMIT_MSG_DISCARDED_EVENTS"; - case STATE_EMIT_MSG_DISCARDED_PACKETS: - return "EMIT_MSG_DISCARDED_PACKETS"; - case STATE_DSCOPE_EVENT_HEADER_BEGIN: - return "DSCOPE_EVENT_HEADER_BEGIN"; - case STATE_DSCOPE_EVENT_HEADER_CONTINUE: - return "DSCOPE_EVENT_HEADER_CONTINUE"; - case STATE_AFTER_EVENT_HEADER: - return "AFTER_EVENT_HEADER"; - case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: - return "DSCOPE_EVENT_COMMON_CONTEXT_BEGIN"; - case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: - return "DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE"; - case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: - return "DSCOPE_EVENT_SPEC_CONTEXT_BEGIN"; - case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: - return "DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE"; - case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: - return "DSCOPE_EVENT_PAYLOAD_BEGIN"; - case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: - return "DSCOPE_EVENT_PAYLOAD_CONTINUE"; - case STATE_EMIT_MSG_EVENT: - return "EMIT_MSG_EVENT"; - case STATE_EMIT_QUEUED_MSG_EVENT: - return "EMIT_QUEUED_MSG_EVENT"; - case STATE_SKIP_PACKET_PADDING: - return "SKIP_PACKET_PADDING"; - case STATE_EMIT_MSG_PACKET_END_MULTI: - return "EMIT_MSG_PACKET_END_MULTI"; - case STATE_EMIT_MSG_PACKET_END_SINGLE: - return "EMIT_MSG_PACKET_END_SINGLE"; - case STATE_EMIT_QUEUED_MSG_PACKET_END: - return "EMIT_QUEUED_MSG_PACKET_END"; - case STATE_CHECK_EMIT_MSG_STREAM_END: - return "CHECK_EMIT_MSG_STREAM_END"; - case STATE_EMIT_MSG_STREAM_END: - return "EMIT_MSG_STREAM_END"; - case STATE_DONE: - return "DONE"; - } - - bt_common_abort(); -} - -static struct stack *stack_new(struct ctf_msg_iter *msg_it) -{ - bt_self_component *self_comp = msg_it->self_comp; - struct stack *stack = NULL; - - stack = g_new0(struct stack, 1); - if (!stack) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate one stack."); - goto error; - } - - stack->msg_it = msg_it; - stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry)); - if (!stack->entries) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate a GArray."); - goto error; - } - - BT_COMP_LOGD("Created stack: msg-it-addr=%p, stack-addr=%p", msg_it, stack); - goto end; - -error: - g_free(stack); - stack = NULL; - -end: - return stack; -} - -static void stack_destroy(struct stack *stack) -{ - struct ctf_msg_iter *msg_it; - - BT_ASSERT_DBG(stack); - msg_it = stack->msg_it; - BT_COMP_LOGD("Destroying stack: addr=%p", stack); - - if (stack->entries) { - g_array_free(stack->entries, TRUE); - } - - g_free(stack); -} - -static void stack_push(struct stack *stack, bt_field *base) -{ - struct stack_entry *entry; - struct ctf_msg_iter *msg_it; - - BT_ASSERT_DBG(stack); - msg_it = stack->msg_it; - BT_ASSERT_DBG(base); - BT_COMP_LOGT("Pushing base field on stack: stack-addr=%p, " - "stack-size-before=%zu, stack-size-after=%zu", - stack, stack->size, stack->size + 1); - - if (stack->entries->len == stack->size) { - g_array_set_size(stack->entries, stack->size + 1); - } - - entry = &bt_g_array_index(stack->entries, struct stack_entry, stack->size); - entry->base = base; - entry->index = 0; - stack->size++; -} - -static inline unsigned int stack_size(struct stack *stack) -{ - BT_ASSERT_DBG(stack); - return stack->size; -} - -static void stack_pop(struct stack *stack) -{ - struct ctf_msg_iter *msg_it; - - BT_ASSERT_DBG(stack); - BT_ASSERT_DBG(stack_size(stack)); - msg_it = stack->msg_it; - BT_COMP_LOGT("Popping from stack: " - "stack-addr=%p, stack-size-before=%zu, stack-size-after=%zu", - stack, stack->size, stack->size - 1); - stack->size--; -} - -static inline struct stack_entry *stack_top(struct stack *stack) -{ - BT_ASSERT_DBG(stack); - BT_ASSERT_DBG(stack_size(stack)); - return &bt_g_array_index(stack->entries, struct stack_entry, stack->size - 1); -} - -static inline bool stack_empty(struct stack *stack) -{ - return stack_size(stack) == 0; -} - -static void stack_clear(struct stack *stack) -{ - BT_ASSERT_DBG(stack); - stack->size = 0; -} - -static inline enum ctf_msg_iter_status -msg_iter_status_from_m_status(enum ctf_msg_iter_medium_status m_status) -{ - /* They are the same */ - return (ctf_msg_iter_status) m_status; -} - -static inline size_t buf_size_bits(struct ctf_msg_iter *msg_it) -{ - return msg_it->buf.sz * 8; -} - -static inline size_t buf_available_bits(struct ctf_msg_iter *msg_it) -{ - return buf_size_bits(msg_it) - msg_it->buf.at; -} - -static inline size_t packet_at(struct ctf_msg_iter *msg_it) -{ - return msg_it->buf.packet_offset + msg_it->buf.at; -} - -static inline void buf_consume_bits(struct ctf_msg_iter *msg_it, size_t incr) -{ - BT_COMP_LOGT("Advancing cursor: msg-it-addr=%p, cur-before=%zu, cur-after=%zu", msg_it, - msg_it->buf.at, msg_it->buf.at + incr); - msg_it->buf.at += incr; -} - -static enum ctf_msg_iter_status request_medium_bytes(struct ctf_msg_iter *msg_it) -{ - bt_self_component *self_comp = msg_it->self_comp; - uint8_t *buffer_addr = NULL; - size_t buffer_sz = 0; - enum ctf_msg_iter_medium_status m_status; - - BT_COMP_LOGD("Calling user function (request bytes): msg-it-addr=%p, " - "request-size=%zu", - msg_it, msg_it->medium.max_request_sz); - m_status = msg_it->medium.medops.request_bytes(msg_it->medium.max_request_sz, &buffer_addr, - &buffer_sz, msg_it->medium.data); - BT_COMP_LOGD("User function returned: status=%s, buf-addr=%p, buf-size=%zu", - ctf_msg_iter_medium_status_string(m_status), buffer_addr, buffer_sz); - if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_OK) { - BT_ASSERT(buffer_sz != 0); - - /* New packet offset is old one + old size (in bits) */ - msg_it->buf.packet_offset += buf_size_bits(msg_it); - - /* Restart at the beginning of the new medium buffer */ - msg_it->buf.at = 0; - msg_it->buf.last_eh_at = SIZE_MAX; - - /* New medium buffer size */ - msg_it->buf.sz = buffer_sz; - - /* New medium buffer address */ - msg_it->buf.addr = buffer_addr; - - BT_COMP_LOGD("User function returned new bytes: " - "packet-offset=%zu, cur=%zu, size=%zu, addr=%p", - msg_it->buf.packet_offset, msg_it->buf.at, msg_it->buf.sz, msg_it->buf.addr); - BT_COMP_LOGT_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:", buffer_addr); - } else if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) { - /* - * User returned end of stream: validate that we're not - * in the middle of a packet header, packet context, or - * event. - */ - if (msg_it->cur_exp_packet_total_size >= 0) { - if (packet_at(msg_it) == msg_it->cur_exp_packet_total_size) { - goto end; - } - } else { - if (packet_at(msg_it) == 0) { - goto end; - } - - if (msg_it->buf.last_eh_at != SIZE_MAX && msg_it->buf.at == msg_it->buf.last_eh_at) { - goto end; - } - } - - /* All other states are invalid */ - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "User function returned %s, but message iterator is in an unexpected state: " - "state=%s, cur-packet-size=%" PRId64 ", cur=%zu, " - "packet-cur=%zu, last-eh-at=%zu", - ctf_msg_iter_medium_status_string(m_status), state_string(msg_it->state), - msg_it->cur_exp_packet_total_size, msg_it->buf.at, packet_at(msg_it), - msg_it->buf.last_eh_at); - m_status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; - } else if (m_status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "User function failed: " - "status=%s", - ctf_msg_iter_medium_status_string(m_status)); - } - -end: - return msg_iter_status_from_m_status(m_status); -} - -static inline enum ctf_msg_iter_status buf_ensure_available_bits(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - - if (G_UNLIKELY(buf_available_bits(msg_it) == 0)) { - /* - * This _cannot_ return CTF_MSG_ITER_STATUS_OK - * _and_ no bits. - */ - status = request_medium_bytes(msg_it); - } - - return status; -} - -static enum ctf_msg_iter_status -read_dscope_begin_state(struct ctf_msg_iter *msg_it, struct ctf_field_class *dscope_fc, - enum state done_state, enum state continue_state, bt_field *dscope_field) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - enum bt_bfcr_status bfcr_status; - size_t consumed_bits; - - msg_it->cur_dscope_field = dscope_field; - BT_COMP_LOGT("Starting BFCR: msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p", msg_it, msg_it->bfcr, - dscope_fc); - consumed_bits = bt_bfcr_start(msg_it->bfcr, dscope_fc, msg_it->buf.addr, msg_it->buf.at, - packet_at(msg_it), msg_it->buf.sz, &bfcr_status); - BT_COMP_LOGT("BFCR consumed bits: size=%zu", consumed_bits); - - switch (bfcr_status) { - case BT_BFCR_STATUS_OK: - /* Field class was read completely */ - BT_COMP_LOGT_STR("Field was completely decoded."); - msg_it->state = done_state; - break; - case BT_BFCR_STATUS_EOF: - BT_COMP_LOGT_STR("BFCR needs more data to decode field completely."); - msg_it->state = continue_state; - break; - default: - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "BFCR failed to start: msg-it-addr=%p, bfcr-addr=%p, " - "status=%s", - msg_it, msg_it->bfcr, bt_bfcr_status_string(bfcr_status)); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - /* Consume bits now since we know we're not in an error state */ - buf_consume_bits(msg_it, consumed_bits); - -end: - return status; -} - -static enum ctf_msg_iter_status read_dscope_continue_state(struct ctf_msg_iter *msg_it, - enum state done_state) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - enum bt_bfcr_status bfcr_status; - size_t consumed_bits; - - BT_COMP_LOGT("Continuing BFCR: msg-it-addr=%p, bfcr-addr=%p", msg_it, msg_it->bfcr); - - status = buf_ensure_available_bits(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - if (status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot ensure that buffer has at least one byte: " - "msg-addr=%p, status=%s", - msg_it, ctf_msg_iter_status_string(status)); - } else { - BT_COMP_LOGT("Cannot ensure that buffer has at least one byte: " - "msg-addr=%p, status=%s", - msg_it, ctf_msg_iter_status_string(status)); - } - - goto end; - } - - consumed_bits = bt_bfcr_continue(msg_it->bfcr, msg_it->buf.addr, msg_it->buf.sz, &bfcr_status); - BT_COMP_LOGT("BFCR consumed bits: size=%zu", consumed_bits); - - switch (bfcr_status) { - case BT_BFCR_STATUS_OK: - /* Type was read completely. */ - BT_COMP_LOGT_STR("Field was completely decoded."); - msg_it->state = done_state; - break; - case BT_BFCR_STATUS_EOF: - /* Stay in this continue state. */ - BT_COMP_LOGT_STR("BFCR needs more data to decode field completely."); - break; - default: - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "BFCR failed to continue: msg-it-addr=%p, bfcr-addr=%p, " - "status=%s", - msg_it, msg_it->bfcr, bt_bfcr_status_string(bfcr_status)); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - /* Consume bits now since we know we're not in an error state. */ - buf_consume_bits(msg_it, consumed_bits); -end: - return status; -} - -static void release_event_dscopes(struct ctf_msg_iter *msg_it) -{ - msg_it->dscopes.event_common_context = NULL; - msg_it->dscopes.event_spec_context = NULL; - msg_it->dscopes.event_payload = NULL; -} - -static void release_all_dscopes(struct ctf_msg_iter *msg_it) -{ - msg_it->dscopes.stream_packet_context = NULL; - - release_event_dscopes(msg_it); -} - -static enum ctf_msg_iter_status switch_packet_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status; - bt_self_component *self_comp = msg_it->self_comp; - - /* - * We don't put the stream class here because we need to make - * sure that all the packets processed by the same message - * iterator refer to the same stream class (the first one). - */ - BT_ASSERT(msg_it); - - if (msg_it->cur_exp_packet_total_size != -1) { - msg_it->cur_packet_offset += msg_it->cur_exp_packet_total_size; - } - - BT_COMP_LOGD("Switching packet: msg-it-addr=%p, cur=%zu, " - "packet-offset=%" PRId64, - msg_it, msg_it->buf.at, msg_it->cur_packet_offset); - stack_clear(msg_it->stack); - msg_it->meta.ec = NULL; - BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); - BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg); - release_all_dscopes(msg_it); - msg_it->cur_dscope_field = NULL; - - if (msg_it->medium.medops.switch_packet) { - enum ctf_msg_iter_medium_status medium_status; - - medium_status = msg_it->medium.medops.switch_packet(msg_it->medium.data); - if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) { - /* No more packets. */ - msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END; - status = CTF_MSG_ITER_STATUS_OK; - goto end; - } else if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) { - status = msg_iter_status_from_m_status(medium_status); - goto end; - } - - /* - * After the packet switch, the medium might want to give us a - * different buffer for the new packet. - */ - status = request_medium_bytes(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - } - - /* - * Adjust current buffer so that addr points to the beginning of the new - * packet. - */ - if (msg_it->buf.addr) { - size_t consumed_bytes = (size_t) (msg_it->buf.at / CHAR_BIT); - - /* Packets are assumed to start on a byte frontier. */ - if (msg_it->buf.at % CHAR_BIT) { - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "Cannot switch packet: current position is not a multiple of 8: " - "msg-it-addr=%p, cur=%zu", - msg_it, msg_it->buf.at); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - msg_it->buf.addr += consumed_bytes; - msg_it->buf.sz -= consumed_bytes; - msg_it->buf.at = 0; - msg_it->buf.packet_offset = 0; - BT_COMP_LOGD("Adjusted buffer: addr=%p, size=%zu", msg_it->buf.addr, msg_it->buf.sz); - } - - msg_it->cur_exp_packet_content_size = -1; - msg_it->cur_exp_packet_total_size = -1; - msg_it->cur_stream_class_id = -1; - msg_it->cur_event_class_id = -1; - msg_it->cur_data_stream_id = -1; - msg_it->prev_packet_snapshots = msg_it->snapshots; - msg_it->snapshots.discarded_events = UINT64_C(-1); - msg_it->snapshots.packets = UINT64_C(-1); - msg_it->snapshots.beginning_clock = UINT64_C(-1); - msg_it->snapshots.end_clock = UINT64_C(-1); - msg_it->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN; - - status = CTF_MSG_ITER_STATUS_OK; -end: - return status; -} - -static enum ctf_msg_iter_status read_packet_header_begin_state(struct ctf_msg_iter *msg_it) -{ - struct ctf_field_class *packet_header_fc = NULL; - bt_self_component *self_comp = msg_it->self_comp; - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - - /* - * Make sure at least one bit is available for this packet. An - * empty packet is impossible. If we reach the end of the medium - * at this point, then it's considered the end of the stream. - */ - status = buf_ensure_available_bits(msg_it); - switch (status) { - case CTF_MSG_ITER_STATUS_OK: - break; - case CTF_MSG_ITER_STATUS_EOF: - status = CTF_MSG_ITER_STATUS_OK; - msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END; - goto end; - default: - goto end; - } - - /* Packet header class is common to the whole trace class. */ - packet_header_fc = msg_it->meta.tc->packet_header_fc; - if (!packet_header_fc) { - msg_it->state = STATE_AFTER_TRACE_PACKET_HEADER; - goto end; - } - - msg_it->cur_stream_class_id = -1; - msg_it->cur_event_class_id = -1; - msg_it->cur_data_stream_id = -1; - BT_COMP_LOGD("Decoding packet header field: " - "msg-it-addr=%p, trace-class-addr=%p, fc-addr=%p", - msg_it, msg_it->meta.tc, packet_header_fc); - status = read_dscope_begin_state(msg_it, packet_header_fc, STATE_AFTER_TRACE_PACKET_HEADER, - STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, NULL); - if (status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot decode packet header field: " - "msg-it-addr=%p, trace-class-addr=%p, " - "fc-addr=%p", - msg_it, msg_it->meta.tc, packet_header_fc); - } - -end: - return status; -} - -static enum ctf_msg_iter_status read_packet_header_continue_state(struct ctf_msg_iter *msg_it) -{ - return read_dscope_continue_state(msg_it, STATE_AFTER_TRACE_PACKET_HEADER); -} - -static inline enum ctf_msg_iter_status set_current_stream_class(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_stream_class *new_stream_class = NULL; - - if (msg_it->cur_stream_class_id == -1) { - /* - * No current stream class ID field, therefore only one - * stream class. - */ - if (msg_it->meta.tc->stream_classes->len != 1) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Need exactly one stream class since there's " - "no stream class ID field: " - "msg-it-addr=%p", - msg_it); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - new_stream_class = (ctf_stream_class *) msg_it->meta.tc->stream_classes->pdata[0]; - msg_it->cur_stream_class_id = new_stream_class->id; - } - - new_stream_class = - ctf_trace_class_borrow_stream_class_by_id(msg_it->meta.tc, msg_it->cur_stream_class_id); - if (!new_stream_class) { - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "No stream class with ID of stream class ID to use in trace class: " - "msg-it-addr=%p, stream-class-id=%" PRIu64 ", " - "trace-class-addr=%p", - msg_it, msg_it->cur_stream_class_id, msg_it->meta.tc); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - if (msg_it->meta.sc) { - if (new_stream_class != msg_it->meta.sc) { - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "Two packets refer to two different stream classes within the same packet sequence: " - "msg-it-addr=%p, prev-stream-class-addr=%p, " - "prev-stream-class-id=%" PRId64 ", " - "next-stream-class-addr=%p, " - "next-stream-class-id=%" PRId64 ", " - "trace-addr=%p", - msg_it, msg_it->meta.sc, msg_it->meta.sc->id, new_stream_class, - new_stream_class->id, msg_it->meta.tc); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - } else { - msg_it->meta.sc = new_stream_class; - } - - BT_COMP_LOGD("Set current stream class: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64, - msg_it, msg_it->meta.sc, msg_it->meta.sc->id); - -end: - return status; -} - -static inline enum ctf_msg_iter_status set_current_stream(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - bt_stream *stream = NULL; - - BT_COMP_LOGD("Calling user function (get stream): msg-it-addr=%p, " - "stream-class-addr=%p, stream-class-id=%" PRId64, - msg_it, msg_it->meta.sc, msg_it->meta.sc->id); - stream = msg_it->medium.medops.borrow_stream(msg_it->meta.sc->ir_sc, msg_it->cur_data_stream_id, - msg_it->medium.data); - bt_stream_get_ref(stream); - BT_COMP_LOGD("User function returned: stream-addr=%p", stream); - if (!stream) { - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "User function failed to return a stream object for the given stream class."); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - if (msg_it->stream && stream != msg_it->stream) { - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "User function returned a different stream than the previous one for the same sequence of packets."); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - BT_STREAM_MOVE_REF(msg_it->stream, stream); - -end: - bt_stream_put_ref(stream); - return status; -} - -static inline enum ctf_msg_iter_status set_current_packet(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - bt_packet *packet = NULL; - - BT_COMP_LOGD("Creating packet from stream: " - "msg-it-addr=%p, stream-addr=%p, " - "stream-class-addr=%p, " - "stream-class-id=%" PRId64, - msg_it, msg_it->stream, msg_it->meta.sc, msg_it->meta.sc->id); - - /* Create packet */ - BT_ASSERT(msg_it->stream); - packet = bt_packet_create(msg_it->stream); - if (!packet) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create packet from stream: " - "msg-it-addr=%p, stream-addr=%p, " - "stream-class-addr=%p, " - "stream-class-id=%" PRId64, - msg_it, msg_it->stream, msg_it->meta.sc, msg_it->meta.sc->id); - goto error; - } - - goto end; - -error: - BT_PACKET_PUT_REF_AND_RESET(packet); - status = CTF_MSG_ITER_STATUS_ERROR; - -end: - BT_PACKET_MOVE_REF(msg_it->packet, packet); - return status; -} - -static enum ctf_msg_iter_status after_packet_header_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status; - - status = set_current_stream_class(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - if (!msg_it->dry_run) { - status = set_current_stream(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - status = set_current_packet(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - } - - msg_it->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN; - - status = CTF_MSG_ITER_STATUS_OK; - -end: - return status; -} - -static enum ctf_msg_iter_status read_packet_context_begin_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_field_class *packet_context_fc; - - BT_ASSERT(msg_it->meta.sc); - packet_context_fc = msg_it->meta.sc->packet_context_fc; - if (!packet_context_fc) { - BT_COMP_LOGD("No packet packet context field class in stream class: continuing: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64, - msg_it, msg_it->meta.sc, msg_it->meta.sc->id); - msg_it->state = STATE_AFTER_STREAM_PACKET_CONTEXT; - goto end; - } - - if (packet_context_fc->in_ir && !msg_it->dry_run) { - BT_ASSERT(!msg_it->dscopes.stream_packet_context); - BT_ASSERT(msg_it->packet); - msg_it->dscopes.stream_packet_context = bt_packet_borrow_context_field(msg_it->packet); - BT_ASSERT(msg_it->dscopes.stream_packet_context); - } - - BT_COMP_LOGD("Decoding packet context field: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", fc-addr=%p", - msg_it, msg_it->meta.sc, msg_it->meta.sc->id, packet_context_fc); - status = read_dscope_begin_state(msg_it, packet_context_fc, STATE_AFTER_STREAM_PACKET_CONTEXT, - STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE, - msg_it->dscopes.stream_packet_context); - if (status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot decode packet context field: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", fc-addr=%p", - msg_it, msg_it->meta.sc, msg_it->meta.sc->id, packet_context_fc); - } - -end: - return status; -} - -static enum ctf_msg_iter_status read_packet_context_continue_state(struct ctf_msg_iter *msg_it) -{ - return read_dscope_continue_state(msg_it, STATE_AFTER_STREAM_PACKET_CONTEXT); -} - -static enum ctf_msg_iter_status set_current_packet_content_sizes(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - - if (msg_it->cur_exp_packet_total_size == -1) { - if (msg_it->cur_exp_packet_content_size != -1) { - msg_it->cur_exp_packet_total_size = msg_it->cur_exp_packet_content_size; - } - } else { - if (msg_it->cur_exp_packet_content_size == -1) { - msg_it->cur_exp_packet_content_size = msg_it->cur_exp_packet_total_size; - } - } - - BT_ASSERT( - (msg_it->cur_exp_packet_total_size >= 0 && msg_it->cur_exp_packet_content_size >= 0) || - (msg_it->cur_exp_packet_total_size < 0 && msg_it->cur_exp_packet_content_size < 0)); - - if (msg_it->cur_exp_packet_content_size > msg_it->cur_exp_packet_total_size) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Invalid packet or content size: " - "content size is greater than packet size: " - "msg-it-addr=%p, packet-context-field-addr=%p, " - "packet-size=%" PRId64 ", content-size=%" PRId64, - msg_it, msg_it->dscopes.stream_packet_context, - msg_it->cur_exp_packet_total_size, - msg_it->cur_exp_packet_content_size); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - BT_COMP_LOGD("Set current packet and content sizes: " - "msg-it-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64, - msg_it, msg_it->cur_exp_packet_total_size, msg_it->cur_exp_packet_content_size); - -end: - return status; -} - -static enum ctf_msg_iter_status after_packet_context_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status; - - status = set_current_packet_content_sizes(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - if (msg_it->emit_stream_beginning_message) { - msg_it->state = STATE_EMIT_MSG_STREAM_BEGINNING; - } else { - msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS; - } - -end: - return status; -} - -static enum ctf_msg_iter_status read_event_header_begin_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_field_class *event_header_fc = NULL; - - /* Reset the position of the last event header */ - msg_it->buf.last_eh_at = msg_it->buf.at; - msg_it->cur_event_class_id = -1; - - /* Check if we have some content left */ - if (msg_it->cur_exp_packet_content_size >= 0) { - if (G_UNLIKELY(packet_at(msg_it) == msg_it->cur_exp_packet_content_size)) { - /* No more events! */ - BT_COMP_LOGD("Reached end of packet: msg-it-addr=%p, " - "cur=%zu", - msg_it, packet_at(msg_it)); - msg_it->state = STATE_EMIT_MSG_PACKET_END_MULTI; - goto end; - } else if (G_UNLIKELY(packet_at(msg_it) > msg_it->cur_exp_packet_content_size)) { - /* That's not supposed to happen */ - BT_COMP_LOGD( - "Before decoding event header field: cursor is passed the packet's content: " - "msg-it-addr=%p, content-size=%" PRId64 ", " - "cur=%zu", - msg_it, msg_it->cur_exp_packet_content_size, packet_at(msg_it)); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - } else { - /* - * "Infinite" content: we're done when the medium has - * nothing else for us. - */ - status = buf_ensure_available_bits(msg_it); - switch (status) { - case CTF_MSG_ITER_STATUS_OK: - break; - case CTF_MSG_ITER_STATUS_EOF: - status = CTF_MSG_ITER_STATUS_OK; - msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE; - goto end; - default: - goto end; - } - } - - release_event_dscopes(msg_it); - BT_ASSERT(msg_it->meta.sc); - event_header_fc = msg_it->meta.sc->event_header_fc; - if (!event_header_fc) { - msg_it->state = STATE_AFTER_EVENT_HEADER; - goto end; - } - - BT_COMP_LOGD("Decoding event header field: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", " - "fc-addr=%p", - msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_header_fc); - status = read_dscope_begin_state(msg_it, event_header_fc, STATE_AFTER_EVENT_HEADER, - STATE_DSCOPE_EVENT_HEADER_CONTINUE, NULL); - if (status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot decode event header field: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", fc-addr=%p", - msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_header_fc); - } - -end: - return status; -} - -static enum ctf_msg_iter_status read_event_header_continue_state(struct ctf_msg_iter *msg_it) -{ - return read_dscope_continue_state(msg_it, STATE_AFTER_EVENT_HEADER); -} - -static inline enum ctf_msg_iter_status set_current_event_class(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - - struct ctf_event_class *new_event_class = NULL; - - if (msg_it->cur_event_class_id == -1) { - /* - * No current event class ID field, therefore only one - * event class. - */ - if (msg_it->meta.sc->event_classes->len != 1) { - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "Need exactly one event class since there's no event class ID field: " - "msg-it-addr=%p", - msg_it); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - new_event_class = (ctf_event_class *) msg_it->meta.sc->event_classes->pdata[0]; - msg_it->cur_event_class_id = new_event_class->id; - } - - new_event_class = - ctf_stream_class_borrow_event_class_by_id(msg_it->meta.sc, msg_it->cur_event_class_id); - if (!new_event_class) { - BT_COMP_LOGE_APPEND_CAUSE( - self_comp, - "No event class with ID of event class ID to use in stream class: " - "msg-it-addr=%p, stream-class-id=%" PRIu64 ", " - "event-class-id=%" PRIu64 ", " - "trace-class-addr=%p", - msg_it, msg_it->meta.sc->id, msg_it->cur_event_class_id, msg_it->meta.tc); - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - - msg_it->meta.ec = new_event_class; - BT_COMP_LOGD("Set current event class: " - "msg-it-addr=%p, event-class-addr=%p, " - "event-class-id=%" PRId64 ", " - "event-class-name=\"%s\"", - msg_it, msg_it->meta.ec, msg_it->meta.ec->id, msg_it->meta.ec->name->str); - -end: - return status; -} - -static inline enum ctf_msg_iter_status set_current_event_message(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - bt_message *msg = NULL; - - BT_ASSERT_DBG(msg_it->meta.ec); - BT_ASSERT_DBG(msg_it->packet); - BT_COMP_LOGD("Creating event message from event class and packet: " - "msg-it-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p", - msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->packet); - BT_ASSERT_DBG(msg_it->self_msg_iter); - BT_ASSERT_DBG(msg_it->meta.sc); - - if (bt_stream_class_borrow_default_clock_class(msg_it->meta.sc->ir_sc)) { - msg = bt_message_event_create_with_packet_and_default_clock_snapshot( - msg_it->self_msg_iter, msg_it->meta.ec->ir_ec, msg_it->packet, - msg_it->default_clock_snapshot); - } else { - msg = bt_message_event_create_with_packet(msg_it->self_msg_iter, msg_it->meta.ec->ir_ec, - msg_it->packet); - } - - if (!msg) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create event message: " - "msg-it-addr=%p, ec-addr=%p, ec-name=\"%s\", " - "packet-addr=%p", - msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, - msg_it->packet); - goto error; - } - - goto end; - -error: - BT_MESSAGE_PUT_REF_AND_RESET(msg); - status = CTF_MSG_ITER_STATUS_ERROR; - -end: - BT_MESSAGE_MOVE_REF(msg_it->event_msg, msg); - return status; -} - -static enum ctf_msg_iter_status after_event_header_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status; - - status = set_current_event_class(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - if (G_UNLIKELY(msg_it->dry_run)) { - goto next_state; - } - - status = set_current_event_message(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - msg_it->event = bt_message_event_borrow_event(msg_it->event_msg); - BT_ASSERT_DBG(msg_it->event); - -next_state: - msg_it->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN; - -end: - return status; -} - -static enum ctf_msg_iter_status read_event_common_context_begin_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_field_class *event_common_context_fc; - - event_common_context_fc = msg_it->meta.sc->event_common_context_fc; - if (!event_common_context_fc) { - msg_it->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN; - goto end; - } - - if (event_common_context_fc->in_ir && !msg_it->dry_run) { - BT_ASSERT_DBG(!msg_it->dscopes.event_common_context); - msg_it->dscopes.event_common_context = bt_event_borrow_common_context_field(msg_it->event); - BT_ASSERT_DBG(msg_it->dscopes.event_common_context); - } - - BT_COMP_LOGT("Decoding event common context field: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", " - "fc-addr=%p", - msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_common_context_fc); - status = read_dscope_begin_state( - msg_it, event_common_context_fc, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN, - STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, msg_it->dscopes.event_common_context); - if (status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot decode event common context field: " - "msg-it-addr=%p, stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", fc-addr=%p", - msg_it, msg_it->meta.sc, msg_it->meta.sc->id, - event_common_context_fc); - } - -end: - return status; -} - -static enum ctf_msg_iter_status -read_event_common_context_continue_state(struct ctf_msg_iter *msg_it) -{ - return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN); -} - -static enum ctf_msg_iter_status read_event_spec_context_begin_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_field_class *event_spec_context_fc; - - event_spec_context_fc = msg_it->meta.ec->spec_context_fc; - if (!event_spec_context_fc) { - msg_it->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN; - goto end; - } - - if (event_spec_context_fc->in_ir && !msg_it->dry_run) { - BT_ASSERT_DBG(!msg_it->dscopes.event_spec_context); - msg_it->dscopes.event_spec_context = bt_event_borrow_specific_context_field(msg_it->event); - BT_ASSERT_DBG(msg_it->dscopes.event_spec_context); - } - - BT_COMP_LOGT("Decoding event specific context field: " - "msg-it-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "fc-addr=%p", - msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->meta.ec->id, - event_spec_context_fc); - status = read_dscope_begin_state( - msg_it, event_spec_context_fc, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, - STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, msg_it->dscopes.event_spec_context); - if (status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot decode event specific context field: " - "msg-it-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", fc-addr=%p", - msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, - msg_it->meta.ec->id, event_spec_context_fc); - } - -end: - return status; -} - -static enum ctf_msg_iter_status read_event_spec_context_continue_state(struct ctf_msg_iter *msg_it) -{ - return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN); -} - -static enum ctf_msg_iter_status read_event_payload_begin_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_field_class *event_payload_fc; - - event_payload_fc = msg_it->meta.ec->payload_fc; - if (!event_payload_fc) { - msg_it->state = STATE_EMIT_MSG_EVENT; - goto end; - } - - if (event_payload_fc->in_ir && !msg_it->dry_run) { - BT_ASSERT_DBG(!msg_it->dscopes.event_payload); - msg_it->dscopes.event_payload = bt_event_borrow_payload_field(msg_it->event); - BT_ASSERT_DBG(msg_it->dscopes.event_payload); - } - - BT_COMP_LOGT("Decoding event payload field: " - "msg-it-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "fc-addr=%p", - msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->meta.ec->id, - event_payload_fc); - status = - read_dscope_begin_state(msg_it, event_payload_fc, STATE_EMIT_MSG_EVENT, - STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, msg_it->dscopes.event_payload); - if (status < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot decode event payload field: " - "msg-it-addr=%p, event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", fc-addr=%p", - msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, - msg_it->meta.ec->id, event_payload_fc); - } - -end: - return status; -} - -static enum ctf_msg_iter_status read_event_payload_continue_state(struct ctf_msg_iter *msg_it) -{ - return read_dscope_continue_state(msg_it, STATE_EMIT_MSG_EVENT); -} - -static enum ctf_msg_iter_status skip_packet_padding_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - size_t bits_to_skip; - const enum state next_state = STATE_SWITCH_PACKET; - - BT_ASSERT(msg_it->cur_exp_packet_total_size > 0); - bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it); - if (bits_to_skip == 0) { - msg_it->state = next_state; - goto end; - } else { - size_t bits_to_consume; - - BT_COMP_LOGD("Trying to skip %zu bits of padding: msg-it-addr=%p, size=%zu", bits_to_skip, - msg_it, bits_to_skip); - status = buf_ensure_available_bits(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - bits_to_consume = MIN(buf_available_bits(msg_it), bits_to_skip); - BT_COMP_LOGD("Skipping %zu bits of padding: msg-it-addr=%p, size=%zu", bits_to_consume, - msg_it, bits_to_consume); - buf_consume_bits(msg_it, bits_to_consume); - bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it); - if (bits_to_skip == 0) { - msg_it->state = next_state; - goto end; - } - } - -end: - return status; -} - -static enum ctf_msg_iter_status check_emit_msg_discarded_events(struct ctf_msg_iter *msg_it) -{ - msg_it->state = STATE_EMIT_MSG_DISCARDED_EVENTS; - - if (!msg_it->meta.sc->has_discarded_events) { - msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; - goto end; - } - - if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) { - if (msg_it->snapshots.discarded_events == 0 || - msg_it->snapshots.discarded_events == UINT64_C(-1)) { - /* - * Stream's first packet with no discarded - * events or no information about discarded - * events: do not emit. - */ - msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; - } - } else { - /* - * If the previous packet has a value for this counter, - * then this counter is defined for the whole stream. - */ - BT_ASSERT(msg_it->snapshots.discarded_events != UINT64_C(-1)); - - if (msg_it->snapshots.discarded_events - msg_it->prev_packet_snapshots.discarded_events == - 0) { - /* - * No discarded events since previous packet: do - * not emit. - */ - msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; - } - } - -end: - return CTF_MSG_ITER_STATUS_OK; -} - -static enum ctf_msg_iter_status check_emit_msg_discarded_packets(struct ctf_msg_iter *msg_it) -{ - msg_it->state = STATE_EMIT_MSG_DISCARDED_PACKETS; - - if (!msg_it->meta.sc->has_discarded_packets) { - msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; - goto end; - } - - if (msg_it->prev_packet_snapshots.packets == UINT64_C(-1)) { - /* - * Stream's first packet or no information about - * discarded packets: do not emit. In other words, if - * this is the first packet and its sequence number is - * not 0, do not consider that packets were previously - * lost: we might be reading a partial stream (LTTng - * snapshot for example). - */ - msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; - } else { - /* - * If the previous packet has a value for this counter, - * then this counter is defined for the whole stream. - */ - BT_ASSERT(msg_it->snapshots.packets != UINT64_C(-1)); - - if (msg_it->snapshots.packets - msg_it->prev_packet_snapshots.packets <= 1) { - /* - * No discarded packets since previous packet: - * do not emit. - */ - msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; - } - } - -end: - return CTF_MSG_ITER_STATUS_OK; -} - -static inline enum state check_emit_msg_stream_end(struct ctf_msg_iter *msg_it) -{ - enum state next_state; - - if (msg_it->emit_stream_end_message) { - next_state = STATE_EMIT_MSG_STREAM_END; - } else { - next_state = STATE_DONE; - } - - return next_state; -} - -static inline enum ctf_msg_iter_status handle_state(struct ctf_msg_iter *msg_it) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - const enum state state = msg_it->state; - - BT_COMP_LOGT("Handling state: msg-it-addr=%p, state=%s", msg_it, state_string(state)); - - // TODO: optimalize! - switch (state) { - case STATE_INIT: - msg_it->state = STATE_SWITCH_PACKET; - break; - case STATE_SWITCH_PACKET: - status = switch_packet_state(msg_it); - break; - case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN: - status = read_packet_header_begin_state(msg_it); - break; - case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE: - status = read_packet_header_continue_state(msg_it); - break; - case STATE_AFTER_TRACE_PACKET_HEADER: - status = after_packet_header_state(msg_it); - break; - case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN: - status = read_packet_context_begin_state(msg_it); - break; - case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE: - status = read_packet_context_continue_state(msg_it); - break; - case STATE_AFTER_STREAM_PACKET_CONTEXT: - status = after_packet_context_state(msg_it); - break; - case STATE_EMIT_MSG_STREAM_BEGINNING: - msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS; - break; - case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS: - status = check_emit_msg_discarded_events(msg_it); - break; - case STATE_EMIT_MSG_DISCARDED_EVENTS: - msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; - break; - case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS: - status = check_emit_msg_discarded_packets(msg_it); - break; - case STATE_EMIT_MSG_DISCARDED_PACKETS: - msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; - break; - case STATE_EMIT_MSG_PACKET_BEGINNING: - msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN; - break; - case STATE_DSCOPE_EVENT_HEADER_BEGIN: - status = read_event_header_begin_state(msg_it); - break; - case STATE_DSCOPE_EVENT_HEADER_CONTINUE: - status = read_event_header_continue_state(msg_it); - break; - case STATE_AFTER_EVENT_HEADER: - status = after_event_header_state(msg_it); - break; - case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: - status = read_event_common_context_begin_state(msg_it); - break; - case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: - status = read_event_common_context_continue_state(msg_it); - break; - case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: - status = read_event_spec_context_begin_state(msg_it); - break; - case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: - status = read_event_spec_context_continue_state(msg_it); - break; - case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: - status = read_event_payload_begin_state(msg_it); - break; - case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: - status = read_event_payload_continue_state(msg_it); - break; - case STATE_EMIT_MSG_EVENT: - msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN; - break; - case STATE_EMIT_QUEUED_MSG_EVENT: - msg_it->state = STATE_EMIT_MSG_EVENT; - break; - case STATE_SKIP_PACKET_PADDING: - status = skip_packet_padding_state(msg_it); - break; - case STATE_EMIT_MSG_PACKET_END_MULTI: - msg_it->state = STATE_SKIP_PACKET_PADDING; - break; - case STATE_EMIT_MSG_PACKET_END_SINGLE: - msg_it->state = STATE_EMIT_MSG_STREAM_END; - break; - case STATE_EMIT_QUEUED_MSG_PACKET_END: - msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE; - break; - case STATE_CHECK_EMIT_MSG_STREAM_END: - msg_it->state = check_emit_msg_stream_end(msg_it); - break; - case STATE_EMIT_MSG_STREAM_END: - msg_it->state = STATE_DONE; - break; - case STATE_DONE: - break; - default: - BT_COMP_LOGF("Unknown CTF plugin message iterator state: " - "msg-it-addr=%p, state=%d", - msg_it, msg_it->state); - bt_common_abort(); - } - - BT_COMP_LOGT("Handled state: msg-it-addr=%p, status=%s, " - "prev-state=%s, cur-state=%s", - msg_it, ctf_msg_iter_status_string(status), state_string(state), - state_string(msg_it->state)); - return status; -} - -void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it) -{ - BT_ASSERT(msg_it); - BT_COMP_LOGD("Resetting message iterator: addr=%p", msg_it); - stack_clear(msg_it->stack); - msg_it->meta.sc = NULL; - msg_it->meta.ec = NULL; - BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); - BT_STREAM_PUT_REF_AND_RESET(msg_it->stream); - BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg); - release_all_dscopes(msg_it); - msg_it->cur_dscope_field = NULL; - - msg_it->buf.addr = NULL; - msg_it->buf.sz = 0; - msg_it->buf.at = 0; - msg_it->buf.last_eh_at = SIZE_MAX; - msg_it->buf.packet_offset = 0; - msg_it->state = STATE_INIT; - msg_it->cur_exp_packet_content_size = -1; - msg_it->cur_exp_packet_total_size = -1; - msg_it->cur_packet_offset = -1; - msg_it->cur_event_class_id = -1; - msg_it->snapshots.beginning_clock = UINT64_C(-1); - msg_it->snapshots.end_clock = UINT64_C(-1); -} - -/** - * Resets the internal state of a CTF message iterator. - */ -void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it) -{ - ctf_msg_iter_reset_for_next_stream_file(msg_it); - msg_it->cur_stream_class_id = -1; - msg_it->cur_data_stream_id = -1; - msg_it->snapshots.discarded_events = UINT64_C(-1); - msg_it->snapshots.packets = UINT64_C(-1); - msg_it->prev_packet_snapshots.discarded_events = UINT64_C(-1); - msg_it->prev_packet_snapshots.packets = UINT64_C(-1); - msg_it->prev_packet_snapshots.beginning_clock = UINT64_C(-1); - msg_it->prev_packet_snapshots.end_clock = UINT64_C(-1); - msg_it->emit_stream_beginning_message = true; - msg_it->emit_stream_end_message = false; -} - -static bt_field *borrow_next_field(struct ctf_msg_iter *msg_it) -{ - bt_field *next_field = NULL; - bt_field *base_field; - const bt_field_class *base_fc; - bt_field_class_type base_fc_type; - size_t index; - - BT_ASSERT_DBG(!stack_empty(msg_it->stack)); - index = stack_top(msg_it->stack)->index; - base_field = stack_top(msg_it->stack)->base; - BT_ASSERT_DBG(base_field); - base_fc = bt_field_borrow_class_const(base_field); - BT_ASSERT_DBG(base_fc); - base_fc_type = bt_field_class_get_type(base_fc); - - if (base_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { - BT_ASSERT_DBG(index < bt_field_class_structure_get_member_count( - bt_field_borrow_class_const(base_field))); - next_field = bt_field_structure_borrow_member_field_by_index(base_field, index); - } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) { - BT_ASSERT_DBG(index < bt_field_array_get_length(base_field)); - next_field = bt_field_array_borrow_element_field_by_index(base_field, index); - } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_VARIANT)) { - BT_ASSERT_DBG(index == 0); - next_field = bt_field_variant_borrow_selected_option_field(base_field); - } else { - bt_common_abort(); - } - - BT_ASSERT_DBG(next_field); - return next_field; -} - -static void update_default_clock(struct ctf_msg_iter *msg_it, uint64_t new_val, - uint64_t new_val_size) -{ - uint64_t new_val_mask; - uint64_t cur_value_masked; - - BT_ASSERT_DBG(new_val_size > 0); - - /* - * Special case for a 64-bit new value, which is the limit - * of a clock value as of this version: overwrite the - * current value directly. - */ - if (new_val_size == 64) { - msg_it->default_clock_snapshot = new_val; - goto end; - } - - new_val_mask = (1ULL << new_val_size) - 1; - cur_value_masked = msg_it->default_clock_snapshot & new_val_mask; - - if (new_val < cur_value_masked) { - /* - * It looks like a wrap happened on the number of bits - * of the requested new value. Assume that the clock - * value wrapped only one time. - */ - msg_it->default_clock_snapshot += new_val_mask + 1; - } - - /* Clear the low bits of the current clock value. */ - msg_it->default_clock_snapshot &= ~new_val_mask; - - /* Set the low bits of the current clock value. */ - msg_it->default_clock_snapshot |= new_val; - -end: - BT_COMP_LOGT("Updated default clock's value from integer field's value: " - "value=%" PRIu64, - msg_it->default_clock_snapshot); -} - -/* - * Ensure the message iterator's `stored_values` array is large enough to - * accommodate `storing_index`. - * - * We may need more slots in the array than initially allocated if more - * metadata arrives along the way. - */ -static void ensure_stored_values_size(ctf_msg_iter *msg_it, uint64_t storing_index) -{ - if (G_UNLIKELY(storing_index >= msg_it->stored_values->len)) { - g_array_set_size(msg_it->stored_values, msg_it->meta.tc->stored_value_count); - } -} - -static enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value, struct ctf_field_class *fc, - void *data) -{ - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - bt_self_component *self_comp = msg_it->self_comp; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - - bt_field *field = NULL; - - BT_COMP_LOGT("Unsigned integer function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d, value=%" PRIu64, - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); - - ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - - if (G_LIKELY(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE)) { - goto update_def_clock; - } - - switch (int_fc->meaning) { - case CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID: - msg_it->cur_event_class_id = value; - break; - case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID: - msg_it->cur_data_stream_id = value; - break; - case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME: - msg_it->snapshots.beginning_clock = value; - break; - case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME: - msg_it->snapshots.end_clock = value; - break; - case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID: - msg_it->cur_stream_class_id = value; - break; - case CTF_FIELD_CLASS_MEANING_MAGIC: - if (value != 0xc1fc1fc1) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Invalid CTF magic number: msg-it-addr=%p, " - "magic=%" PRIx64, - msg_it, value); - status = BT_BFCR_STATUS_ERROR; - goto end; - } - - break; - case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT: - msg_it->snapshots.packets = value; - break; - case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT: - msg_it->snapshots.discarded_events = value; - break; - case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE: - msg_it->cur_exp_packet_total_size = value; - break; - case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE: - msg_it->cur_exp_packet_content_size = value; - break; - default: - bt_common_abort(); - } - -update_def_clock: - if (G_UNLIKELY(int_fc->mapped_clock_class)) { - update_default_clock(msg_it, value, int_fc->base.size); - } - - if (G_UNLIKELY(int_fc->storing_index >= 0)) { - ensure_stored_values_size(msg_it, int_fc->storing_index); - bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = value; - } - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - field = borrow_next_field(msg_it); - BT_ASSERT_DBG(field); - BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(field), - BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)); - bt_field_integer_unsigned_set_value(field, value); - stack_top(msg_it->stack)->index++; - -end: - return status; -} - -static enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value, struct ctf_field_class *fc, - void *data) -{ - int ret; - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - bt_self_component *self_comp = msg_it->self_comp; - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - bt_field *string_field = NULL; - char str[2] = {'\0', '\0'}; - - BT_COMP_LOGT("Unsigned integer character function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d, value=%" PRIu64, - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); - - ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); - BT_ASSERT_DBG(!int_fc->mapped_clock_class); - BT_ASSERT_DBG(int_fc->storing_index < 0); - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - if (msg_it->done_filling_string) { - goto end; - } - - if (value == 0) { - msg_it->done_filling_string = true; - goto end; - } - - string_field = stack_top(msg_it->stack)->base; - BT_ASSERT_DBG(bt_field_get_class_type(string_field) == BT_FIELD_CLASS_TYPE_STRING); - - /* Append character */ - str[0] = (char) value; - ret = bt_field_string_append_with_length(string_field, str, 1); - if (ret) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot append character to string field's value: " - "msg-it-addr=%p, field-addr=%p, ret=%d", - msg_it, string_field, ret); - status = BT_BFCR_STATUS_ERROR; - goto end; - } - -end: - return status; -} - -static enum bt_bfcr_status bfcr_signed_int_cb(int64_t value, struct ctf_field_class *fc, void *data) -{ - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - bt_field *field = NULL; - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - - BT_COMP_LOGT("Signed integer function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d, value=%" PRId64, - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); - - ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); - BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); - - if (G_UNLIKELY(int_fc->storing_index >= 0)) { - ensure_stored_values_size(msg_it, int_fc->storing_index); - bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = - (uint64_t) value; - } - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - field = borrow_next_field(msg_it); - BT_ASSERT_DBG(field); - BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT_DBG( - bt_field_class_type_is(bt_field_get_class_type(field), BT_FIELD_CLASS_TYPE_SIGNED_INTEGER)); - bt_field_integer_signed_set_value(field, value); - stack_top(msg_it->stack)->index++; - -end: - return status; -} - -static enum bt_bfcr_status bfcr_floating_point_cb(double value, struct ctf_field_class *fc, - void *data) -{ - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - bt_field *field = NULL; - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - bt_field_class_type type; - - BT_COMP_LOGT("Floating point number function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d, value=%f", - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - field = borrow_next_field(msg_it); - type = bt_field_get_class_type(field); - BT_ASSERT_DBG(field); - BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT_DBG(bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_REAL)); - - if (type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) { - bt_field_real_single_precision_set_value(field, (float) value); - } else { - bt_field_real_double_precision_set_value(field, value); - } - stack_top(msg_it->stack)->index++; - -end: - return status; -} - -static enum bt_bfcr_status bfcr_string_begin_cb(struct ctf_field_class *fc, void *data) -{ - bt_field *field = NULL; - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - - BT_COMP_LOGT("String (beginning) function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d", - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - field = borrow_next_field(msg_it); - BT_ASSERT_DBG(field); - BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); - BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING); - bt_field_string_clear(field); - - /* - * Push on stack. Not a compound class per se, but we know that - * only bfcr_string_cb() may be called between this call and a - * subsequent call to bfcr_string_end_cb(). - */ - stack_push(msg_it->stack, field); - -end: - return BT_BFCR_STATUS_OK; -} - -static enum bt_bfcr_status bfcr_string_cb(const char *value, size_t len, struct ctf_field_class *fc, - void *data) -{ - enum bt_bfcr_status status = BT_BFCR_STATUS_OK; - bt_field *field = NULL; - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - bt_self_component *self_comp = msg_it->self_comp; - int ret; - - BT_COMP_LOGT("String (substring) function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d, string-length=%zu", - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, len); - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - field = stack_top(msg_it->stack)->base; - BT_ASSERT_DBG(field); - - /* Append current substring */ - ret = bt_field_string_append_with_length(field, value, len); - if (ret) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot append substring to string field's value: " - "msg-it-addr=%p, field-addr=%p, string-length=%zu, " - "ret=%d", - msg_it, field, len, ret); - status = BT_BFCR_STATUS_ERROR; - goto end; - } - -end: - return status; -} - -static enum bt_bfcr_status bfcr_string_end_cb(struct ctf_field_class *fc, void *data) -{ - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - - BT_COMP_LOGT("String (end) function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d", - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - /* Pop string field */ - stack_pop(msg_it->stack); - - /* Go to next field */ - stack_top(msg_it->stack)->index++; - -end: - return BT_BFCR_STATUS_OK; -} - -static enum bt_bfcr_status bfcr_compound_begin_cb(struct ctf_field_class *fc, void *data) -{ - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - bt_field *field; - - BT_COMP_LOGT("Compound (beginning) function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d", - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - /* Borrow field */ - if (stack_empty(msg_it->stack)) { - /* Root: already set by read_dscope_begin_state() */ - field = msg_it->cur_dscope_field; - } else { - field = borrow_next_field(msg_it); - BT_ASSERT_DBG(field); - } - - /* Push field */ - BT_ASSERT_DBG(field); - BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); - stack_push(msg_it->stack, field); - - /* - * Change BFCR "unsigned int" callback if it's a text - * array/sequence. - */ - if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { - ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - if (array_fc->is_text) { - BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING); - msg_it->done_filling_string = false; - bt_field_string_clear(field); - bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_char_cb); - } - } - -end: - return BT_BFCR_STATUS_OK; -} - -static enum bt_bfcr_status bfcr_compound_end_cb(struct ctf_field_class *fc, void *data) -{ - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - - BT_COMP_LOGT("Compound (end) function called from BFCR: " - "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " - "fc-type=%d, fc-in-ir=%d", - msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); - - if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { - goto end; - } - - BT_ASSERT_DBG(!stack_empty(msg_it->stack)); - BT_ASSERT_DBG(bt_field_borrow_class_const(stack_top(msg_it->stack)->base) == fc->ir_fc); - - /* - * Reset BFCR "unsigned int" callback if it's a text - * array/sequence. - */ - if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { - ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); - - if (array_fc->is_text) { - BT_ASSERT_DBG(bt_field_get_class_type(stack_top(msg_it->stack)->base) == - BT_FIELD_CLASS_TYPE_STRING); - bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_cb); - } - } - - /* Pop stack */ - stack_pop(msg_it->stack); - - /* If the stack is not empty, increment the base's index */ - if (!stack_empty(msg_it->stack)) { - stack_top(msg_it->stack)->index++; - } - -end: - return BT_BFCR_STATUS_OK; -} - -static int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data) -{ - bt_field *seq_field; - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); - int64_t length; - int ret; - - length = - (uint64_t) bt_g_array_index(msg_it->stored_values, uint64_t, seq_fc->stored_length_index); - - if (G_UNLIKELY(msg_it->dry_run)) { - goto end; - } - - seq_field = stack_top(msg_it->stack)->base; - BT_ASSERT_DBG(seq_field); - - /* - * bfcr_get_sequence_length_cb() also gets called back for a - * text sequence, but the destination field is a string field. - * Only set the field's sequence length if the destination field - * is a sequence field. - */ - if (!seq_fc->base.is_text) { - BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(seq_field), - BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)); - ret = bt_field_array_dynamic_set_length(seq_field, (uint64_t) length); - if (ret) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot set dynamic array field's length field: " - "msg-it-addr=%p, field-addr=%p, " - "length=%" PRIu64, - msg_it, seq_field, length); - length = -1; - } - } - -end: - return length; -} - -static struct ctf_field_class * -bfcr_borrow_variant_selected_field_class_cb(struct ctf_field_class *fc, void *data) -{ - int ret; - uint64_t i; - int64_t option_index = -1; - ctf_msg_iter *msg_it = (ctf_msg_iter *) data; - ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); - struct ctf_named_field_class *selected_option = NULL; - bt_self_component *self_comp = msg_it->self_comp; - struct ctf_field_class *ret_fc = NULL; - union - { - uint64_t u; - int64_t i; - } tag; - - /* Get variant's tag */ - tag.u = bt_g_array_index(msg_it->stored_values, uint64_t, var_fc->stored_tag_index); - - /* - * Check each range to find the selected option's index. - */ - if (var_fc->tag_fc->base.is_signed) { - for (i = 0; i < var_fc->ranges->len; i++) { - struct ctf_field_class_variant_range *range = - ctf_field_class_variant_borrow_range_by_index(var_fc, i); - - if (tag.i >= range->range.lower.i && tag.i <= range->range.upper.i) { - option_index = (int64_t) range->option_index; - break; - } - } - } else { - for (i = 0; i < var_fc->ranges->len; i++) { - struct ctf_field_class_variant_range *range = - ctf_field_class_variant_borrow_range_by_index(var_fc, i); - - if (tag.u >= range->range.lower.u && tag.u <= range->range.upper.u) { - option_index = (int64_t) range->option_index; - break; - } - } - } - - if (option_index < 0) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot find variant field class's option: " - "msg-it-addr=%p, var-fc-addr=%p, u-tag=%" PRIu64 ", " - "i-tag=%" PRId64, - msg_it, var_fc, tag.u, tag.i); - ret_fc = NULL; - goto end; - } - - selected_option = - ctf_field_class_variant_borrow_option_by_index(var_fc, (uint64_t) option_index); - - if (selected_option->fc->in_ir && !msg_it->dry_run) { - bt_field *var_field = stack_top(msg_it->stack)->base; - - ret = bt_field_variant_select_option_by_index(var_field, option_index); - if (ret) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot select variant field's option field: " - "msg-it-addr=%p, var-field-addr=%p, " - "opt-index=%" PRId64, - msg_it, var_field, option_index); - ret_fc = NULL; - goto end; - } - } - - ret_fc = selected_option->fc; - -end: - return ret_fc; -} - -static bt_message *create_msg_stream_beginning(struct ctf_msg_iter *msg_it) -{ - bt_self_component *self_comp = msg_it->self_comp; - bt_message *msg; - - BT_ASSERT(msg_it->stream); - BT_ASSERT(msg_it->self_msg_iter); - msg = bt_message_stream_beginning_create(msg_it->self_msg_iter, msg_it->stream); - if (!msg) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create stream beginning message: " - "msg-it-addr=%p, stream-addr=%p", - msg_it, msg_it->stream); - } - - return msg; -} - -static bt_message *create_msg_stream_end(struct ctf_msg_iter *msg_it) -{ - bt_self_component *self_comp = msg_it->self_comp; - bt_message *msg; - - if (!msg_it->stream) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create stream end message because stream is NULL: " - "msg-it-addr=%p", - msg_it); - msg = NULL; - goto end; - } - - BT_ASSERT(msg_it->self_msg_iter); - msg = bt_message_stream_end_create(msg_it->self_msg_iter, msg_it->stream); - if (!msg) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create stream end message: " - "msg-it-addr=%p, stream-addr=%p", - msg_it, msg_it->stream); - } - -end: - return msg; -} - -static bt_message *create_msg_packet_beginning(struct ctf_msg_iter *msg_it, bool use_default_cs) -{ - bt_self_component *self_comp = msg_it->self_comp; - bt_message *msg; - const bt_stream_class *sc = msg_it->meta.sc->ir_sc; - - BT_ASSERT(msg_it->packet); - BT_ASSERT(sc); - BT_ASSERT(msg_it->self_msg_iter); - - if (msg_it->meta.sc->packets_have_ts_begin) { - BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1)); - uint64_t raw_cs_value; - - /* - * Either use the decoded packet `timestamp_begin` field or the - * current stream's default clock_snapshot. - */ - if (use_default_cs) { - raw_cs_value = msg_it->default_clock_snapshot; - } else { - raw_cs_value = msg_it->snapshots.beginning_clock; - } - - msg = bt_message_packet_beginning_create_with_default_clock_snapshot( - msg_it->self_msg_iter, msg_it->packet, raw_cs_value); - } else { - msg = bt_message_packet_beginning_create(msg_it->self_msg_iter, msg_it->packet); - } - - if (!msg) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create packet beginning message: " - "msg-it-addr=%p, packet-addr=%p", - msg_it, msg_it->packet); - goto end; - } - -end: - return msg; -} - -static bt_message *emit_delayed_packet_beg_msg(struct ctf_msg_iter *msg_it) -{ - bool packet_beg_ts_need_fix_up; - - msg_it->emit_delayed_packet_beginning_msg = false; - - /* - * Only fix the packet's timestamp_begin if it's larger than the first - * event of the packet. If there was no event in the packet, the - * `default_clock_snapshot` field will be either equal or greater than - * `snapshots.beginning_clock` so there is not fix needed. - */ - packet_beg_ts_need_fix_up = msg_it->default_clock_snapshot < msg_it->snapshots.beginning_clock; - - /* create_msg_packet_beginning() logs errors */ - return create_msg_packet_beginning(msg_it, packet_beg_ts_need_fix_up); -} - -static bt_message *create_msg_packet_end(struct ctf_msg_iter *msg_it) -{ - bt_message *msg; - bool update_default_cs = true; - bt_self_component *self_comp = msg_it->self_comp; - - if (!msg_it->packet) { - msg = NULL; - goto end; - } - - /* - * Check if we need to emit the delayed packet - * beginning message instead of the packet end message. - */ - if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) { - msg = emit_delayed_packet_beg_msg(msg_it); - /* Don't forget to emit the packet end message. */ - msg_it->state = STATE_EMIT_QUEUED_MSG_PACKET_END; - goto end; - } - - /* Check if may be affected by lttng-crash timestamp_end quirk. */ - if (G_UNLIKELY(msg_it->meta.tc->quirks.lttng_crash)) { - /* - * Check if the `timestamp_begin` field is non-zero but - * `timestamp_end` is zero. It means the trace is affected by - * the lttng-crash packet `timestamp_end` quirk and must be - * fixed up by omitting to update the default clock snapshot to - * the `timestamp_end` as is typically done. - */ - if (msg_it->snapshots.beginning_clock != 0 && msg_it->snapshots.end_clock == 0) { - update_default_cs = false; - } - } - - /* - * Check if may be affected by lttng event-after-packet `timestamp_end` - * quirk. - */ - if (msg_it->meta.tc->quirks.lttng_event_after_packet) { - /* - * Check if `timestamp_end` is smaller then the current - * default_clock_snapshot (which is set to the last event - * decoded). It means the trace is affected by the lttng - * `event-after-packet` packet `timestamp_end` quirk and must - * be fixed up by omitting to update the default clock snapshot - * to the `timestamp_end` as is typically done. - */ - if (msg_it->snapshots.end_clock < msg_it->default_clock_snapshot) { - update_default_cs = false; - } - } - - /* Update default clock from packet's end time. */ - if (msg_it->snapshots.end_clock != UINT64_C(-1) && update_default_cs) { - msg_it->default_clock_snapshot = msg_it->snapshots.end_clock; - } - - BT_ASSERT(msg_it->self_msg_iter); - - if (msg_it->meta.sc->packets_have_ts_end) { - BT_ASSERT(msg_it->snapshots.end_clock != UINT64_C(-1)); - msg = bt_message_packet_end_create_with_default_clock_snapshot( - msg_it->self_msg_iter, msg_it->packet, msg_it->default_clock_snapshot); - } else { - msg = bt_message_packet_end_create(msg_it->self_msg_iter, msg_it->packet); - } - - if (!msg) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create packet end message: " - "msg-it-addr=%p, packet-addr=%p", - msg_it, msg_it->packet); - goto end; - } - - BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); - -end: - return msg; -} - -static bt_message *create_msg_discarded_events(struct ctf_msg_iter *msg_it) -{ - bt_message *msg; - bt_self_component *self_comp = msg_it->self_comp; - uint64_t beginning_raw_value = UINT64_C(-1); - uint64_t end_raw_value = UINT64_C(-1); - - BT_ASSERT(msg_it->self_msg_iter); - BT_ASSERT(msg_it->stream); - BT_ASSERT(msg_it->meta.sc->has_discarded_events); - - if (msg_it->meta.sc->discarded_events_have_default_cs) { - if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) { - /* - * We discarded events, but before (and possibly - * including) the current packet: use this packet's time - * range, and do not have a specific count. - */ - beginning_raw_value = msg_it->snapshots.beginning_clock; - end_raw_value = msg_it->snapshots.end_clock; - } else { - beginning_raw_value = msg_it->prev_packet_snapshots.end_clock; - end_raw_value = msg_it->snapshots.end_clock; - } - - BT_ASSERT(beginning_raw_value != UINT64_C(-1)); - BT_ASSERT(end_raw_value != UINT64_C(-1)); - msg = bt_message_discarded_events_create_with_default_clock_snapshots( - msg_it->self_msg_iter, msg_it->stream, beginning_raw_value, end_raw_value); - } else { - msg = bt_message_discarded_events_create(msg_it->self_msg_iter, msg_it->stream); - } - - if (!msg) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create discarded events message: " - "msg-it-addr=%p, stream-addr=%p", - msg_it, msg_it->stream); - goto end; - } - - if (msg_it->prev_packet_snapshots.discarded_events != UINT64_C(-1)) { - bt_message_discarded_events_set_count(msg, - msg_it->snapshots.discarded_events - - msg_it->prev_packet_snapshots.discarded_events); - } - -end: - return msg; -} - -static bt_message *create_msg_discarded_packets(struct ctf_msg_iter *msg_it) -{ - bt_message *msg; - bt_self_component *self_comp = msg_it->self_comp; - - BT_ASSERT(msg_it->self_msg_iter); - BT_ASSERT(msg_it->stream); - BT_ASSERT(msg_it->meta.sc->has_discarded_packets); - BT_ASSERT(msg_it->prev_packet_snapshots.packets != UINT64_C(-1)); - - if (msg_it->meta.sc->discarded_packets_have_default_cs) { - BT_ASSERT(msg_it->prev_packet_snapshots.end_clock != UINT64_C(-1)); - BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1)); - msg = bt_message_discarded_packets_create_with_default_clock_snapshots( - msg_it->self_msg_iter, msg_it->stream, msg_it->prev_packet_snapshots.end_clock, - msg_it->snapshots.beginning_clock); - } else { - msg = bt_message_discarded_packets_create(msg_it->self_msg_iter, msg_it->stream); - } - - if (!msg) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, - "Cannot create discarded packets message: " - "msg-it-addr=%p, stream-addr=%p", - msg_it, msg_it->stream); - goto end; - } - - bt_message_discarded_packets_set_count(msg, msg_it->snapshots.packets - - msg_it->prev_packet_snapshots.packets - 1); - -end: - return msg; -} - -struct ctf_msg_iter *ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz, - struct ctf_msg_iter_medium_ops medops, void *data, - bt_logging_level log_level, bt_self_component *self_comp, - bt_self_message_iterator *self_msg_iter) -{ - struct ctf_msg_iter *msg_it = NULL; - struct bt_bfcr_cbs cbs = { - .classes = - { - .signed_int = bfcr_signed_int_cb, - .unsigned_int = bfcr_unsigned_int_cb, - .floating_point = bfcr_floating_point_cb, - .string_begin = bfcr_string_begin_cb, - .string = bfcr_string_cb, - .string_end = bfcr_string_end_cb, - .compound_begin = bfcr_compound_begin_cb, - .compound_end = bfcr_compound_end_cb, - }, - .query = - { - .get_sequence_length = bfcr_get_sequence_length_cb, - .borrow_variant_selected_field_class = bfcr_borrow_variant_selected_field_class_cb, - }, - }; - - BT_ASSERT(tc); - BT_ASSERT(medops.request_bytes); - BT_ASSERT(medops.borrow_stream); - BT_ASSERT(max_request_sz > 0); - - BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp, - "Creating CTF plugin message iterator: " - "trace-addr=%p, max-request-size=%zu, " - "data=%p, log-level=%s", - tc, max_request_sz, data, bt_common_logging_level_string(log_level)); - msg_it = g_new0(struct ctf_msg_iter, 1); - if (!msg_it) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, - "Failed to allocate one CTF plugin message iterator."); - goto end; - } - msg_it->self_comp = self_comp; - msg_it->self_msg_iter = self_msg_iter; - msg_it->log_level = log_level; - msg_it->meta.tc = tc; - msg_it->medium.medops = medops; - msg_it->medium.max_request_sz = max_request_sz; - msg_it->medium.data = data; - msg_it->stack = stack_new(msg_it); - msg_it->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t)); - g_array_set_size(msg_it->stored_values, tc->stored_value_count); - - if (!msg_it->stack) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create field stack."); - goto error; - } - - msg_it->bfcr = bt_bfcr_create(cbs, msg_it, log_level, NULL); - if (!msg_it->bfcr) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create binary class reader (BFCR)."); - goto error; - } - - ctf_msg_iter_reset(msg_it); - BT_COMP_LOGD("Created CTF plugin message iterator: " - "trace-addr=%p, max-request-size=%zu, " - "data=%p, msg-it-addr=%p, log-level=%s", - tc, max_request_sz, data, msg_it, bt_common_logging_level_string(log_level)); - msg_it->cur_packet_offset = 0; - -end: - return msg_it; - -error: - ctf_msg_iter_destroy(msg_it); - msg_it = NULL; - goto end; -} - -void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_it) -{ - BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); - BT_STREAM_PUT_REF_AND_RESET(msg_it->stream); - release_all_dscopes(msg_it); - - BT_COMP_LOGD("Destroying CTF plugin message iterator: addr=%p", msg_it); - - if (msg_it->stack) { - BT_COMP_LOGD_STR("Destroying field stack."); - stack_destroy(msg_it->stack); - } - - if (msg_it->bfcr) { - BT_COMP_LOGD("Destroying BFCR: bfcr-addr=%p", msg_it->bfcr); - bt_bfcr_destroy(msg_it->bfcr); - } - - if (msg_it->stored_values) { - g_array_free(msg_it->stored_values, TRUE); - } - - g_free(msg_it); -} - -enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it, - const bt_message **message) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - - BT_ASSERT_DBG(msg_it); - BT_ASSERT_DBG(message); - BT_COMP_LOGD("Getting next message: msg-it-addr=%p", msg_it); - - while (true) { - status = handle_state(msg_it); - if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) { - BT_COMP_LOGD_STR("Medium returned CTF_MSG_ITER_STATUS_AGAIN."); - goto end; - } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot handle state: msg-it-addr=%p, state=%s", - msg_it, state_string(msg_it->state)); - goto end; - } - - switch (msg_it->state) { - case STATE_EMIT_MSG_EVENT: - BT_ASSERT_DBG(msg_it->event_msg); - - /* - * Check if we need to emit the delayed packet - * beginning message instead of the event message. - */ - if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) { - *message = emit_delayed_packet_beg_msg(msg_it); - if (!*message) { - status = CTF_MSG_ITER_STATUS_ERROR; - } - - /* - * Don't forget to emit the event message of - * the event record that was just decoded. - */ - msg_it->state = STATE_EMIT_QUEUED_MSG_EVENT; - - } else { - *message = msg_it->event_msg; - msg_it->event_msg = NULL; - } - goto end; - case STATE_EMIT_MSG_DISCARDED_EVENTS: - /* create_msg_discarded_events() logs errors */ - *message = create_msg_discarded_events(msg_it); - - if (!*message) { - status = CTF_MSG_ITER_STATUS_ERROR; - } - - goto end; - case STATE_EMIT_MSG_DISCARDED_PACKETS: - /* create_msg_discarded_packets() logs errors */ - *message = create_msg_discarded_packets(msg_it); - - if (!*message) { - status = CTF_MSG_ITER_STATUS_ERROR; - } - - goto end; - case STATE_EMIT_MSG_PACKET_BEGINNING: - if (G_UNLIKELY(msg_it->meta.tc->quirks.barectf_event_before_packet)) { - msg_it->emit_delayed_packet_beginning_msg = true; - /* - * There is no message to return yet as this - * packet beginning message is delayed until we - * decode the first event message of the - * packet. - */ - break; - } else { - /* create_msg_packet_beginning() logs errors */ - *message = create_msg_packet_beginning(msg_it, false); - if (!*message) { - status = CTF_MSG_ITER_STATUS_ERROR; - } - } - - goto end; - case STATE_EMIT_MSG_PACKET_END_SINGLE: - case STATE_EMIT_MSG_PACKET_END_MULTI: - /* create_msg_packet_end() logs errors */ - *message = create_msg_packet_end(msg_it); - - if (!*message) { - status = CTF_MSG_ITER_STATUS_ERROR; - } - - goto end; - case STATE_EMIT_MSG_STREAM_BEGINNING: - /* create_msg_stream_beginning() logs errors */ - *message = create_msg_stream_beginning(msg_it); - msg_it->emit_stream_beginning_message = false; - msg_it->emit_stream_end_message = true; - - if (!*message) { - status = CTF_MSG_ITER_STATUS_ERROR; - } - - goto end; - case STATE_EMIT_MSG_STREAM_END: - /* create_msg_stream_end() logs errors */ - *message = create_msg_stream_end(msg_it); - msg_it->emit_stream_end_message = false; - - if (!*message) { - status = CTF_MSG_ITER_STATUS_ERROR; - } - - goto end; - case STATE_DONE: - status = CTF_MSG_ITER_STATUS_EOF; - goto end; - default: - /* Non-emitting state: continue */ - break; - } - } - -end: - return status; -} - -static enum ctf_msg_iter_status decode_until_state(struct ctf_msg_iter *msg_it, - enum state target_state_1, - enum state target_state_2) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - bt_self_component *self_comp = msg_it->self_comp; - - BT_ASSERT_DBG(msg_it); - - do { - /* - * Check if we reached the state at which we want to stop - * decoding. - */ - if (msg_it->state == target_state_1 || msg_it->state == target_state_2) { - goto end; - } - - status = handle_state(msg_it); - if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) { - BT_COMP_LOGD_STR("Medium returned CTF_MSG_ITER_STATUS_AGAIN."); - goto end; - } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) { - BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot handle state: msg-it-addr=%p, state=%s", - msg_it, state_string(msg_it->state)); - goto end; - } - - switch (msg_it->state) { - case STATE_INIT: - case STATE_SWITCH_PACKET: - case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN: - case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE: - case STATE_AFTER_TRACE_PACKET_HEADER: - case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN: - case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE: - case STATE_AFTER_STREAM_PACKET_CONTEXT: - case STATE_EMIT_MSG_STREAM_BEGINNING: - case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS: - case STATE_EMIT_MSG_DISCARDED_EVENTS: - case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS: - case STATE_EMIT_MSG_DISCARDED_PACKETS: - case STATE_EMIT_MSG_PACKET_BEGINNING: - case STATE_DSCOPE_EVENT_HEADER_BEGIN: - case STATE_DSCOPE_EVENT_HEADER_CONTINUE: - case STATE_AFTER_EVENT_HEADER: - case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: - case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: - case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: - case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: - case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: - case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: - case STATE_EMIT_MSG_EVENT: - case STATE_EMIT_QUEUED_MSG_EVENT: - case STATE_SKIP_PACKET_PADDING: - case STATE_EMIT_MSG_PACKET_END_MULTI: - case STATE_EMIT_MSG_PACKET_END_SINGLE: - case STATE_EMIT_QUEUED_MSG_PACKET_END: - case STATE_EMIT_MSG_STREAM_END: - break; - case STATE_DONE: - /* fall-through */ - default: - /* We should never get to the STATE_DONE state. */ - BT_COMP_LOGF("Unexpected state: msg-it-addr=%p, state=%s", msg_it, - state_string(msg_it->state)); - bt_common_abort(); - } - } while (true); - -end: - return status; -} - -static enum ctf_msg_iter_status read_packet_header_context_fields(struct ctf_msg_iter *msg_it) -{ - int ret; - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - - status = decode_until_state(msg_it, STATE_EMIT_MSG_PACKET_BEGINNING, (state) -1); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - ret = set_current_packet_content_sizes(msg_it); - if (ret) { - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - -end: - return status; -} - -enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, off_t offset) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - enum ctf_msg_iter_medium_status medium_status; - - BT_ASSERT(msg_it); - BT_ASSERT(offset >= 0); - BT_ASSERT(msg_it->medium.medops.seek); - - medium_status = msg_it->medium.medops.seek(offset, msg_it->medium.data); - if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) { - if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) { - status = CTF_MSG_ITER_STATUS_EOF; - } else { - status = CTF_MSG_ITER_STATUS_ERROR; - goto end; - } - } - - ctf_msg_iter_reset(msg_it); - msg_it->cur_packet_offset = offset; - -end: - return status; -} - -static enum ctf_msg_iter_status clock_snapshot_at_msg_iter_state(struct ctf_msg_iter *msg_it, - enum state target_state_1, - enum state target_state_2, - uint64_t *clock_snapshot) -{ - enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; - - BT_ASSERT_DBG(msg_it); - BT_ASSERT_DBG(clock_snapshot); - status = decode_until_state(msg_it, target_state_1, target_state_2); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - *clock_snapshot = msg_it->default_clock_snapshot; -end: - return status; -} - -enum ctf_msg_iter_status -ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it, - uint64_t *first_clock_snapshot) -{ - return clock_snapshot_at_msg_iter_state(msg_it, STATE_AFTER_EVENT_HEADER, (state) -1, - first_clock_snapshot); -} - -enum ctf_msg_iter_status -ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it, - uint64_t *last_clock_snapshot) -{ - return clock_snapshot_at_msg_iter_state(msg_it, STATE_EMIT_MSG_PACKET_END_SINGLE, - STATE_EMIT_MSG_PACKET_END_MULTI, last_clock_snapshot); -} - -enum ctf_msg_iter_status -ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it, - struct ctf_msg_iter_packet_properties *props) -{ - enum ctf_msg_iter_status status; - - BT_ASSERT_DBG(msg_it); - BT_ASSERT_DBG(props); - status = read_packet_header_context_fields(msg_it); - if (status != CTF_MSG_ITER_STATUS_OK) { - goto end; - } - - props->exp_packet_total_size = msg_it->cur_exp_packet_total_size; - props->exp_packet_content_size = msg_it->cur_exp_packet_content_size; - props->stream_class_id = (uint64_t) msg_it->cur_stream_class_id; - props->data_stream_id = msg_it->cur_data_stream_id; - props->snapshots.discarded_events = msg_it->snapshots.discarded_events; - props->snapshots.packets = msg_it->snapshots.packets; - props->snapshots.beginning_clock = msg_it->snapshots.beginning_clock; - props->snapshots.end_clock = msg_it->snapshots.end_clock; - -end: - return status; -} - -void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val) -{ - msg_it->dry_run = val; -} diff --git a/src/plugins/ctf/common/msg-iter/msg-iter.hpp b/src/plugins/ctf/common/msg-iter/msg-iter.hpp deleted file mode 100644 index 0b49c1c6..00000000 --- a/src/plugins/ctf/common/msg-iter/msg-iter.hpp +++ /dev/null @@ -1,341 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015-2016 Philippe Proulx - * - * Babeltrace - CTF message iterator - */ - -#ifndef CTF_MSG_ITER_H -#define CTF_MSG_ITER_H - -#include -#include -#include - -#include - -#include "common/common.h" - -/** - * @file ctf-msg-iter.h - * - * CTF message iterator - * - * This is a common internal API used by CTF source plugins. It allows - * one to get messages from a user-provided medium. - */ - -/** - * Medium operations status codes. These use the same values as - * libbabeltrace2. - */ -enum ctf_msg_iter_medium_status -{ - /** - * End of file. - * - * The medium function called by the message iterator - * function reached the end of the file. - */ - CTF_MSG_ITER_MEDIUM_STATUS_EOF = 1, - - /** - * There is no data available right now, try again later. - */ - CTF_MSG_ITER_MEDIUM_STATUS_AGAIN = 11, - - /** General error. */ - CTF_MSG_ITER_MEDIUM_STATUS_ERROR = -1, - - /** Memory error. */ - CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR = -12, - - /** Everything okay. */ - CTF_MSG_ITER_MEDIUM_STATUS_OK = 0, -}; - -/** - * CTF message iterator API status code. - */ -enum ctf_msg_iter_status -{ - /** - * End of file. - * - * The medium function called by the message iterator - * function reached the end of the file. - */ - CTF_MSG_ITER_STATUS_EOF = CTF_MSG_ITER_MEDIUM_STATUS_EOF, - - /** - * There is no data available right now, try again later. - * - * Some condition resulted in the - * ctf_msg_iter_medium_ops::request_bytes() user function not - * having access to any data now. You should retry calling the - * last called message iterator function once the situation - * is resolved. - */ - CTF_MSG_ITER_STATUS_AGAIN = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN, - - /** General error. */ - CTF_MSG_ITER_STATUS_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_ERROR, - - /** Memory error. */ - CTF_MSG_ITER_STATUS_MEMORY_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR, - - /** Everything okay. */ - CTF_MSG_ITER_STATUS_OK = CTF_MSG_ITER_MEDIUM_STATUS_OK, -}; - -/** - * Medium operations. - * - * Those user functions are called by the message iterator - * functions to request medium actions. - */ -struct ctf_msg_iter_medium_ops -{ - /** - * Returns the next byte buffer to be used by the binary file - * reader to deserialize binary data. - * - * This function \em must be defined. - * - * The purpose of this function is to return a buffer of bytes - * to the message iterator, of a maximum of \p request_sz - * bytes. If this function cannot return a buffer of at least - * \p request_sz bytes, it may return a smaller buffer. In - * either cases, \p buffer_sz must be set to the returned buffer - * size (in bytes). - * - * The returned buffer's ownership remains the medium, in that - * it won't be freed by the message iterator functions. The - * returned buffer won't be modified by the message - * iterator functions either. - * - * When this function is called for the first time for a given - * file, the offset within the file is considered to be 0. The - * next times this function is called, the returned buffer's - * byte offset within the complete file must be the previous - * offset plus the last returned value of \p buffer_sz by this - * medium. - * - * This function must return one of the following statuses: - * - * - #CTF_MSG_ITER_MEDIUM_STATUS_OK: Everything - * is okay, i.e. \p buffer_sz is set to a positive value - * reflecting the number of available bytes in the buffer - * starting at the address written in \p buffer_addr. - * - #CTF_MSG_ITER_MEDIUM_STATUS_AGAIN: No data is - * available right now. In this case, the message - * iterator function called by the user returns - * #CTF_MSG_ITER_STATUS_AGAIN, and it is the user's - * responsibility to make sure enough data becomes available - * before calling the \em same message iterator - * function again to continue the decoding process. - * - #CTF_MSG_ITER_MEDIUM_STATUS_EOF: The end of - * the file was reached, and no more data will ever be - * available for this file. In this case, the message - * iterator function called by the user returns - * #CTF_MSG_ITER_STATUS_EOF. This must \em not be - * returned when returning at least one byte of data to the - * caller, i.e. this must be returned when there's - * absolutely nothing left; should the request size be - * larger than what's left in the file, this function must - * return what's left, setting \p buffer_sz to the number of - * remaining bytes, and return - * #CTF_MSG_ITER_MEDIUM_STATUS_EOF on the \em following - * call. - * - #CTF_MSG_ITER_MEDIUM_STATUS_ERROR: A fatal - * error occurred during this operation. In this case, the - * message iterator function called by the user returns - * #CTF_MSG_ITER_STATUS_ERROR. - * - * If #CTF_MSG_ITER_MEDIUM_STATUS_OK is not returned, the - * values of \p buffer_sz and \p buffer_addr are \em ignored by - * the caller. - * - * @param request_sz Requested buffer size (bytes) - * @param buffer_addr Returned buffer address - * @param buffer_sz Returned buffer's size (bytes) - * @param data User data - * @returns Status code (see description above) - */ - enum ctf_msg_iter_medium_status (*request_bytes)(size_t request_sz, uint8_t **buffer_addr, - size_t *buffer_sz, void *data); - - /** - * Repositions the underlying stream's position. - * - * This *optional* method repositions the underlying stream - * to a given absolute position in the medium. - * - * @param offset Offset to use for the given directive - * @param data User data - * @returns One of #ctf_msg_iter_medium_status values - */ - enum ctf_msg_iter_medium_status (*seek)(off_t offset, void *data); - - /** - * Called when the message iterator wishes to inform the medium that it - * is about to start a new packet. - * - * After the iterator has called switch_packet, the following call to - * request_bytes must return the content at the start of the next - * packet. */ - enum ctf_msg_iter_medium_status (*switch_packet)(void *data); - - /** - * Returns a stream instance (weak reference) for the given - * stream class. - * - * This is called after a packet header is read, and the - * corresponding stream class is found by the message - * iterator. - * - * @param stream_class Stream class of the stream to get - * @param stream_id Stream (instance) ID of the stream - * to get (-1ULL if not available) - * @param data User data - * @returns Stream instance (weak reference) or - * \c NULL on error - */ - bt_stream *(*borrow_stream)(bt_stream_class *stream_class, int64_t stream_id, void *data); -}; - -/** - * Creates a CTF message iterator. - * - * Upon successful completion, the reference count of \p trace is - * incremented. - * - * @param trace Trace to read - * @param max_request_sz Maximum buffer size, in bytes, to - * request to - * ctf_msg_iter_medium_ops::request_bytes() - * at a time - * @param medops Medium operations - * @param medops_data User data (passed to medium operations) - * @returns New CTF message iterator on - * success, or \c NULL on error - */ -struct ctf_msg_iter *ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz, - struct ctf_msg_iter_medium_ops medops, void *medops_data, - bt_logging_level log_level, bt_self_component *self_comp, - bt_self_message_iterator *self_msg_iter); - -/** - * Destroys a CTF message iterator, freeing all internal resources. - * - * The registered trace's reference count is decremented. - * - * @param msg_iter CTF message iterator - */ -void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_iter); - -/** - * Returns the next message from a CTF message iterator. - * - * Upon successful completion, #CTF_MSG_ITER_STATUS_OK is - * returned, and the next message is written to \p msg. - * In this case, the caller is responsible for calling - * bt_message_put() on the returned message. - * - * If this function returns #CTF_MSG_ITER_STATUS_AGAIN, the caller - * should make sure that data becomes available to its medium, and - * call this function again, until another status is returned. - * - * @param msg_iter CTF message iterator - * @param message Returned message if the function's - * return value is #CTF_MSG_ITER_STATUS_OK - * @returns One of #ctf_msg_iter_status values - */ -enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it, - const bt_message **message); - -struct ctf_msg_iter_packet_properties -{ - int64_t exp_packet_total_size; - int64_t exp_packet_content_size; - uint64_t stream_class_id; - int64_t data_stream_id; - - struct - { - uint64_t discarded_events; - uint64_t packets; - uint64_t beginning_clock; - uint64_t end_clock; - } snapshots; -}; - -enum ctf_msg_iter_status -ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it, - struct ctf_msg_iter_packet_properties *props); - -enum ctf_msg_iter_status -ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it, - uint64_t *first_event_cs); - -enum ctf_msg_iter_status -ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it, - uint64_t *last_event_cs); - -enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, off_t offset); - -/* - * Resets the iterator so that the next requested medium bytes are - * assumed to be the first bytes of a new stream. Depending on - * ctf_msg_iter_set_emit_stream_beginning_message(), the first message - * which this iterator emits after calling ctf_msg_iter_reset() is of - * type `CTF_MESSAGE_TYPE_STREAM_BEGINNING`. - */ -void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it); - -/* - * Like ctf_msg_iter_reset(), but preserves stream-dependent state. - */ -void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it); - -void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val); - -static inline const char *ctf_msg_iter_medium_status_string(enum ctf_msg_iter_medium_status status) -{ - switch (status) { - case CTF_MSG_ITER_MEDIUM_STATUS_EOF: - return "EOF"; - case CTF_MSG_ITER_MEDIUM_STATUS_AGAIN: - return "AGAIN"; - case CTF_MSG_ITER_MEDIUM_STATUS_ERROR: - return "ERROR"; - case CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR: - return "MEMORY_ERROR"; - case CTF_MSG_ITER_MEDIUM_STATUS_OK: - return "OK"; - } - - bt_common_abort(); -} - -static inline const char *ctf_msg_iter_status_string(enum ctf_msg_iter_status status) -{ - switch (status) { - case CTF_MSG_ITER_STATUS_EOF: - return "EOF"; - case CTF_MSG_ITER_STATUS_AGAIN: - return "AGAIN"; - case CTF_MSG_ITER_STATUS_ERROR: - return "ERROR"; - case CTF_MSG_ITER_STATUS_MEMORY_ERROR: - return "MEMORY_ERROR"; - case CTF_MSG_ITER_STATUS_OK: - return "OK"; - } - - bt_common_abort(); -} - -#endif /* CTF_MSG_ITER_H */ diff --git a/src/plugins/ctf/common/print.hpp b/src/plugins/ctf/common/print.hpp deleted file mode 100644 index 7db4dde9..00000000 --- a/src/plugins/ctf/common/print.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2016 Philippe Proulx - * - * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file. - */ - -#ifndef CTF_BTR_PRINT_H -#define CTF_BTR_PRINT_H - -#include - -#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 */ diff --git a/src/plugins/ctf/common/src/bfcr/bfcr.cpp b/src/plugins/ctf/common/src/bfcr/bfcr.cpp new file mode 100644 index 00000000..9682d30d --- /dev/null +++ b/src/plugins/ctf/common/src/bfcr/bfcr.cpp @@ -0,0 +1,1264 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2016 Philippe Proulx + * + * Babeltrace - CTF binary field class reader (BFCR) + */ + +#include +#include +#include +#include +#include + +#include + +#define BT_COMP_LOG_SELF_COMP (bfcr->self_comp) +#define BT_LOG_OUTPUT_LEVEL (bfcr->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/BFCR" +#include "logging/comp-logging.h" + +#include "common/align.h" +#include "common/assert.h" +#include "common/common.h" +#include "compat/bitfield.h" + +#include "../metadata/tsdl/ctf-meta.hpp" +#include "bfcr.hpp" + +#define DIV8(_x) ((_x) >> 3) +#define BYTES_TO_BITS(_x) ((_x) *8) +#define BITS_TO_BYTES_FLOOR(_x) DIV8(_x) +#define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7) +#define IN_BYTE_OFFSET(_at) ((_at) &7) + +/* A visit stack entry */ +struct stack_entry +{ + /* + * Current class of base field, one of: + * + * * Structure + * * Array + * * Sequence + * * Variant + */ + struct ctf_field_class *base_class; + + /* Length of base field (always 1 for a variant class) */ + int64_t base_len; + + /* Index of next field to read */ + int64_t index; +}; + +/* Visit stack */ +struct stack +{ + struct bt_bfcr *bfcr; + + /* Entries (struct stack_entry) */ + GArray *entries; + + /* Number of active entries */ + size_t size; +}; + +/* Reading states */ +enum bfcr_state +{ + BFCR_STATE_NEXT_FIELD, + BFCR_STATE_ALIGN_BASIC, + BFCR_STATE_ALIGN_COMPOUND, + BFCR_STATE_READ_BASIC_BEGIN, + BFCR_STATE_READ_BASIC_CONTINUE, + BFCR_STATE_DONE, +}; + +/* Binary class reader */ +struct bt_bfcr +{ + bt_logging_level log_level; + + /* Weak */ + bt_self_component *self_comp; + + /* BFCR stack */ + struct stack *stack; + + /* Current basic field class */ + struct ctf_field_class *cur_basic_field_class; + + /* Current state */ + enum bfcr_state state; + + /* + * Last basic field class's byte order. + * + * This is used to detect errors since two contiguous basic + * classes for which the common boundary is not the boundary of + * a byte cannot have different byte orders. + * + * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last + * basic field class was a string class. + */ + enum ctf_byte_order last_bo; + + /* Current byte order (copied to last_bo after a successful read) */ + enum ctf_byte_order cur_bo; + + /* Stitch buffer infos */ + struct + { + /* Stitch buffer */ + uint8_t buf[16]; + + /* Offset, within stitch buffer, of first bit */ + size_t offset; + + /* Length (bits) of data in stitch buffer from offset */ + size_t at; + } stitch; + + /* User buffer infos */ + struct + { + /* Address */ + const uint8_t *addr; + + /* Offset of data from address (bits) */ + size_t offset; + + /* Current position from offset (bits) */ + size_t at; + + /* Offset of offset within whole packet (bits) */ + size_t packet_offset; + + /* Data size in buffer (bits) */ + size_t sz; + + /* Buffer size (bytes) */ + size_t buf_sz; + } buf; + + /* User stuff */ + struct + { + /* Callback functions */ + struct bt_bfcr_cbs cbs; + + /* Private data */ + void *data; + } user; +}; + +static inline const char *bfcr_state_string(enum bfcr_state state) +{ + switch (state) { + case BFCR_STATE_NEXT_FIELD: + return "NEXT_FIELD"; + case BFCR_STATE_ALIGN_BASIC: + return "ALIGN_BASIC"; + case BFCR_STATE_ALIGN_COMPOUND: + return "ALIGN_COMPOUND"; + case BFCR_STATE_READ_BASIC_BEGIN: + return "READ_BASIC_BEGIN"; + case BFCR_STATE_READ_BASIC_CONTINUE: + return "READ_BASIC_CONTINUE"; + case BFCR_STATE_DONE: + return "DONE"; + } + + bt_common_abort(); +} + +static struct stack *stack_new(struct bt_bfcr *bfcr) +{ + struct stack *stack = NULL; + + stack = g_new0(struct stack, 1); + if (!stack) { + BT_COMP_LOGE_STR("Failed to allocate one stack."); + goto error; + } + + stack->bfcr = bfcr; + stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry)); + if (!stack->entries) { + BT_COMP_LOGE_STR("Failed to allocate a GArray."); + goto error; + } + + BT_COMP_LOGD("Created stack: addr=%p", stack); + return stack; + +error: + g_free(stack); + return NULL; +} + +static void stack_destroy(struct stack *stack) +{ + struct bt_bfcr *bfcr; + + if (!stack) { + return; + } + + bfcr = stack->bfcr; + BT_COMP_LOGD("Destroying stack: addr=%p", stack); + + if (stack->entries) { + g_array_free(stack->entries, TRUE); + } + + g_free(stack); +} + +static int stack_push(struct stack *stack, struct ctf_field_class *base_class, size_t base_len) +{ + struct stack_entry *entry; + struct bt_bfcr *bfcr; + + BT_ASSERT_DBG(stack); + BT_ASSERT_DBG(base_class); + bfcr = stack->bfcr; + BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, " + "fc-addr=%p, fc-type=%d, base-length=%zu, " + "stack-size-before=%zu, stack-size-after=%zu", + stack, base_class, base_class->type, base_len, stack->size, stack->size + 1); + + if (stack->entries->len == stack->size) { + g_array_set_size(stack->entries, stack->size + 1); + } + + entry = &bt_g_array_index(stack->entries, struct stack_entry, stack->size); + entry->base_class = base_class; + entry->base_len = base_len; + entry->index = 0; + stack->size++; + return 0; +} + +static inline int64_t get_compound_field_class_length(struct bt_bfcr *bfcr, + struct ctf_field_class *fc) +{ + int64_t length; + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + length = (int64_t) struct_fc->members->len; + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + /* Variant field classes always "contain" a single class */ + length = 1; + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + { + struct ctf_field_class_array *array_fc = ctf_field_class_as_array(fc); + + length = (int64_t) array_fc->length; + break; + } + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + length = bfcr->user.cbs.query.get_sequence_length(fc, bfcr->user.data); + break; + default: + bt_common_abort(); + } + + return length; +} + +static int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class) +{ + int ret; + int64_t length = get_compound_field_class_length(bfcr, base_class); + + if (length < 0) { + BT_COMP_LOGW("Cannot get compound field class's field count: " + "bfcr-addr=%p, fc-addr=%p, fc-type=%d", + bfcr, base_class, base_class->type); + ret = BT_BFCR_STATUS_ERROR; + goto end; + } + + ret = stack_push(bfcr->stack, base_class, (size_t) length); + +end: + return ret; +} + +static inline unsigned int stack_size(struct stack *stack) +{ + BT_ASSERT_DBG(stack); + return stack->size; +} + +static void stack_pop(struct stack *stack) +{ + struct bt_bfcr *bfcr; + + BT_ASSERT_DBG(stack); + BT_ASSERT_DBG(stack_size(stack)); + bfcr = stack->bfcr; + BT_COMP_LOGT("Popping from stack: " + "stack-addr=%p, stack-size-before=%u, stack-size-after=%u", + stack, stack->entries->len, stack->entries->len - 1); + stack->size--; +} + +static inline bool stack_empty(struct stack *stack) +{ + return stack_size(stack) == 0; +} + +static void stack_clear(struct stack *stack) +{ + BT_ASSERT_DBG(stack); + stack->size = 0; +} + +static inline struct stack_entry *stack_top(struct stack *stack) +{ + BT_ASSERT_DBG(stack); + BT_ASSERT_DBG(stack_size(stack)); + return &bt_g_array_index(stack->entries, struct stack_entry, stack->size - 1); +} + +static inline size_t available_bits(struct bt_bfcr *bfcr) +{ + return bfcr->buf.sz - bfcr->buf.at; +} + +static inline void consume_bits(struct bt_bfcr *bfcr, size_t incr) +{ + BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu", bfcr, + bfcr->buf.at, bfcr->buf.at + incr); + bfcr->buf.at += incr; +} + +static inline bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz) +{ + return available_bits(bfcr) >= sz; +} + +static inline bool at_least_one_bit_left(struct bt_bfcr *bfcr) +{ + return has_enough_bits(bfcr, 1); +} + +static inline size_t packet_at(struct bt_bfcr *bfcr) +{ + return bfcr->buf.packet_offset + bfcr->buf.at; +} + +static inline size_t buf_at_from_addr(struct bt_bfcr *bfcr) +{ + /* + * Considering this: + * + * ====== offset ===== (17) + * + * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx + * ^ + * addr (0) ==== at ==== (12) + * + * We want this: + * + * =============================== (29) + */ + return bfcr->buf.offset + bfcr->buf.at; +} + +static void stitch_reset(struct bt_bfcr *bfcr) +{ + bfcr->stitch.offset = 0; + bfcr->stitch.at = 0; +} + +static inline size_t stitch_at_from_addr(struct bt_bfcr *bfcr) +{ + return bfcr->stitch.offset + bfcr->stitch.at; +} + +static void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz) +{ + size_t stitch_byte_at; + size_t buf_byte_at; + size_t nb_bytes; + + if (sz == 0) { + return; + } + + stitch_byte_at = BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr)); + buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr)); + nb_bytes = BITS_TO_BYTES_CEIL(sz); + BT_ASSERT(nb_bytes > 0); + BT_ASSERT(bfcr->buf.addr); + memcpy(&bfcr->stitch.buf[stitch_byte_at], &bfcr->buf.addr[buf_byte_at], nb_bytes); + bfcr->stitch.at += sz; + consume_bits(bfcr, sz); +} + +static void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr) +{ + stitch_append_from_buf(bfcr, available_bits(bfcr)); +} + +static void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr) +{ + stitch_reset(bfcr); + bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr)); + stitch_append_from_remaining_buf(bfcr); +} + +static inline void read_unsigned_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at, + unsigned int field_size, enum ctf_byte_order bo, + uint64_t *v) +{ + switch (bo) { + case CTF_BYTE_ORDER_BIG: + bt_bitfield_read_be(buf, uint8_t, at, field_size, v); + break; + case CTF_BYTE_ORDER_LITTLE: + bt_bitfield_read_le(buf, uint8_t, at, field_size, v); + break; + default: + bt_common_abort(); + } + + BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, " + "bo=%d, val=%" PRIu64, + at, field_size, bo, *v); +} + +static inline void read_signed_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at, + unsigned int field_size, enum ctf_byte_order bo, int64_t *v) +{ + switch (bo) { + case CTF_BYTE_ORDER_BIG: + bt_bitfield_read_be(buf, uint8_t, at, field_size, v); + break; + case CTF_BYTE_ORDER_LITTLE: + bt_bitfield_read_le(buf, uint8_t, at, field_size, v); + break; + default: + bt_common_abort(); + } + + BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, " + "bo=%d, val=%" PRId64, + at, field_size, bo, *v); +} + +typedef enum bt_bfcr_status (*read_basic_and_call_cb_t)(struct bt_bfcr *, const uint8_t *, size_t); + +static inline enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr, + enum ctf_byte_order next_bo) +{ + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + + /* Always valid when at a byte boundary */ + if (packet_at(bfcr) % 8 == 0) { + goto end; + } + + /* Always valid if last byte order is unknown */ + if (bfcr->last_bo == CTF_BYTE_ORDER_UNKNOWN) { + goto end; + } + + /* Always valid if next byte order is unknown */ + if (next_bo == CTF_BYTE_ORDER_UNKNOWN) { + goto end; + } + + /* Make sure last byte order is compatible with the next byte order */ + switch (bfcr->last_bo) { + case CTF_BYTE_ORDER_BIG: + if (next_bo != CTF_BYTE_ORDER_BIG) { + status = BT_BFCR_STATUS_ERROR; + } + break; + case CTF_BYTE_ORDER_LITTLE: + if (next_bo != CTF_BYTE_ORDER_LITTLE) { + status = BT_BFCR_STATUS_ERROR; + } + break; + default: + status = BT_BFCR_STATUS_ERROR; + } + +end: + if (status < 0) { + BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: " + "bfcr-addr=%p, last-bo=%d, next-bo=%d", + bfcr, bfcr->last_bo, next_bo); + } + + return status; +} + +static enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr, const uint8_t *buf, + size_t at) +{ + double dblval; + unsigned int field_size; + enum ctf_byte_order bo; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + ctf_field_class_float *fc = ctf_field_class_as_float(bfcr->cur_basic_field_class); + + BT_ASSERT_DBG(fc); + field_size = fc->base.size; + bo = fc->base.byte_order; + bfcr->cur_bo = bo; + + switch (field_size) { + case 32: + { + uint64_t v; + union + { + uint32_t u; + float f; + } f32; + + read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v); + f32.u = (uint32_t) v; + dblval = (double) f32.f; + break; + } + case 64: + { + union + { + uint64_t u; + double d; + } f64; + + read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &f64.u); + dblval = f64.d; + break; + } + default: + /* Only 32-bit and 64-bit fields are supported currently */ + bt_common_abort(); + } + + BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f", bfcr, at, dblval); + + if (bfcr->user.cbs.classes.floating_point) { + BT_COMP_LOGT("Calling user function (floating point number)."); + status = bfcr->user.cbs.classes.floating_point(dblval, bfcr->cur_basic_field_class, + bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, + bt_bfcr_status_string(status)); + } + } + + return status; +} + +static inline enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr, + const uint8_t *buf, size_t at) +{ + unsigned int field_size; + enum ctf_byte_order bo; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + ctf_field_class_int *fc = ctf_field_class_as_int(bfcr->cur_basic_field_class); + + field_size = fc->base.size; + bo = fc->base.byte_order; + + /* + * Update current byte order now because we could be reading + * the integer value of an enumeration class, and thus we know + * here the actual supporting integer class's byte order. + */ + bfcr->cur_bo = bo; + + if (fc->is_signed) { + int64_t v; + + read_signed_bitfield(bfcr, buf, at, field_size, bo, &v); + + if (bfcr->user.cbs.classes.signed_int) { + BT_COMP_LOGT("Calling user function (signed integer)."); + status = + bfcr->user.cbs.classes.signed_int(v, bfcr->cur_basic_field_class, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: " + "bfcr-addr=%p, status=%s", + bfcr, bt_bfcr_status_string(status)); + } + } + } else { + uint64_t v; + + read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v); + + if (bfcr->user.cbs.classes.unsigned_int) { + BT_COMP_LOGT("Calling user function (unsigned integer)."); + status = bfcr->user.cbs.classes.unsigned_int(v, bfcr->cur_basic_field_class, + bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: " + "bfcr-addr=%p, status=%s", + bfcr, bt_bfcr_status_string(status)); + } + } + } + + return status; +} + +static inline enum bt_bfcr_status +read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr, + read_basic_and_call_cb_t read_basic_and_call_cb) +{ + size_t available; + size_t needed_bits; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class); + + if (!at_least_one_bit_left(bfcr)) { + BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr); + status = BT_BFCR_STATUS_EOF; + goto end; + } + + available = available_bits(bfcr); + needed_bits = fc->size - bfcr->stitch.at; + BT_COMP_LOGT("Continuing basic field decoding: " + "bfcr-addr=%p, field-size=%u, needed-size=%zu, " + "available-size=%zu", + bfcr, fc->size, needed_bits, available); + if (needed_bits <= available) { + /* We have all the bits; append to stitch, then decode */ + stitch_append_from_buf(bfcr, needed_bits); + status = read_basic_and_call_cb(bfcr, bfcr->stitch.buf, bfcr->stitch.offset); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("Cannot read basic field: " + "bfcr-addr=%p, fc-addr=%p, status=%s", + bfcr, bfcr->cur_basic_field_class, bt_bfcr_status_string(status)); + goto end; + } + + if (stack_empty(bfcr->stack)) { + /* Root is a basic class */ + bfcr->state = BFCR_STATE_DONE; + } else { + /* Go to next field */ + stack_top(bfcr->stack)->index++; + bfcr->state = BFCR_STATE_NEXT_FIELD; + bfcr->last_bo = bfcr->cur_bo; + } + goto end; + } + + /* We are here; it means we don't have enough data to decode this */ + BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer."); + stitch_append_from_remaining_buf(bfcr); + status = BT_BFCR_STATUS_EOF; + +end: + return status; +} + +static inline enum bt_bfcr_status +read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr, + read_basic_and_call_cb_t read_basic_and_call_cb) +{ + size_t available; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class); + + if (!at_least_one_bit_left(bfcr)) { + BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr); + status = BT_BFCR_STATUS_EOF; + goto end; + } + + status = validate_contiguous_bo(bfcr, fc->byte_order); + if (status != BT_BFCR_STATUS_OK) { + /* validate_contiguous_bo() logs errors */ + goto end; + } + + available = available_bits(bfcr); + + if (fc->size <= available) { + /* We have all the bits; decode and set now */ + BT_ASSERT_DBG(bfcr->buf.addr); + status = read_basic_and_call_cb(bfcr, bfcr->buf.addr, buf_at_from_addr(bfcr)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("Cannot read basic field: " + "bfcr-addr=%p, fc-addr=%p, status=%s", + bfcr, bfcr->cur_basic_field_class, bt_bfcr_status_string(status)); + goto end; + } + + consume_bits(bfcr, fc->size); + + if (stack_empty(bfcr->stack)) { + /* Root is a basic class */ + bfcr->state = BFCR_STATE_DONE; + } else { + /* Go to next field */ + stack_top(bfcr->stack)->index++; + bfcr->state = BFCR_STATE_NEXT_FIELD; + bfcr->last_bo = bfcr->cur_bo; + } + + goto end; + } + + /* We are here; it means we don't have enough data to decode this */ + BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer."); + stitch_set_from_remaining_buf(bfcr); + bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE; + status = BT_BFCR_STATUS_EOF; + +end: + return status; +} + +static inline enum bt_bfcr_status read_basic_int_class_and_call_begin(struct bt_bfcr *bfcr) +{ + return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb); +} + +static inline enum bt_bfcr_status read_basic_int_class_and_call_continue(struct bt_bfcr *bfcr) +{ + return read_bit_array_class_and_call_continue(bfcr, read_basic_int_and_call_cb); +} + +static inline enum bt_bfcr_status read_basic_float_class_and_call_begin(struct bt_bfcr *bfcr) +{ + return read_bit_array_class_and_call_begin(bfcr, read_basic_float_and_call_cb); +} + +static inline enum bt_bfcr_status read_basic_float_class_and_call_continue(struct bt_bfcr *bfcr) +{ + return read_bit_array_class_and_call_continue(bfcr, read_basic_float_and_call_cb); +} + +static inline enum bt_bfcr_status read_basic_string_class_and_call(struct bt_bfcr *bfcr, bool begin) +{ + size_t buf_at_bytes; + const uint8_t *result; + size_t available_bytes; + const uint8_t *first_chr; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + + if (!at_least_one_bit_left(bfcr)) { + BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr); + status = BT_BFCR_STATUS_EOF; + goto end; + } + + BT_ASSERT_DBG(buf_at_from_addr(bfcr) % 8 == 0); + available_bytes = BITS_TO_BYTES_FLOOR(available_bits(bfcr)); + buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr)); + BT_ASSERT_DBG(bfcr->buf.addr); + first_chr = &bfcr->buf.addr[buf_at_bytes]; + result = (const uint8_t *) memchr(first_chr, '\0', available_bytes); + + if (begin && bfcr->user.cbs.classes.string_begin) { + BT_COMP_LOGT("Calling user function (string, beginning)."); + status = bfcr->user.cbs.classes.string_begin(bfcr->cur_basic_field_class, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, + bt_bfcr_status_string(status)); + goto end; + } + } + + if (!result) { + /* No null character yet */ + if (bfcr->user.cbs.classes.string) { + BT_COMP_LOGT("Calling user function (substring)."); + status = bfcr->user.cbs.classes.string((const char *) first_chr, available_bytes, + bfcr->cur_basic_field_class, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: " + "bfcr-addr=%p, status=%s", + bfcr, bt_bfcr_status_string(status)); + goto end; + } + } + + consume_bits(bfcr, BYTES_TO_BITS(available_bytes)); + bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE; + status = BT_BFCR_STATUS_EOF; + } else { + /* Found the null character */ + size_t result_len = (size_t) (result - first_chr); + + if (bfcr->user.cbs.classes.string && result_len) { + BT_COMP_LOGT("Calling user function (substring)."); + status = bfcr->user.cbs.classes.string((const char *) first_chr, result_len, + bfcr->cur_basic_field_class, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: " + "bfcr-addr=%p, status=%s", + bfcr, bt_bfcr_status_string(status)); + goto end; + } + } + + if (bfcr->user.cbs.classes.string_end) { + BT_COMP_LOGT("Calling user function (string, end)."); + status = + bfcr->user.cbs.classes.string_end(bfcr->cur_basic_field_class, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: " + "bfcr-addr=%p, status=%s", + bfcr, bt_bfcr_status_string(status)); + goto end; + } + } + + consume_bits(bfcr, BYTES_TO_BITS(result_len + 1)); + + if (stack_empty(bfcr->stack)) { + /* Root is a basic class */ + bfcr->state = BFCR_STATE_DONE; + } else { + /* Go to next field */ + stack_top(bfcr->stack)->index++; + bfcr->state = BFCR_STATE_NEXT_FIELD; + bfcr->last_bo = bfcr->cur_bo; + } + } + +end: + return status; +} + +static inline enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr) +{ + enum bt_bfcr_status status; + + BT_ASSERT_DBG(bfcr->cur_basic_field_class); + + switch (bfcr->cur_basic_field_class->type) { + case CTF_FIELD_CLASS_TYPE_INT: + case CTF_FIELD_CLASS_TYPE_ENUM: + status = read_basic_int_class_and_call_begin(bfcr); + break; + case CTF_FIELD_CLASS_TYPE_FLOAT: + status = read_basic_float_class_and_call_begin(bfcr); + break; + case CTF_FIELD_CLASS_TYPE_STRING: + status = read_basic_string_class_and_call(bfcr, true); + break; + default: + bt_common_abort(); + } + + return status; +} + +static inline enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr) +{ + enum bt_bfcr_status status; + + BT_ASSERT_DBG(bfcr->cur_basic_field_class); + + switch (bfcr->cur_basic_field_class->type) { + case CTF_FIELD_CLASS_TYPE_INT: + case CTF_FIELD_CLASS_TYPE_ENUM: + status = read_basic_int_class_and_call_continue(bfcr); + break; + case CTF_FIELD_CLASS_TYPE_FLOAT: + status = read_basic_float_class_and_call_continue(bfcr); + break; + case CTF_FIELD_CLASS_TYPE_STRING: + status = read_basic_string_class_and_call(bfcr, false); + break; + default: + bt_common_abort(); + } + + return status; +} + +static inline size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align) +{ + size_t aligned_packet_at; + + aligned_packet_at = BT_ALIGN(packet_at(bfcr), align); + return aligned_packet_at - packet_at(bfcr); +} + +static inline enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr, + struct ctf_field_class *field_class, + enum bfcr_state next_state) +{ + unsigned int field_alignment; + size_t skip_bits; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + + /* Get field's alignment */ + field_alignment = field_class->alignment; + + /* + * 0 means "undefined" for variants; what we really want is 1 + * (always aligned) + */ + BT_ASSERT_DBG(field_alignment >= 1); + + /* Compute how many bits we need to skip */ + skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment); + + /* Nothing to skip? aligned */ + if (skip_bits == 0) { + bfcr->state = next_state; + goto end; + } + + /* Make sure there's at least one bit left */ + if (!at_least_one_bit_left(bfcr)) { + status = BT_BFCR_STATUS_EOF; + goto end; + } + + /* Consume as many bits as possible in what's left */ + consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits)); + + /* Are we done now? */ + skip_bits = bits_to_skip_to_align_to(bfcr, field_alignment); + if (skip_bits == 0) { + /* Yes: go to next state */ + bfcr->state = next_state; + goto end; + } else { + /* No: need more data */ + BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr); + status = BT_BFCR_STATUS_EOF; + } + +end: + return status; +} + +static inline enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr) +{ + int ret; + struct stack_entry *top; + struct ctf_field_class *next_field_class = NULL; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + + if (stack_empty(bfcr->stack)) { + goto end; + } + + top = stack_top(bfcr->stack); + + /* Are we done with this base class? */ + while (top->index == top->base_len) { + if (bfcr->user.cbs.classes.compound_end) { + BT_COMP_LOGT("Calling user function (compound, end)."); + status = bfcr->user.cbs.classes.compound_end(top->base_class, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, + bt_bfcr_status_string(status)); + goto end; + } + } + + stack_pop(bfcr->stack); + + /* Are we done with the root class? */ + if (stack_empty(bfcr->stack)) { + bfcr->state = BFCR_STATE_DONE; + goto end; + } + + top = stack_top(bfcr->stack); + top->index++; + } + + /* Get next field's class */ + switch (top->base_class->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + next_field_class = ctf_field_class_struct_borrow_member_by_index( + ctf_field_class_as_struct(top->base_class), (uint64_t) top->index) + ->fc; + break; + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(top->base_class); + + next_field_class = array_fc->elem_fc; + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + /* Variant classes are dynamic: the user should know! */ + next_field_class = bfcr->user.cbs.query.borrow_variant_selected_field_class( + top->base_class, bfcr->user.data); + break; + default: + break; + } + + if (!next_field_class) { + BT_COMP_LOGW("Cannot get the field class of the next field: " + "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, " + "index=%" PRId64, + bfcr, top->base_class, top->base_class->type, top->index); + status = BT_BFCR_STATUS_ERROR; + goto end; + } + + if (next_field_class->is_compound) { + if (bfcr->user.cbs.classes.compound_begin) { + BT_COMP_LOGT("Calling user function (compound, begin)."); + status = bfcr->user.cbs.classes.compound_begin(next_field_class, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status)); + if (status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, + bt_bfcr_status_string(status)); + goto end; + } + } + + ret = stack_push_with_len(bfcr, next_field_class); + if (ret) { + /* stack_push_with_len() logs errors */ + status = BT_BFCR_STATUS_ERROR; + goto end; + } + + /* Next state: align a compound class */ + bfcr->state = BFCR_STATE_ALIGN_COMPOUND; + } else { + /* Replace current basic field class */ + BT_COMP_LOGT("Replacing current basic field class: " + "bfcr-addr=%p, cur-basic-fc-addr=%p, " + "next-basic-fc-addr=%p", + bfcr, bfcr->cur_basic_field_class, next_field_class); + bfcr->cur_basic_field_class = next_field_class; + + /* Next state: align a basic class */ + bfcr->state = BFCR_STATE_ALIGN_BASIC; + } + +end: + return status; +} + +static inline enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr) +{ + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + + BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s", bfcr, bfcr_state_string(bfcr->state)); + + switch (bfcr->state) { + case BFCR_STATE_NEXT_FIELD: + status = next_field_state(bfcr); + break; + case BFCR_STATE_ALIGN_BASIC: + status = align_class_state(bfcr, bfcr->cur_basic_field_class, BFCR_STATE_READ_BASIC_BEGIN); + break; + case BFCR_STATE_ALIGN_COMPOUND: + status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class, BFCR_STATE_NEXT_FIELD); + break; + case BFCR_STATE_READ_BASIC_BEGIN: + status = read_basic_begin_state(bfcr); + break; + case BFCR_STATE_READ_BASIC_CONTINUE: + status = read_basic_continue_state(bfcr); + break; + case BFCR_STATE_DONE: + break; + } + + BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s", bfcr, bt_bfcr_status_string(status)); + return status; +} + +struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, bt_logging_level log_level, + bt_self_component *self_comp) +{ + struct bt_bfcr *bfcr; + + BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp, + "Creating binary field class reader (BFCR)."); + bfcr = g_new0(struct bt_bfcr, 1); + if (!bfcr) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, + "Failed to allocate one binary class reader."); + goto end; + } + + bfcr->log_level = log_level; + bfcr->self_comp = self_comp; + bfcr->stack = stack_new(bfcr); + if (!bfcr->stack) { + BT_COMP_LOGE_STR("Cannot create BFCR's stack."); + bt_bfcr_destroy(bfcr); + bfcr = NULL; + goto end; + } + + bfcr->state = BFCR_STATE_NEXT_FIELD; + bfcr->user.cbs = cbs; + bfcr->user.data = data; + BT_COMP_LOGD("Created BFCR: addr=%p", bfcr); + +end: + return bfcr; +} + +void bt_bfcr_destroy(struct bt_bfcr *bfcr) +{ + if (bfcr->stack) { + stack_destroy(bfcr->stack); + } + + BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr); + g_free(bfcr); +} + +static void reset(struct bt_bfcr *bfcr) +{ + BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr); + stack_clear(bfcr->stack); + stitch_reset(bfcr); + bfcr->buf.addr = NULL; + bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN; +} + +static void update_packet_offset(struct bt_bfcr *bfcr) +{ + BT_COMP_LOGT("Updating packet offset for next call: " + "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu", + bfcr, bfcr->buf.packet_offset, bfcr->buf.packet_offset + bfcr->buf.at); + bfcr->buf.packet_offset += bfcr->buf.at; +} + +size_t bt_bfcr_start(struct bt_bfcr *bfcr, struct ctf_field_class *cls, const uint8_t *buf, + size_t offset, size_t packet_offset, size_t sz, enum bt_bfcr_status *status) +{ + BT_ASSERT_DBG(bfcr); + BT_ASSERT_DBG(BYTES_TO_BITS(sz) >= offset); + reset(bfcr); + bfcr->buf.addr = buf; + bfcr->buf.offset = offset; + bfcr->buf.at = 0; + bfcr->buf.packet_offset = packet_offset; + bfcr->buf.buf_sz = sz; + bfcr->buf.sz = BYTES_TO_BITS(sz) - offset; + *status = BT_BFCR_STATUS_OK; + + BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, " + "buf-addr=%p, buf-size=%zu, offset=%zu, " + "packet-offset=%zu", + bfcr, cls, buf, sz, offset, packet_offset); + + /* Set root class */ + if (cls->is_compound) { + /* Compound class: push on visit stack */ + int stack_ret; + + if (bfcr->user.cbs.classes.compound_begin) { + BT_COMP_LOGT("Calling user function (compound, begin)."); + *status = bfcr->user.cbs.classes.compound_begin(cls, bfcr->user.data); + BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(*status)); + if (*status != BT_BFCR_STATUS_OK) { + BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr, + bt_bfcr_status_string(*status)); + goto end; + } + } + + stack_ret = stack_push_with_len(bfcr, cls); + if (stack_ret) { + /* stack_push_with_len() logs errors */ + *status = BT_BFCR_STATUS_ERROR; + goto end; + } + + bfcr->state = BFCR_STATE_ALIGN_COMPOUND; + } else { + /* Basic class: set as current basic class */ + bfcr->cur_basic_field_class = cls; + bfcr->state = BFCR_STATE_ALIGN_BASIC; + } + + /* Run the machine! */ + BT_COMP_LOGT_STR("Running the state machine."); + + while (true) { + *status = handle_state(bfcr); + if (*status != BT_BFCR_STATUS_OK || bfcr->state == BFCR_STATE_DONE) { + break; + } + } + + /* Update packet offset for next time */ + update_packet_offset(bfcr); + +end: + return bfcr->buf.at; +} + +size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz, + enum bt_bfcr_status *status) +{ + BT_ASSERT_DBG(bfcr); + BT_ASSERT_DBG(buf); + BT_ASSERT_DBG(sz > 0); + bfcr->buf.addr = buf; + bfcr->buf.offset = 0; + bfcr->buf.at = 0; + bfcr->buf.buf_sz = sz; + bfcr->buf.sz = BYTES_TO_BITS(sz); + *status = BT_BFCR_STATUS_OK; + + BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu", bfcr, buf, sz); + + /* Continue running the machine */ + BT_COMP_LOGT_STR("Running the state machine."); + + while (true) { + *status = handle_state(bfcr); + if (*status != BT_BFCR_STATUS_OK || bfcr->state == BFCR_STATE_DONE) { + break; + } + } + + /* Update packet offset for next time */ + update_packet_offset(bfcr); + return bfcr->buf.at; +} + +void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb) +{ + BT_ASSERT_DBG(bfcr); + BT_ASSERT_DBG(cb); + bfcr->user.cbs.classes.unsigned_int = cb; +} diff --git a/src/plugins/ctf/common/src/bfcr/bfcr.hpp b/src/plugins/ctf/common/src/bfcr/bfcr.hpp new file mode 100644 index 00000000..9e3a2dc1 --- /dev/null +++ b/src/plugins/ctf/common/src/bfcr/bfcr.hpp @@ -0,0 +1,346 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2016 Philippe Proulx + * + * Babeltrace - CTF binary field class reader (BFCR) + */ + +#ifndef CTF_BFCR_H +#define CTF_BFCR_H + +#include +#include + +#include + +#include "../metadata/tsdl/ctf-meta.hpp" + +/** + * @file bfcr.h + * + * Event-driven CTF binary field class reader (BFCR). + * + * This is a common, internal API used by CTF source plugins. It allows + * a binary CTF IR field class to be decoded from user-provided buffers. + * As the class is decoded (and, possibly, its nested classes), + * registered user callback functions are called. + * + * This API is only concerned with reading one CTF class at a time from + * one or more buffer of bytes. It does not know CTF dynamic scopes, + * events, or streams. Sequence lengths and selected variant classes are + * requested to the user when needed. + */ + +/** + * Binary class reader API status codes. + */ +enum bt_bfcr_status +{ + /** Out of memory. */ + BT_BFCR_STATUS_ENOMEM = -5, + /** + * The binary stream reader reached the end of the user-provided + * buffer, but data is still needed to finish decoding the + * requested class. + * + * The user needs to call bt_bfcr_continue() as long as + * #BT_BFCR_STATUS_EOF is returned to complete the decoding + * process of a given class. + */ + BT_BFCR_STATUS_EOF = 1, + + /** Invalid argument. */ + BT_BFCR_STATUS_INVAL = -3, + + /** General error. */ + BT_BFCR_STATUS_ERROR = -1, + + /** Everything okay. */ + BT_BFCR_STATUS_OK = 0, +}; + +typedef enum bt_bfcr_status (*bt_bfcr_unsigned_int_cb_func)(uint64_t, struct ctf_field_class *, + void *); + +/* + * Field class reader user callback functions. + */ +struct bt_bfcr_cbs +{ + /** + * Field class callback functions. + * + * This CTF binary class reader is event-driven. The following + * functions are called during the decoding process, either when + * a compound class begins/ends, or when a basic class is + * completely decoded (along with its value). + * + * Each function also receives the CTF field class associated + * with the call, and user data (registered to the class reader + * calling them). + * + * Actual trace IR fields are \em not created here; this would + * be the responsibility of a class reader's user (the provider + * of those callback functions). + * + * All the class callback functions return one of the following + * values: + * + * - #BT_BFCR_STATUS_OK: Everything is okay; + * continue the decoding process. + * - #BT_BFCR_STATUS_ERROR: General error (reported + * to class reader's user). + * + * Any member of this structure may be set to \c NULL, should + * a specific message be not needed. + */ + struct + { + /** + * Called when a signed integer class is completely + * decoded. This could also be the supporting signed + * integer class of an enumeration class (\p class will + * indicate this). + * + * @param value Signed integer value + * @param class Integer or enumeration class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + enum bt_bfcr_status (*signed_int)(int64_t value, struct ctf_field_class *cls, void *data); + + /** + * Called when an unsigned integer class is completely + * decoded. This could also be the supporting signed + * integer class of an enumeration class (\p class will + * indicate this). + * + * @param value Unsigned integer value + * @param class Integer or enumeration class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + bt_bfcr_unsigned_int_cb_func unsigned_int; + + /** + * Called when a floating point number class is + * completely decoded. + * + * @param value Floating point number value + * @param class Floating point number class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + enum bt_bfcr_status (*floating_point)(double value, struct ctf_field_class *cls, + void *data); + + /** + * Called when a string class begins. + * + * All the following user callback function calls will + * be made to bt_bfcr_cbs::classes::string(), each of + * them providing one substring of the complete string + * class's value. + * + * @param class Beginning string class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + enum bt_bfcr_status (*string_begin)(struct ctf_field_class *cls, void *data); + + /** + * Called when a string class's substring is decoded + * (between a call to bt_bfcr_cbs::classes::string_begin() + * and a call to bt_bfcr_cbs::classes::string_end()). + * + * @param value String value (\em not null-terminated) + * @param len String value length + * @param class String class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + enum bt_bfcr_status (*string)(const char *value, size_t len, struct ctf_field_class *cls, + void *data); + + /** + * Called when a string class ends. + * + * @param class Ending string class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + enum bt_bfcr_status (*string_end)(struct ctf_field_class *cls, void *data); + + /** + * Called when a compound class begins. + * + * All the following class callback function calls will + * signal sequential elements of this compound class, + * until the next corresponding + * bt_bfcr_cbs::classes::compound_end() is called. + * + * If \p class is a variant class, then only one class + * callback function call will follow before the call to + * bt_bfcr_cbs::classes::compound_end(). This single + * call indicates the selected class of this variant + * class. + * + * @param class Beginning compound class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + enum bt_bfcr_status (*compound_begin)(struct ctf_field_class *cls, void *data); + + /** + * Called when a compound class ends. + * + * @param class Ending compound class + * @param data User data + * @returns #BT_BFCR_STATUS_OK or + * #BT_BFCR_STATUS_ERROR + */ + enum bt_bfcr_status (*compound_end)(struct ctf_field_class *cls, void *data); + } classes; + + /** + * Query callback functions are used when the class reader needs + * dynamic information, i.e. a sequence class's current length + * or a variant class's current selected class. + * + * Both functions need to be set unless it is known that no + * sequences or variants will have to be decoded. + */ + struct + { + /** + * Called to query the current length of a given sequence + * class. + * + * @param class Sequence class + * @param data User data + * @returns Sequence length or + * #BT_BFCR_STATUS_ERROR on error + */ + int64_t (*get_sequence_length)(struct ctf_field_class *cls, void *data); + + /** + * Called to query the current selected class of a given + * variant class. + * + * @param class Variant class + * @param data User data + * @returns Current selected class (owned by + * this) or \c NULL on error + */ + struct ctf_field_class *(*borrow_variant_selected_field_class)(struct ctf_field_class *cls, + void *data); + } query; +}; + +/** + * Creates a CTF binary class reader. + * + * @param cbs User callback functions + * @param data User data (passed to user callback functions) + * @returns New binary class reader on success, or \c NULL on error + */ +struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, bt_logging_level log_level, + bt_self_component *self_comp); + +/** + * Destroys a CTF binary class reader, freeing all internal resources. + * + * @param bfcr Binary class reader + */ +void bt_bfcr_destroy(struct bt_bfcr *bfcr); + +/** + * Decodes a given CTF class from a buffer of bytes. + * + * The number of \em bits consumed by this function is returned. + * + * The \p status output parameter is where a status is written, amongst + * the following: + * + * - #BT_BFCR_STATUS_OK: Decoding is done. + * - #BT_BFCR_STATUS_EOF: The end of the buffer was reached, + * but more data is needed to finish the decoding process of the + * requested class. The user needs to call bt_bfcr_continue() + * as long as #BT_BFCR_STATUS_EOF is returned to complete the + * decoding process of the original class. + * - #BT_BFCR_STATUS_INVAL: Invalid argument. + * - #BT_BFCR_STATUS_ERROR: General error. + * + * Calling this function resets the class reader's internal state. If + * #BT_BFCR_STATUS_EOF is returned, bt_bfcr_continue() needs to + * be called next, \em not bt_bfcr_decode(). + * + * @param bfcr Binary class reader + * @param class Field class to decode + * @param buf Buffer + * @param offset Offset of first bit from \p buf (bits) + * @param packet_offset Offset of \p offset within the CTF + * binary packet containing \p class (bits) + * @param sz Size of buffer in bytes (from \p buf) + * @param status Returned status (see description above) + * @returns Number of consumed bits + */ +size_t bt_bfcr_start(struct bt_bfcr *bfcr, struct ctf_field_class *cls, const uint8_t *buf, + size_t offset, size_t packet_offset, size_t sz, enum bt_bfcr_status *status); + +/** + * Continues the decoding process a given CTF class. + * + * The number of bits consumed by this function is returned. + * + * The \p status output parameter is where a status is placed, amongst + * the following: + * + * - #BT_BFCR_STATUS_OK: decoding is done. + * - #BT_BFCR_STATUS_EOF: the end of the buffer was reached, + * but more data is needed to finish the decoding process of the + * requested class. The user needs to call bt_bfcr_continue() + * as long as #BT_BFCR_STATUS_EOF is returned to complete the + * decoding process of the original class. + * - #BT_BFCR_STATUS_INVAL: invalid argument. + * - #BT_BFCR_STATUS_ERROR: general error. + * + * @param bfcr Binary class reader + * @param buf Buffer + * @param sz Size of buffer in bytes (from \p offset) + * @param status Returned status (see description above) + * @returns Number of consumed bits + */ +size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz, + enum bt_bfcr_status *status); + +void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb); + +static inline const char *bt_bfcr_status_string(enum bt_bfcr_status status) +{ + switch (status) { + case BT_BFCR_STATUS_ENOMEM: + return "ENOMEM"; + case BT_BFCR_STATUS_EOF: + return "EOF"; + case BT_BFCR_STATUS_INVAL: + return "INVAL"; + case BT_BFCR_STATUS_ERROR: + return "ERROR"; + case BT_BFCR_STATUS_OK: + return "OK"; + } + + bt_common_abort(); +} + +#endif /* CTF_BFCR_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ast.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ast.hpp new file mode 100644 index 00000000..a6a7e9f7 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ast.hpp @@ -0,0 +1,458 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2011-2012 Mathieu Desnoyers + */ + +#ifndef _CTF_AST_H +#define _CTF_AST_H + +#include +#include +#include + +#include + +#include "common/assert.h" +#include "common/list.h" + +#include "ctf-meta.hpp" +#include "decoder.hpp" + +// the parameter name (of the reentrant 'yyparse' function) +// data is a pointer to a 'SParserParam' structure +//#define YYPARSE_PARAM scanner + +struct ctf_node; +struct ctf_parser; +struct ctf_visitor_generate_ir; + +#define EINCOMPLETE 1000 + +#define FOREACH_CTF_NODES(F) \ + F(NODE_UNKNOWN) \ + F(NODE_ROOT) \ + F(NODE_ERROR) \ + F(NODE_EVENT) \ + F(NODE_STREAM) \ + F(NODE_ENV) \ + F(NODE_TRACE) \ + F(NODE_CLOCK) \ + F(NODE_CALLSITE) \ + F(NODE_CTF_EXPRESSION) \ + F(NODE_UNARY_EXPRESSION) \ + F(NODE_TYPEDEF) \ + F(NODE_TYPEALIAS_TARGET) \ + F(NODE_TYPEALIAS_ALIAS) \ + F(NODE_TYPEALIAS) \ + F(NODE_TYPE_SPECIFIER) \ + F(NODE_TYPE_SPECIFIER_LIST) \ + F(NODE_POINTER) \ + F(NODE_TYPE_DECLARATOR) \ + F(NODE_FLOATING_POINT) \ + F(NODE_INTEGER) \ + F(NODE_STRING) \ + F(NODE_ENUMERATOR) \ + F(NODE_ENUM) \ + F(NODE_STRUCT_OR_VARIANT_DECLARATION) \ + F(NODE_VARIANT) \ + F(NODE_STRUCT) + +enum node_type +{ +#define ENTRY(S) S, + FOREACH_CTF_NODES(ENTRY) +#undef ENTRY +}; + +enum ctf_unary +{ + UNARY_UNKNOWN = 0, + UNARY_STRING, + UNARY_SIGNED_CONSTANT, + UNARY_UNSIGNED_CONSTANT, + UNARY_SBRAC, +}; + +enum ctf_unary_link +{ + UNARY_LINK_UNKNOWN = 0, + UNARY_DOTLINK, + UNARY_ARROWLINK, + UNARY_DOTDOTDOT, +}; + +enum ctf_typedec +{ + TYPEDEC_UNKNOWN = 0, + TYPEDEC_ID, /* identifier */ + TYPEDEC_NESTED, /* (), array or sequence */ +}; + +enum ctf_typespec +{ + TYPESPEC_UNKNOWN = 0, + TYPESPEC_VOID, + TYPESPEC_CHAR, + TYPESPEC_SHORT, + TYPESPEC_INT, + TYPESPEC_LONG, + TYPESPEC_FLOAT, + TYPESPEC_DOUBLE, + TYPESPEC_SIGNED, + TYPESPEC_UNSIGNED, + TYPESPEC_BOOL, + TYPESPEC_COMPLEX, + TYPESPEC_IMAGINARY, + TYPESPEC_CONST, + TYPESPEC_ID_TYPE, + TYPESPEC_FLOATING_POINT, + TYPESPEC_INTEGER, + TYPESPEC_STRING, + TYPESPEC_STRUCT, + TYPESPEC_VARIANT, + TYPESPEC_ENUM, +}; + +struct ctf_node +{ + /* + * Parent node is only set on demand by specific visitor. + */ + struct ctf_node *parent; + struct bt_list_head siblings; + struct bt_list_head tmp_head; + unsigned int lineno; + /* + * We mark nodes visited in the generate-ir phase (last + * phase). We only mark the 1-depth level nodes as visited + * (never the root node, and not their sub-nodes). This allows + * skipping already visited nodes when doing incremental + * metadata append. + */ + int visited; + + enum node_type type; + union + { + struct + { + } unknown; + struct + { + /* + * Children nodes are ctf_expression, field_class_def, + * field_class_alias and field_class_specifier_list. + */ + struct bt_list_head declaration_list; + struct bt_list_head trace; + struct bt_list_head env; + struct bt_list_head stream; + struct bt_list_head event; + struct bt_list_head clock; + struct bt_list_head callsite; + } root; + struct + { + /* + * Children nodes are ctf_expression, field_class_def, + * field_class_alias and field_class_specifier_list. + */ + struct bt_list_head declaration_list; + } event; + struct + { + /* + * Children nodes are ctf_expression, field_class_def, + * field_class_alias and field_class_specifier_list. + */ + struct bt_list_head declaration_list; + } stream; + struct + { + /* + * Children nodes are ctf_expression, field_class_def, + * field_class_alias and field_class_specifier_list. + */ + struct bt_list_head declaration_list; + } env; + struct + { + /* + * Children nodes are ctf_expression, field_class_def, + * field_class_alias and field_class_specifier_list. + */ + struct bt_list_head declaration_list; + } trace; + struct + { + /* + * Children nodes are ctf_expression, field_class_def, + * field_class_alias and field_class_specifier_list. + */ + struct bt_list_head declaration_list; + } clock; + struct + { + /* + * Children nodes are ctf_expression, field_class_def, + * field_class_alias and field_class_specifier_list. + */ + struct bt_list_head declaration_list; + } callsite; + struct + { + struct bt_list_head left; /* Should be string */ + struct bt_list_head right; /* Unary exp. or type */ + } ctf_expression; + struct + { + ctf_unary type; + union + { + /* + * string for identifier, id_type, keywords, + * string literals and character constants. + */ + char *string; + int64_t signed_constant; + uint64_t unsigned_constant; + struct ctf_node *sbrac_exp; + } u; + ctf_unary_link link; + } unary_expression; + struct + { + struct ctf_node *field_class_specifier_list; + struct bt_list_head field_class_declarators; + } field_class_def; + /* new type is "alias", existing type "target" */ + struct + { + struct ctf_node *field_class_specifier_list; + struct bt_list_head field_class_declarators; + } field_class_alias_target; + struct + { + struct ctf_node *field_class_specifier_list; + struct bt_list_head field_class_declarators; + } field_class_alias_name; + struct + { + struct ctf_node *target; + struct ctf_node *alias; + } field_class_alias; + struct + { + ctf_typespec type; + /* For struct, variant and enum */ + struct ctf_node *node; + const char *id_type; + } field_class_specifier; + struct + { + /* list of field_class_specifier */ + struct bt_list_head head; + } field_class_specifier_list; + struct + { + unsigned int const_qualifier; + } pointer; + struct + { + struct bt_list_head pointers; + ctf_typedec type; + union + { + char *id; + struct + { + /* typedec has no pointer list */ + struct ctf_node *field_class_declarator; + /* + * unary expression (value) or + * field_class_specifier_list. + */ + struct bt_list_head length; + /* for abstract type declarator */ + unsigned int abstract_array; + } nested; + } u; + struct ctf_node *bitfield_len; + } field_class_declarator; + struct + { + /* Children nodes are ctf_expression. */ + struct bt_list_head expressions; + } floating_point; + struct + { + /* Children nodes are ctf_expression. */ + struct bt_list_head expressions; + } integer; + struct + { + /* Children nodes are ctf_expression. */ + struct bt_list_head expressions; + } string; + struct + { + char *id; + /* + * Range list or single value node. Contains unary + * expressions. + */ + struct bt_list_head values; + } enumerator; + struct + { + char *enum_id; + /* + * Either NULL, or points to unary expression or + * field_class_specifier_list. + */ + struct ctf_node *container_field_class; + struct bt_list_head enumerator_list; + int has_body; + } _enum; + struct + { + struct ctf_node *field_class_specifier_list; + struct bt_list_head field_class_declarators; + } struct_or_variant_declaration; + struct + { + char *name; + char *choice; + /* + * list of field_class_def, field_class_alias and + * declarations + */ + struct bt_list_head declaration_list; + int has_body; + } variant; + struct + { + char *name; + /* + * list of field_class_def, field_class_alias and + * declarations + */ + struct bt_list_head declaration_list; + int has_body; + struct bt_list_head min_align; /* align() attribute */ + } _struct; + } u; +}; + +struct ctf_ast +{ + struct ctf_node root; +}; + +const char *node_type(struct ctf_node *node); + +struct meta_log_config; + +struct ctf_visitor_generate_ir * +ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *config); + +void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor); + +bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *visitor); + +struct ctf_trace_class * +ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *visitor); + +int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor, + struct ctf_node *node); + +int ctf_visitor_semantic_check(int depth, struct ctf_node *node, struct meta_log_config *log_cfg); + +int ctf_visitor_parent_links(int depth, struct ctf_node *node, struct meta_log_config *log_cfg); + +static inline char *ctf_ast_concatenate_unary_strings(struct bt_list_head *head) +{ + int i = 0; + GString *str; + struct ctf_node *node; + + str = g_string_new(NULL); + BT_ASSERT(str); + + bt_list_for_each_entry (node, head, siblings) { + char *src_string; + + if (node->type != NODE_UNARY_EXPRESSION || node->u.unary_expression.type != UNARY_STRING || + !((node->u.unary_expression.link != UNARY_LINK_UNKNOWN) ^ (i == 0))) { + goto error; + } + + switch (node->u.unary_expression.link) { + case UNARY_DOTLINK: + g_string_append(str, "."); + break; + case UNARY_ARROWLINK: + g_string_append(str, "->"); + break; + case UNARY_DOTDOTDOT: + g_string_append(str, "..."); + break; + default: + break; + } + + src_string = node->u.unary_expression.u.string; + g_string_append(str, src_string); + i++; + } + + /* Destroys the container, returns the underlying string */ + return g_string_free(str, FALSE); + +error: + /* This always returns NULL */ + return g_string_free(str, TRUE); +} + +#ifndef BT_COMP_LOG_CUR_LVL +# define BT_AST_LOG_LEVEL_UNUSED_ATTR __attribute__((unused)) +#else +# define BT_AST_LOG_LEVEL_UNUSED_ATTR +#endif + +static inline int ctf_ast_get_unary_uuid(struct bt_list_head *head, bt_uuid_t uuid, + int log_level BT_AST_LOG_LEVEL_UNUSED_ATTR, + bt_self_component *self_comp BT_AST_LOG_LEVEL_UNUSED_ATTR) +{ + int i = 0; + int ret = 0; + struct ctf_node *node; + + bt_list_for_each_entry (node, head, siblings) { + int uexpr_type = node->u.unary_expression.type; + int uexpr_link = node->u.unary_expression.link; + const char *src_string; + + if (node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_STRING || + uexpr_link != UNARY_LINK_UNKNOWN || i != 0) { + ret = -EINVAL; + goto end; + } + + src_string = node->u.unary_expression.u.string; + ret = bt_uuid_from_str(src_string, uuid); + if (ret) { +#ifdef BT_COMP_LOG_CUR_LVL + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, + "Cannot parse UUID: uuid=\"%s\"", src_string); +#endif + goto end; + } + } + +end: + return ret; +} + +#endif /* _CTF_AST_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp new file mode 100644 index 00000000..eb252def --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp @@ -0,0 +1,50 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Philippe Proulx + */ + +#include + +#include "common/assert.h" + +#include "ctf-meta-configure-ir-trace.hpp" +#include "plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp" + +int ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, bt_trace *ir_trace) +{ + int ret = 0; + uint64_t i; + + BT_ASSERT(tc); + BT_ASSERT(ir_trace); + + if (tc->is_uuid_set) { + bt_trace_set_uuid(ir_trace, tc->uuid); + } + + for (i = 0; i < tc->env_entries->len; i++) { + struct ctf_trace_class_env_entry *env_entry = + ctf_trace_class_borrow_env_entry_by_index(tc, i); + + switch (env_entry->type) { + case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT: + ret = bt_trace_set_environment_entry_integer(ir_trace, env_entry->name->str, + env_entry->value.i); + break; + case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR: + ret = bt_trace_set_environment_entry_string(ir_trace, env_entry->name->str, + env_entry->value.str->str); + break; + default: + bt_common_abort(); + } + + if (ret) { + goto end; + } + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp new file mode 100644 index 00000000..f94f19e6 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Philippe Proulx + */ + +#ifndef _CTF_META_CONFIGURE_IR_TRACE_H +#define _CTF_META_CONFIGURE_IR_TRACE_H + +#include + +int ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, bt_trace *ir_trace); + +#endif /* _CTF_META_CONFIGURE_IR_TRACE_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp new file mode 100644 index 00000000..1f7ffe57 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp @@ -0,0 +1,1261 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2018 Philippe Proulx + * Copyright 2015 Jérémie Galarneau + */ + +#include +#include +#include +#include + +#include + +#define BT_COMP_LOG_SELF_COMP (ctx->self_comp) +#define BT_COMP_LOG_SELF_COMP_CLASS (ctx->self_comp_class) +#define BT_LOG_OUTPUT_LEVEL ((enum bt_log_level) ctx->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/RESOLVE" +#include "logging.hpp" +#include "logging/comp-logging.h" + +#include "common/assert.h" +#include "common/common.h" + +#include "ctf-meta-visitors.hpp" + +using field_class_stack_t = GPtrArray; + +/* + * A stack frame. + * + * `fc` contains a compound field class (structure, variant, array, + * or sequence) and `index` indicates the index of the field class in + * the upper frame (-1 for array and sequence field classes). `name` + * indicates the name of the field class in the upper frame (empty + * string for array and sequence field classes). + */ +struct field_class_stack_frame +{ + struct ctf_field_class *fc; + int64_t index; +}; + +/* + * The current context of the resolving engine. + */ +struct resolve_context +{ + bt_logging_level log_level; + + /* Weak, exactly one of these must be set */ + bt_self_component *self_comp; + bt_self_component_class *self_comp_class; + + struct ctf_trace_class *tc; + struct ctf_stream_class *sc; + struct ctf_event_class *ec; + + struct + { + struct ctf_field_class *packet_header; + struct ctf_field_class *packet_context; + struct ctf_field_class *event_header; + struct ctf_field_class *event_common_context; + struct ctf_field_class *event_spec_context; + struct ctf_field_class *event_payload; + } scopes; + + /* Root scope being visited */ + enum ctf_scope root_scope; + field_class_stack_t *field_class_stack; + struct ctf_field_class *cur_fc; +}; + +/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */ +static const char * const absolute_path_prefixes[] = { + /* CTF_SCOPE_PACKET_HEADER */ "trace.packet.header.", + /* CTF_SCOPE_PACKET_CONTEXT */ "stream.packet.context.", + /* CTF_SCOPE_EVENT_HEADER */ "stream.event.header.", + /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ "stream.event.context.", + /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ "event.context.", + /* CTF_SCOPE_EVENT_PAYLOAD */ "event.fields.", +}; + +/* Number of path tokens used for the absolute prefixes */ +static const uint64_t absolute_path_prefix_ptoken_counts[] = { + /* CTF_SCOPE_PACKET_HEADER */ 3, + /* CTF_SCOPE_PACKET_CONTEXT */ 3, + /* CTF_SCOPE_EVENT_HEADER */ 3, + /* CTF_SCOPE_EVENT_COMMON_CONTEXT */ 3, + /* CTF_SCOPE_EVENT_SPECIFIC_CONTEXT */ 2, + /* CTF_SCOPE_EVENT_PAYLOAD */ 2, +}; + +static void destroy_field_class_stack_frame(struct field_class_stack_frame *frame) +{ + if (!frame) { + return; + } + + g_free(frame); +} + +/* + * Creates a class stack. + */ +static field_class_stack_t *field_class_stack_create(void) +{ + return g_ptr_array_new_with_free_func((GDestroyNotify) destroy_field_class_stack_frame); +} + +/* + * Destroys a class stack. + */ +static void field_class_stack_destroy(field_class_stack_t *stack) +{ + if (stack) { + g_ptr_array_free(stack, TRUE); + } +} + +/* + * Pushes a field class onto a class stack. + */ +static int field_class_stack_push(field_class_stack_t *stack, struct ctf_field_class *fc, + struct resolve_context *ctx) +{ + int ret = 0; + struct field_class_stack_frame *frame = NULL; + + if (!stack || !fc) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid parameter: stack or field class is `NULL`."); + ret = -1; + goto end; + } + + frame = g_new0(struct field_class_stack_frame, 1); + if (!frame) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one field class stack frame."); + ret = -1; + goto end; + } + + BT_COMP_LOGD("Pushing field class on context's stack: " + "fc-addr=%p, stack-size-before=%u", + fc, stack->len); + frame->fc = fc; + g_ptr_array_add(stack, frame); + +end: + return ret; +} + +/* + * Checks whether or not `stack` is empty. + */ +static bool field_class_stack_empty(field_class_stack_t *stack) +{ + return stack->len == 0; +} + +/* + * Returns the number of frames in `stack`. + */ +static size_t field_class_stack_size(field_class_stack_t *stack) +{ + return stack->len; +} + +/* + * Returns the top frame of `stack`. + */ +static struct field_class_stack_frame *field_class_stack_peek(field_class_stack_t *stack) +{ + BT_ASSERT(stack); + BT_ASSERT(!field_class_stack_empty(stack)); + + return (field_class_stack_frame *) g_ptr_array_index(stack, stack->len - 1); +} + +/* + * Returns the frame at index `index` in `stack`. + */ +static struct field_class_stack_frame *field_class_stack_at(field_class_stack_t *stack, + size_t index) +{ + BT_ASSERT(stack); + BT_ASSERT(index < stack->len); + + return (field_class_stack_frame *) g_ptr_array_index(stack, index); +} + +/* + * Removes the top frame of `stack`. + */ +static void field_class_stack_pop(field_class_stack_t *stack, struct resolve_context *ctx) +{ + if (!field_class_stack_empty(stack)) { + /* + * This will call the frame's destructor and free it, as + * well as put its contained field class. + */ + BT_COMP_LOGD("Popping context's stack: stack-size-before=%u", stack->len); + g_ptr_array_set_size(stack, stack->len - 1); + } +} + +/* + * Returns the scope field class of `scope` in the context `ctx`. + */ +static struct ctf_field_class *borrow_class_from_ctx(struct resolve_context *ctx, + enum ctf_scope scope) +{ + switch (scope) { + case CTF_SCOPE_PACKET_HEADER: + return ctx->scopes.packet_header; + case CTF_SCOPE_PACKET_CONTEXT: + return ctx->scopes.packet_context; + case CTF_SCOPE_EVENT_HEADER: + return ctx->scopes.event_header; + case CTF_SCOPE_EVENT_COMMON_CONTEXT: + return ctx->scopes.event_common_context; + case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: + return ctx->scopes.event_spec_context; + case CTF_SCOPE_EVENT_PAYLOAD: + return ctx->scopes.event_payload; + default: + bt_common_abort(); + } + + return NULL; +} + +/* + * Returns the CTF scope from a path string. May return -1 if the path + * is found to be relative. + */ +static enum ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr, + struct resolve_context *ctx) +{ + enum ctf_scope scope; + enum ctf_scope ret = CTF_SCOPE_PACKET_UNKNOWN; + const size_t prefixes_count = sizeof(absolute_path_prefixes) / sizeof(*absolute_path_prefixes); + + for (scope = CTF_SCOPE_PACKET_HEADER; scope < CTF_SCOPE_PACKET_HEADER + prefixes_count; + scope = (ctf_scope) (scope + 1)) { + /* + * Check if path string starts with a known absolute + * path prefix. + * + * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES. + */ + if (strncmp(pathstr, absolute_path_prefixes[scope], + strlen(absolute_path_prefixes[scope]))) { + /* Prefix does not match: try the next one */ + BT_COMP_LOGD("Prefix does not match: trying the next one: " + "path=\"%s\", path-prefix=\"%s\", scope=%s", + pathstr, absolute_path_prefixes[scope], ctf_scope_string(scope)); + continue; + } + + /* Found it! */ + ret = scope; + BT_COMP_LOGD("Found root scope from absolute path: " + "path=\"%s\", scope=%s", + pathstr, ctf_scope_string(scope)); + goto end; + } + +end: + return ret; +} + +/* + * Destroys a path token. + */ +static void ptokens_destroy_func(gpointer ptoken, gpointer) +{ + g_string_free((GString *) ptoken, TRUE); +} + +/* + * Destroys a path token list. + */ +static void ptokens_destroy(GList *ptokens) +{ + if (!ptokens) { + return; + } + + g_list_foreach(ptokens, ptokens_destroy_func, NULL); + g_list_free(ptokens); +} + +/* + * Returns the string contained in a path token. + */ +static const char *ptoken_get_string(GList *ptoken) +{ + GString *tokenstr = (GString *) ptoken->data; + + return tokenstr->str; +} + +/* + * Converts a path string to a path token list, that is, splits the + * individual words of a path string into a list of individual + * strings. + */ +static GList *pathstr_to_ptokens(const char *pathstr, struct resolve_context *ctx) +{ + const char *at = pathstr; + const char *last = at; + GList *ptokens = NULL; + + for (;;) { + if (*at == '.' || *at == '\0') { + GString *tokenstr; + + if (at == last) { + /* Error: empty token */ + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Empty path token: path=\"%s\", pos=%u", + pathstr, (unsigned int) (at - pathstr)); + goto error; + } + + tokenstr = g_string_new(NULL); + g_string_append_len(tokenstr, last, at - last); + ptokens = g_list_append(ptokens, tokenstr); + last = at + 1; + } + + if (*at == '\0') { + break; + } + + at++; + } + + return ptokens; + +error: + ptokens_destroy(ptokens); + return NULL; +} + +/* + * Converts a path token list to a field path object. The path token + * list is relative from `fc`. The index of the source looking for its + * target within `fc` is indicated by `src_index`. This can be + * `INT64_MAX` if the source is contained in `fc`. + * + * `field_path` is an output parameter owned by the caller that must be + * filled here. + */ +static int ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path, + struct ctf_field_class *fc, int64_t src_index, + struct resolve_context *ctx) +{ + int ret = 0; + GList *cur_ptoken = ptokens; + bool first_level_done = false; + + /* Locate target */ + while (cur_ptoken) { + int64_t child_index; + struct ctf_field_class *child_fc; + const char *ft_name = ptoken_get_string(cur_ptoken); + + BT_COMP_LOGD("Current path token: token=\"%s\"", ft_name); + + /* Find to which index corresponds the current path token */ + if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { + child_index = -1; + } else { + child_index = + ctf_field_class_compound_get_field_class_index_from_orig_name(fc, ft_name); + if (child_index < 0) { + /* + * Error: field name does not exist or + * wrong current class. + */ + BT_COMP_LOGD("Cannot get index of field class: " + "field-name=\"%s\", " + "src-index=%" PRId64 ", " + "child-index=%" PRId64 ", " + "first-level-done=%d", + ft_name, src_index, child_index, first_level_done); + ret = -1; + goto end; + } else if (child_index > src_index && !first_level_done) { + BT_COMP_LOGD("Child field class is located after source field class: " + "field-name=\"%s\", " + "src-index=%" PRId64 ", " + "child-index=%" PRId64 ", " + "first-level-done=%d", + ft_name, src_index, child_index, first_level_done); + ret = -1; + goto end; + } + + /* Next path token */ + cur_ptoken = g_list_next(cur_ptoken); + first_level_done = true; + } + + /* Create new field path entry */ + ctf_field_path_append_index(field_path, child_index); + + /* Get child field class */ + child_fc = ctf_field_class_compound_borrow_field_class_by_index(fc, child_index); + BT_ASSERT(child_fc); + + /* Move child class to current class */ + fc = child_fc; + } + +end: + return ret; +} + +/* + * Converts a known absolute path token list to a field path object + * within the resolving context `ctx`. + * + * `field_path` is an output parameter owned by the caller that must be + * filled here. + */ +static int absolute_ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int ret = 0; + GList *cur_ptoken; + struct ctf_field_class *fc; + + /* + * Make sure we're not referring to a scope within a translated + * object. + */ + switch (field_path->root) { + case CTF_SCOPE_PACKET_HEADER: + if (ctx->tc->is_translated) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Trace class is already translated: " + "root-scope=%s", + ctf_scope_string(field_path->root)); + ret = -1; + goto end; + } + + break; + case CTF_SCOPE_PACKET_CONTEXT: + case CTF_SCOPE_EVENT_HEADER: + case CTF_SCOPE_EVENT_COMMON_CONTEXT: + if (!ctx->sc) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current stream class: " + "root-scope=%s", + ctf_scope_string(field_path->root)); + ret = -1; + goto end; + } + + if (ctx->sc->is_translated) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class is already translated: " + "root-scope=%s", + ctf_scope_string(field_path->root)); + ret = -1; + goto end; + } + + break; + case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: + case CTF_SCOPE_EVENT_PAYLOAD: + if (!ctx->ec) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current event class: " + "root-scope=%s", + ctf_scope_string(field_path->root)); + ret = -1; + goto end; + } + + if (ctx->ec->is_translated) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Event class is already translated: " + "root-scope=%s", + ctf_scope_string(field_path->root)); + ret = -1; + goto end; + } + + break; + + default: + bt_common_abort(); + } + + /* Skip absolute path tokens */ + cur_ptoken = g_list_nth(ptokens, absolute_path_prefix_ptoken_counts[field_path->root]); + + /* Start with root class */ + fc = borrow_class_from_ctx(ctx, field_path->root); + if (!fc) { + /* Error: root class is not available */ + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: " + "root-scope=%s", + ctf_scope_string(field_path->root)); + ret = -1; + goto end; + } + + /* Locate target */ + ret = ptokens_to_field_path(cur_ptoken, field_path, fc, INT64_MAX, ctx); + +end: + return ret; +} + +/* + * Converts a known relative path token list to a field path object + * within the resolving context `ctx`. + * + * `field_path` is an output parameter owned by the caller that must be + * filled here. + */ +static int relative_ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int ret = 0; + int64_t parent_pos_in_stack; + struct ctf_field_path tail_field_path; + + ctf_field_path_init(&tail_field_path); + parent_pos_in_stack = field_class_stack_size(ctx->field_class_stack) - 1; + + while (parent_pos_in_stack >= 0) { + struct ctf_field_class *parent_class = + field_class_stack_at(ctx->field_class_stack, parent_pos_in_stack)->fc; + int64_t cur_index = + field_class_stack_at(ctx->field_class_stack, parent_pos_in_stack)->index; + + BT_COMP_LOGD("Locating target field class from current parent field class: " + "parent-pos=%" PRId64 ", parent-fc-addr=%p, " + "cur-index=%" PRId64, + parent_pos_in_stack, parent_class, cur_index); + + /* Locate target from current parent class */ + ret = ptokens_to_field_path(ptokens, &tail_field_path, parent_class, cur_index, ctx); + if (ret) { + /* Not found... yet */ + BT_COMP_LOGD_STR("Not found at this point."); + ctf_field_path_clear(&tail_field_path); + } else { + /* Found: stitch tail field path to head field path */ + uint64_t i = 0; + size_t tail_field_path_len = tail_field_path.path->len; + + while (BT_TRUE) { + struct ctf_field_class *cur_class = + field_class_stack_at(ctx->field_class_stack, i)->fc; + int64_t index = field_class_stack_at(ctx->field_class_stack, i)->index; + + if (cur_class == parent_class) { + break; + } + + ctf_field_path_append_index(field_path, index); + i++; + } + + for (i = 0; i < tail_field_path_len; i++) { + int64_t index = ctf_field_path_borrow_index_by_index(&tail_field_path, i); + + ctf_field_path_append_index(field_path, (int64_t) index); + } + break; + } + + parent_pos_in_stack--; + } + + if (parent_pos_in_stack < 0) { + /* Not found */ + ret = -1; + } + + ctf_field_path_fini(&tail_field_path); + return ret; +} + +/* + * Converts a path string to a field path object within the resolving + * context `ctx`. + */ +static int pathstr_to_field_path(const char *pathstr, struct ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int ret = 0; + enum ctf_scope root_scope; + GList *ptokens = NULL; + + /* Convert path string to path tokens */ + ptokens = pathstr_to_ptokens(pathstr, ctx); + if (!ptokens) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot convert path string to path tokens: " + "path=\"%s\"", + pathstr); + ret = -1; + goto end; + } + + /* Absolute or relative path? */ + root_scope = get_root_scope_from_absolute_pathstr(pathstr, ctx); + + if (root_scope == CTF_SCOPE_PACKET_UNKNOWN) { + /* Relative path: start with current root scope */ + field_path->root = ctx->root_scope; + BT_COMP_LOGD("Detected relative path: starting with current root scope: " + "scope=%s", + ctf_scope_string(field_path->root)); + ret = relative_ptokens_to_field_path(ptokens, field_path, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot get relative field path of path string: " + "path=\"%s\", start-scope=%s, end-scope=%s", + pathstr, ctf_scope_string(ctx->root_scope), ctf_scope_string(field_path->root)); + goto end; + } + } else { + /* Absolute path: use found root scope */ + field_path->root = root_scope; + BT_COMP_LOGD("Detected absolute path: using root scope: " + "scope=%s", + ctf_scope_string(field_path->root)); + ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot get absolute field path of path string: " + "path=\"%s\", root-scope=%s", + pathstr, ctf_scope_string(root_scope)); + goto end; + } + } + + if (BT_LOG_ON_TRACE && ret == 0) { + GString *field_path_pretty = ctf_field_path_string(field_path); + const char *field_path_pretty_str = field_path_pretty ? field_path_pretty->str : "(null)"; + + BT_COMP_LOGD("Found field path: path=\"%s\", field-path=\"%s\"", pathstr, + field_path_pretty_str); + + if (field_path_pretty) { + g_string_free(field_path_pretty, TRUE); + } + } + +end: + ptokens_destroy(ptokens); + return ret; +} + +/* + * Retrieves a field class by following the field path `field_path` in + * the resolving context `ctx`. + */ +static struct ctf_field_class *field_path_to_field_class(struct ctf_field_path *field_path, + struct resolve_context *ctx) +{ + uint64_t i; + struct ctf_field_class *fc; + + /* Start with root class */ + fc = borrow_class_from_ctx(ctx, field_path->root); + if (!fc) { + /* Error: root class is not available */ + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Root field class is not available: root-scope=%s", + ctf_scope_string(field_path->root)); + goto end; + } + + /* Locate target */ + for (i = 0; i < field_path->path->len; i++) { + struct ctf_field_class *child_fc; + int64_t child_index = ctf_field_path_borrow_index_by_index(field_path, i); + + /* Get child field class */ + child_fc = ctf_field_class_compound_borrow_field_class_by_index(fc, child_index); + BT_ASSERT(child_fc); + + /* Move child class to current class */ + fc = child_fc; + } + +end: + return fc; +} + +/* + * Fills the equivalent field path object of the context class stack. + */ +static void get_ctx_stack_field_path(struct resolve_context *ctx, struct ctf_field_path *field_path) +{ + uint64_t i; + + BT_ASSERT(field_path); + field_path->root = ctx->root_scope; + ctf_field_path_clear(field_path); + + for (i = 0; i < field_class_stack_size(ctx->field_class_stack); i++) { + struct field_class_stack_frame *frame = field_class_stack_at(ctx->field_class_stack, i); + + ctf_field_path_append_index(field_path, frame->index); + } +} + +/* + * Returns the index of the lowest common ancestor of two field path + * objects having the same root scope. + */ +static int64_t get_field_paths_lca_index(struct ctf_field_path *field_path1, + struct ctf_field_path *field_path2, + struct resolve_context *ctx) +{ + int64_t lca_index = 0; + uint64_t field_path1_len, field_path2_len; + + if (BT_LOG_ON_TRACE) { + GString *field_path1_pretty = ctf_field_path_string(field_path1); + GString *field_path2_pretty = ctf_field_path_string(field_path2); + const char *field_path1_pretty_str = + field_path1_pretty ? field_path1_pretty->str : "(null)"; + const char *field_path2_pretty_str = + field_path2_pretty ? field_path2_pretty->str : "(null)"; + + BT_COMP_LOGD("Finding lowest common ancestor (LCA) between two field paths: " + "field-path-1=\"%s\", field-path-2=\"%s\"", + field_path1_pretty_str, field_path2_pretty_str); + + if (field_path1_pretty) { + g_string_free(field_path1_pretty, TRUE); + } + + if (field_path2_pretty) { + g_string_free(field_path2_pretty, TRUE); + } + } + + /* + * Start from both roots and find the first mismatch. + */ + BT_ASSERT(field_path1->root == field_path2->root); + field_path1_len = field_path1->path->len; + field_path2_len = field_path2->path->len; + + while (true) { + int64_t target_index, ctx_index; + + if (lca_index == (int64_t) field_path2_len || lca_index == (int64_t) field_path1_len) { + /* + * This means that both field paths never split. + * This is invalid because the target cannot be + * an ancestor of the source. + */ + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Source field class is an ancestor of target field class or vice versa: " + "lca-index=%" PRId64 ", " + "field-path-1-len=%" PRIu64 ", " + "field-path-2-len=%" PRIu64, + lca_index, field_path1_len, field_path2_len); + lca_index = -1; + break; + } + + target_index = ctf_field_path_borrow_index_by_index(field_path1, lca_index); + ctx_index = ctf_field_path_borrow_index_by_index(field_path2, lca_index); + + if (target_index != ctx_index) { + /* LCA index is the previous */ + break; + } + + lca_index++; + } + + BT_COMP_LOGD("Found LCA: lca-index=%" PRId64, lca_index); + return lca_index; +} + +/* + * Validates a target field path. + */ +static int validate_target_field_path(struct ctf_field_path *target_field_path, + struct ctf_field_class *target_fc, + struct resolve_context *ctx) +{ + int ret = 0; + struct ctf_field_path ctx_field_path; + uint64_t target_field_path_len = target_field_path->path->len; + int64_t lca_index; + + /* Get context field path */ + ctf_field_path_init(&ctx_field_path); + get_ctx_stack_field_path(ctx, &ctx_field_path); + + /* + * Make sure the target is not a root. + */ + if (target_field_path_len == 0) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Target field path's length is 0 (targeting the root)."); + ret = -1; + goto end; + } + + /* + * Make sure the root of the target field path is not located + * after the context field path's root. + */ + if (target_field_path->root > ctx_field_path.root) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Target field class is located after source field class: " + "target-root=%s, source-root=%s", + ctf_scope_string(target_field_path->root), ctf_scope_string(ctx_field_path.root)); + ret = -1; + goto end; + } + + if (target_field_path->root == ctx_field_path.root) { + int64_t target_index, ctx_index; + + /* + * Find the index of the lowest common ancestor of both field + * paths. + */ + lca_index = get_field_paths_lca_index(target_field_path, &ctx_field_path, ctx); + if (lca_index < 0) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get least common ancestor."); + ret = -1; + goto end; + } + + /* + * Make sure the target field path is located before the + * context field path. + */ + target_index = + ctf_field_path_borrow_index_by_index(target_field_path, (uint64_t) lca_index); + ctx_index = ctf_field_path_borrow_index_by_index(&ctx_field_path, (uint64_t) lca_index); + + if (target_index >= ctx_index) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Target field class's index is greater than or equal to source field class's index in LCA: " + "lca-index=%" PRId64 ", " + "target-index=%" PRId64 ", " + "source-index=%" PRId64, + lca_index, target_index, ctx_index); + ret = -1; + goto end; + } + } + + /* + * Make sure the target class has the right class and properties. + */ + switch (ctx->cur_fc->type) { + case CTF_FIELD_CLASS_TYPE_VARIANT: + if (target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Variant field class's tag field class is not an enumeration field class: " + "tag-fc-addr=%p, tag-fc-id=%d", + target_fc, target_fc->type); + ret = -1; + goto end; + } + break; + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + if (target_fc->type != CTF_FIELD_CLASS_TYPE_INT && + target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Sequence field class's length field class is not an unsigned integer field class: " + "length-fc-addr=%p, length-fc-id=%d", + target_fc, target_fc->type); + ret = -1; + goto end; + } + + ctf_field_class_int *int_fc = ctf_field_class_as_int(target_fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Sequence field class's length field class is not an unsigned integer field class: " + "length-fc-addr=%p, length-fc-id=%d", + target_fc, target_fc->type); + ret = -1; + goto end; + } + break; + } + default: + bt_common_abort(); + } + +end: + ctf_field_path_fini(&ctx_field_path); + return ret; +} + +/* + * Resolves a variant or sequence field class `fc`. + */ +static int resolve_sequence_or_variant_field_class(struct ctf_field_class *fc, + struct resolve_context *ctx) +{ + int ret = 0; + const char *pathstr; + struct ctf_field_path target_field_path; + struct ctf_field_class *target_fc = NULL; + GString *target_field_path_pretty = NULL; + const char *target_field_path_pretty_str; + + ctf_field_path_init(&target_field_path); + + /* Get path string */ + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); + pathstr = seq_fc->length_ref->str; + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + pathstr = var_fc->tag_ref->str; + break; + } + default: + bt_common_abort(); + } + + if (!pathstr) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get path string."); + ret = -1; + goto end; + } + + /* Get target field path out of path string */ + ret = pathstr_to_field_path(pathstr, &target_field_path, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field path for path string: " + "path=\"%s\"", + pathstr); + goto end; + } + + target_field_path_pretty = ctf_field_path_string(&target_field_path); + target_field_path_pretty_str = target_field_path_pretty ? target_field_path_pretty->str : NULL; + + /* Get target field class */ + target_fc = field_path_to_field_class(&target_field_path, ctx); + if (!target_fc) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot get target field class for path string: " + "path=\"%s\", target-field-path=\"%s\"", + pathstr, target_field_path_pretty_str); + ret = -1; + goto end; + } + + ret = validate_target_field_path(&target_field_path, target_fc, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid target field path for path string: " + "path=\"%s\", target-field-path=\"%s\"", + pathstr, target_field_path_pretty_str); + goto end; + } + + /* Set target field path and target field class */ + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); + + ctf_field_path_copy_content(&seq_fc->length_path, &target_field_path); + seq_fc->length_fc = ctf_field_class_as_int(target_fc); + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + ctf_field_path_copy_content(&var_fc->tag_path, &target_field_path); + ctf_field_class_variant_set_tag_field_class(var_fc, ctf_field_class_as_enum(target_fc)); + break; + } + default: + bt_common_abort(); + } + +end: + if (target_field_path_pretty) { + g_string_free(target_field_path_pretty, TRUE); + } + + ctf_field_path_fini(&target_field_path); + return ret; +} + +/* + * Resolves a field class `fc`. + */ +static int resolve_field_class(struct ctf_field_class *fc, struct resolve_context *ctx) +{ + int ret = 0; + + if (!fc) { + /* Field class is not available; still valid */ + goto end; + } + + ctx->cur_fc = fc; + + /* Resolve sequence/variant field class */ + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + case CTF_FIELD_CLASS_TYPE_VARIANT: + ret = resolve_sequence_or_variant_field_class(fc, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot resolve sequence field class's length or variant field class's tag: " + "ret=%d, fc-addr=%p", + ret, fc); + goto end; + } + + break; + default: + break; + } + + /* Recurse into compound classes */ + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + case CTF_FIELD_CLASS_TYPE_VARIANT: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + case CTF_FIELD_CLASS_TYPE_ARRAY: + { + uint64_t i; + uint64_t field_count = ctf_field_class_compound_get_field_class_count(fc); + + ret = field_class_stack_push(ctx->field_class_stack, fc, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot push field class on context's stack: " + "fc-addr=%p", + fc); + goto end; + } + + for (i = 0; i < field_count; i++) { + struct ctf_field_class *child_fc = + ctf_field_class_compound_borrow_field_class_by_index(fc, i); + + BT_ASSERT(child_fc); + + if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || + fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { + field_class_stack_peek(ctx->field_class_stack)->index = -1; + } else { + field_class_stack_peek(ctx->field_class_stack)->index = (int64_t) i; + } + + BT_COMP_LOGD("Resolving field class's child field class: " + "parent-fc-addr=%p, child-fc-addr=%p, " + "index=%" PRIu64 ", count=%" PRIu64, + fc, child_fc, i, field_count); + ret = resolve_field_class(child_fc, ctx); + if (ret) { + goto end; + } + } + + field_class_stack_pop(ctx->field_class_stack, ctx); + break; + } + default: + break; + } + +end: + return ret; +} + +/* + * Resolves the root field class corresponding to the scope `root_scope`. + */ +static int resolve_root_class(enum ctf_scope root_scope, struct resolve_context *ctx) +{ + int ret; + + BT_ASSERT(field_class_stack_size(ctx->field_class_stack) == 0); + ctx->root_scope = root_scope; + ret = resolve_field_class(borrow_class_from_ctx(ctx, root_scope), ctx); + ctx->root_scope = CTF_SCOPE_PACKET_UNKNOWN; + return ret; +} + +static int resolve_event_class_field_classes(struct resolve_context *ctx, + struct ctf_event_class *ec) +{ + int ret = 0; + + BT_ASSERT(!ctx->scopes.event_spec_context); + BT_ASSERT(!ctx->scopes.event_payload); + + if (ec->is_translated) { + goto end; + } + + ctx->ec = ec; + ctx->scopes.event_spec_context = ec->spec_context_fc; + ret = resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot resolve event specific context field class: " + "ret=%d", + ret); + goto end; + } + + ctx->scopes.event_payload = ec->payload_fc; + ret = resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event payload field class: " + "ret=%d", + ret); + goto end; + } + +end: + ctx->scopes.event_spec_context = NULL; + ctx->scopes.event_payload = NULL; + ctx->ec = NULL; + return ret; +} + +static int resolve_stream_class_field_classes(struct resolve_context *ctx, + struct ctf_stream_class *sc) +{ + int ret = 0; + uint64_t i; + + BT_ASSERT(!ctx->scopes.packet_context); + BT_ASSERT(!ctx->scopes.event_header); + BT_ASSERT(!ctx->scopes.event_common_context); + ctx->sc = sc; + + if (!sc->is_translated) { + ctx->scopes.packet_context = sc->packet_context_fc; + ret = resolve_root_class(CTF_SCOPE_PACKET_CONTEXT, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet context field class: " + "ret=%d", + ret); + goto end; + } + + ctx->scopes.event_header = sc->event_header_fc; + ret = resolve_root_class(CTF_SCOPE_EVENT_HEADER, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event header field class: " + "ret=%d", + ret); + goto end; + } + + ctx->scopes.event_common_context = sc->event_common_context_fc; + ret = resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot resolve event common context field class: " + "ret=%d", + ret); + goto end; + } + } + + ctx->scopes.packet_context = sc->packet_context_fc; + ctx->scopes.event_header = sc->event_header_fc; + ctx->scopes.event_common_context = sc->event_common_context_fc; + + for (i = 0; i < sc->event_classes->len; i++) { + ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[i]; + + ret = resolve_event_class_field_classes(ctx, ec); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve event class's field classes: " + "ec-id=%" PRIu64 ", ec-name=\"%s\"", + ec->id, ec->name->str); + goto end; + } + } + +end: + ctx->scopes.packet_context = NULL; + ctx->scopes.event_header = NULL; + ctx->scopes.event_common_context = NULL; + ctx->sc = NULL; + return ret; +} + +int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc, + struct meta_log_config *log_cfg) +{ + int ret = 0; + uint64_t i; + + resolve_context local_ctx {}; + local_ctx.log_level = log_cfg->log_level; + local_ctx.self_comp = log_cfg->self_comp; + local_ctx.self_comp_class = log_cfg->self_comp_class; + local_ctx.tc = tc; + local_ctx.scopes.packet_header = tc->packet_header_fc; + local_ctx.root_scope = CTF_SCOPE_PACKET_HEADER; + + struct resolve_context *ctx = &local_ctx; + + /* Initialize class stack */ + ctx->field_class_stack = field_class_stack_create(); + if (!ctx->field_class_stack) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create field class stack."); + ret = -1; + goto end; + } + + if (!tc->is_translated) { + ctx->scopes.packet_header = tc->packet_header_fc; + ret = resolve_root_class(CTF_SCOPE_PACKET_HEADER, ctx); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve packet header field class: " + "ret=%d", + ret); + goto end; + } + } + + ctx->scopes.packet_header = tc->packet_header_fc; + + for (i = 0; i < tc->stream_classes->len; i++) { + ctf_stream_class *sc = (ctf_stream_class *) tc->stream_classes->pdata[i]; + + ret = resolve_stream_class_field_classes(ctx, sc); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot resolve stream class's field classes: " + "sc-id=%" PRIu64, + sc->id); + goto end; + } + } + +end: + field_class_stack_destroy(ctx->field_class_stack); + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp new file mode 100644 index 00000000..e3ecfd07 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp @@ -0,0 +1,651 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#include + +#include "common/assert.h" + +#include "ctf-meta-visitors.hpp" + +struct ctx +{ + bt_self_component *self_comp; + bt_trace_class *ir_tc; + bt_stream_class *ir_sc; + struct ctf_trace_class *tc; + struct ctf_stream_class *sc; + struct ctf_event_class *ec; + enum ctf_scope scope; +}; + +static inline bt_field_class *ctf_field_class_to_ir(struct ctx *ctx, struct ctf_field_class *fc); + +static inline void ctf_field_class_int_set_props(struct ctf_field_class_int *fc, + bt_field_class *ir_fc) +{ + bt_field_class_integer_set_field_value_range(ir_fc, fc->base.size); + bt_field_class_integer_set_preferred_display_base(ir_fc, fc->disp_base); +} + +static inline bt_field_class *ctf_field_class_int_to_ir(struct ctx *ctx, + struct ctf_field_class_int *fc) +{ + bt_field_class *ir_fc; + + if (fc->is_signed) { + ir_fc = bt_field_class_integer_signed_create(ctx->ir_tc); + } else { + ir_fc = bt_field_class_integer_unsigned_create(ctx->ir_tc); + } + + BT_ASSERT(ir_fc); + ctf_field_class_int_set_props(fc, ir_fc); + return ir_fc; +} + +static inline bt_field_class *ctf_field_class_enum_to_ir(struct ctx *ctx, + struct ctf_field_class_enum *fc) +{ + int ret; + bt_field_class *ir_fc; + uint64_t i; + + if (fc->base.is_signed) { + ir_fc = bt_field_class_enumeration_signed_create(ctx->ir_tc); + } else { + ir_fc = bt_field_class_enumeration_unsigned_create(ctx->ir_tc); + } + + BT_ASSERT(ir_fc); + ctf_field_class_int_set_props(&fc->base, ir_fc); + + for (i = 0; i < fc->mappings->len; i++) { + struct ctf_field_class_enum_mapping *mapping = + ctf_field_class_enum_borrow_mapping_by_index(fc, i); + bt_integer_range_set_signed *range_set_signed = NULL; + bt_integer_range_set_unsigned *range_set_unsigned = NULL; + uint64_t range_i; + + if (fc->base.is_signed) { + range_set_signed = bt_integer_range_set_signed_create(); + BT_ASSERT(range_set_signed); + } else { + range_set_unsigned = bt_integer_range_set_unsigned_create(); + BT_ASSERT(range_set_unsigned); + } + + for (range_i = 0; range_i < mapping->ranges->len; range_i++) { + struct ctf_range *range = + ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i); + + if (fc->base.is_signed) { + ret = bt_integer_range_set_signed_add_range(range_set_signed, range->lower.i, + range->upper.i); + } else { + ret = bt_integer_range_set_unsigned_add_range(range_set_unsigned, range->lower.u, + range->upper.u); + } + + BT_ASSERT(ret == 0); + } + + if (fc->base.is_signed) { + ret = bt_field_class_enumeration_signed_add_mapping(ir_fc, mapping->label->str, + range_set_signed); + BT_INTEGER_RANGE_SET_SIGNED_PUT_REF_AND_RESET(range_set_signed); + } else { + ret = bt_field_class_enumeration_unsigned_add_mapping(ir_fc, mapping->label->str, + range_set_unsigned); + BT_INTEGER_RANGE_SET_UNSIGNED_PUT_REF_AND_RESET(range_set_unsigned); + } + + BT_ASSERT(ret == 0); + } + + return ir_fc; +} + +static inline bt_field_class *ctf_field_class_float_to_ir(struct ctx *ctx, + struct ctf_field_class_float *fc) +{ + bt_field_class *ir_fc; + + if (fc->base.size == 32) { + ir_fc = bt_field_class_real_single_precision_create(ctx->ir_tc); + } else { + ir_fc = bt_field_class_real_double_precision_create(ctx->ir_tc); + } + BT_ASSERT(ir_fc); + + return ir_fc; +} + +static inline bt_field_class *ctf_field_class_string_to_ir(struct ctx *ctx, + struct ctf_field_class_string *) +{ + bt_field_class *ir_fc = bt_field_class_string_create(ctx->ir_tc); + + BT_ASSERT(ir_fc); + return ir_fc; +} + +static inline void translate_struct_field_class_members(struct ctx *ctx, + struct ctf_field_class_struct *fc, + bt_field_class *ir_fc, bool, + struct ctf_field_class_struct *) +{ + uint64_t i; + int ret; + + for (i = 0; i < fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(fc, i); + bt_field_class *member_ir_fc; + const char *name = named_fc->name->str; + + if (!named_fc->fc->in_ir) { + continue; + } + + member_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc); + BT_ASSERT(member_ir_fc); + ret = bt_field_class_structure_append_member(ir_fc, name, member_ir_fc); + BT_ASSERT(ret == 0); + bt_field_class_put_ref(member_ir_fc); + } +} + +static inline bt_field_class *ctf_field_class_struct_to_ir(struct ctx *ctx, + struct ctf_field_class_struct *fc) +{ + bt_field_class *ir_fc = bt_field_class_structure_create(ctx->ir_tc); + + BT_ASSERT(ir_fc); + translate_struct_field_class_members(ctx, fc, ir_fc, false, NULL); + return ir_fc; +} + +static inline bt_field_class *borrow_ir_fc_from_field_path(struct ctx *ctx, + struct ctf_field_path *field_path) +{ + bt_field_class *ir_fc = NULL; + struct ctf_field_class *fc = + ctf_field_path_borrow_field_class(field_path, ctx->tc, ctx->sc, ctx->ec); + + BT_ASSERT(fc); + + if (fc->in_ir) { + ir_fc = fc->ir_fc; + } + + return ir_fc; +} + +static inline const bt_field_class_enumeration_mapping * +find_ir_enum_field_class_mapping_by_label(const bt_field_class *fc, const char *label, + bool is_signed) +{ + const bt_field_class_enumeration_mapping *mapping = NULL; + uint64_t i; + + for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) { + const bt_field_class_enumeration_mapping *this_mapping; + const bt_field_class_enumeration_signed_mapping *signed_this_mapping = NULL; + const bt_field_class_enumeration_unsigned_mapping *unsigned_this_mapping = NULL; + + if (is_signed) { + signed_this_mapping = + bt_field_class_enumeration_signed_borrow_mapping_by_index_const(fc, i); + BT_ASSERT(signed_this_mapping); + this_mapping = + bt_field_class_enumeration_signed_mapping_as_mapping_const(signed_this_mapping); + } else { + unsigned_this_mapping = + bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(fc, i); + BT_ASSERT(unsigned_this_mapping); + this_mapping = + bt_field_class_enumeration_unsigned_mapping_as_mapping_const(unsigned_this_mapping); + } + + BT_ASSERT(this_mapping); + + if (strcmp(bt_field_class_enumeration_mapping_get_label(this_mapping), label) == 0) { + mapping = this_mapping; + goto end; + } + } + +end: + return mapping; +} + +static inline bt_field_class *ctf_field_class_variant_to_ir(struct ctx *ctx, + struct ctf_field_class_variant *fc) +{ + int ret; + bt_field_class *ir_fc; + uint64_t i; + bt_field_class *ir_tag_fc = NULL; + + if (fc->tag_path.root != CTF_SCOPE_PACKET_HEADER && + fc->tag_path.root != CTF_SCOPE_EVENT_HEADER) { + ir_tag_fc = borrow_ir_fc_from_field_path(ctx, &fc->tag_path); + BT_ASSERT(ir_tag_fc); + } + + ir_fc = bt_field_class_variant_create(ctx->ir_tc, ir_tag_fc); + BT_ASSERT(ir_fc); + + for (i = 0; i < fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(fc, i); + bt_field_class *option_ir_fc; + + BT_ASSERT(named_fc->fc->in_ir); + option_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc); + BT_ASSERT(option_ir_fc); + + if (ir_tag_fc) { + /* + * At this point the trace IR selector + * (enumeration) field class already exists if + * the variant is tagged (`ir_tag_fc`). This one + * already contains range sets for its mappings, + * so we just reuse the same, finding them by + * matching a variant field class's option's + * _original_ name (with a leading underscore, + * possibly) with a selector field class's + * mapping name. + */ + if (fc->tag_fc->base.is_signed) { + const bt_field_class_enumeration_signed_mapping *mapping = + (bt_field_class_enumeration_signed_mapping *) + find_ir_enum_field_class_mapping_by_label(ir_tag_fc, + named_fc->orig_name->str, true); + const bt_integer_range_set_signed *range_set; + + BT_ASSERT(mapping); + range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(mapping); + BT_ASSERT(range_set); + ret = bt_field_class_variant_with_selector_field_integer_signed_append_option( + ir_fc, named_fc->name->str, option_ir_fc, range_set); + } else { + const bt_field_class_enumeration_unsigned_mapping *mapping = + (bt_field_class_enumeration_unsigned_mapping *) + find_ir_enum_field_class_mapping_by_label(ir_tag_fc, + named_fc->orig_name->str, false); + const bt_integer_range_set_unsigned *range_set; + + BT_ASSERT(mapping); + range_set = + bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(mapping); + BT_ASSERT(range_set); + ret = bt_field_class_variant_with_selector_field_integer_unsigned_append_option( + ir_fc, named_fc->name->str, option_ir_fc, range_set); + } + } else { + ret = bt_field_class_variant_without_selector_append_option(ir_fc, named_fc->name->str, + option_ir_fc); + } + + BT_ASSERT(ret == 0); + bt_field_class_put_ref(option_ir_fc); + } + + return ir_fc; +} + +static inline bt_field_class *ctf_field_class_array_to_ir(struct ctx *ctx, + struct ctf_field_class_array *fc) +{ + bt_field_class *ir_fc; + bt_field_class *elem_ir_fc; + + if (fc->base.is_text) { + ir_fc = bt_field_class_string_create(ctx->ir_tc); + BT_ASSERT(ir_fc); + goto end; + } + + elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc); + BT_ASSERT(elem_ir_fc); + ir_fc = bt_field_class_array_static_create(ctx->ir_tc, elem_ir_fc, fc->length); + BT_ASSERT(ir_fc); + bt_field_class_put_ref(elem_ir_fc); + +end: + return ir_fc; +} + +static inline bt_field_class *ctf_field_class_sequence_to_ir(struct ctx *ctx, + struct ctf_field_class_sequence *fc) +{ + bt_field_class *ir_fc; + bt_field_class *elem_ir_fc; + bt_field_class *length_fc = NULL; + + if (fc->base.is_text) { + ir_fc = bt_field_class_string_create(ctx->ir_tc); + BT_ASSERT(ir_fc); + goto end; + } + + elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc); + BT_ASSERT(elem_ir_fc); + + if (fc->length_path.root != CTF_SCOPE_PACKET_HEADER && + fc->length_path.root != CTF_SCOPE_EVENT_HEADER) { + length_fc = borrow_ir_fc_from_field_path(ctx, &fc->length_path); + BT_ASSERT(length_fc); + } + + ir_fc = bt_field_class_array_dynamic_create(ctx->ir_tc, elem_ir_fc, length_fc); + BT_ASSERT(ir_fc); + bt_field_class_put_ref(elem_ir_fc); + BT_ASSERT(ir_fc); + +end: + return ir_fc; +} + +static inline bt_field_class *ctf_field_class_to_ir(struct ctx *ctx, struct ctf_field_class *fc) +{ + bt_field_class *ir_fc = NULL; + + BT_ASSERT(fc); + BT_ASSERT(fc->in_ir); + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_INT: + ir_fc = ctf_field_class_int_to_ir(ctx, ctf_field_class_as_int(fc)); + break; + case CTF_FIELD_CLASS_TYPE_ENUM: + ir_fc = ctf_field_class_enum_to_ir(ctx, ctf_field_class_as_enum(fc)); + break; + case CTF_FIELD_CLASS_TYPE_FLOAT: + ir_fc = ctf_field_class_float_to_ir(ctx, ctf_field_class_as_float(fc)); + break; + case CTF_FIELD_CLASS_TYPE_STRING: + ir_fc = ctf_field_class_string_to_ir(ctx, ctf_field_class_as_string(fc)); + break; + case CTF_FIELD_CLASS_TYPE_STRUCT: + ir_fc = ctf_field_class_struct_to_ir(ctx, ctf_field_class_as_struct(fc)); + break; + case CTF_FIELD_CLASS_TYPE_ARRAY: + ir_fc = ctf_field_class_array_to_ir(ctx, ctf_field_class_as_array(fc)); + break; + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + ir_fc = ctf_field_class_sequence_to_ir(ctx, ctf_field_class_as_sequence(fc)); + break; + case CTF_FIELD_CLASS_TYPE_VARIANT: + ir_fc = ctf_field_class_variant_to_ir(ctx, ctf_field_class_as_variant(fc)); + break; + default: + bt_common_abort(); + } + + fc->ir_fc = ir_fc; + return ir_fc; +} + +static inline bool +ctf_field_class_struct_has_immediate_member_in_ir(struct ctf_field_class_struct *fc) +{ + uint64_t i; + bool has_immediate_member_in_ir = false; + + /* + * If the structure field class has no members at all, then it + * was an empty structure in the beginning, so leave it existing + * and empty. + */ + if (fc->members->len == 0) { + has_immediate_member_in_ir = true; + goto end; + } + + for (i = 0; i < fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(fc, i); + + if (named_fc->fc->in_ir) { + has_immediate_member_in_ir = true; + goto end; + } + } + +end: + return has_immediate_member_in_ir; +} + +static inline bt_field_class *scope_ctf_field_class_to_ir(struct ctx *ctx) +{ + bt_field_class *ir_fc = NULL; + struct ctf_field_class *fc = NULL; + + switch (ctx->scope) { + case CTF_SCOPE_PACKET_CONTEXT: + fc = ctx->sc->packet_context_fc; + break; + case CTF_SCOPE_EVENT_COMMON_CONTEXT: + fc = ctx->sc->event_common_context_fc; + break; + case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: + fc = ctx->ec->spec_context_fc; + break; + case CTF_SCOPE_EVENT_PAYLOAD: + fc = ctx->ec->payload_fc; + break; + default: + bt_common_abort(); + } + + if (fc && ctf_field_class_struct_has_immediate_member_in_ir(ctf_field_class_as_struct(fc))) { + ir_fc = ctf_field_class_to_ir(ctx, fc); + } + + return ir_fc; +} + +static inline void ctf_event_class_to_ir(struct ctx *ctx) +{ + int ret; + bt_event_class *ir_ec = NULL; + bt_field_class *ir_fc; + + BT_ASSERT(ctx->ec); + + if (ctx->ec->is_translated) { + ir_ec = bt_stream_class_borrow_event_class_by_id(ctx->ir_sc, ctx->ec->id); + BT_ASSERT(ir_ec); + goto end; + } + + ir_ec = bt_event_class_create_with_id(ctx->ir_sc, ctx->ec->id); + BT_ASSERT(ir_ec); + bt_event_class_put_ref(ir_ec); + ctx->scope = CTF_SCOPE_EVENT_SPECIFIC_CONTEXT; + ir_fc = scope_ctf_field_class_to_ir(ctx); + if (ir_fc) { + ret = bt_event_class_set_specific_context_field_class(ir_ec, ir_fc); + BT_ASSERT(ret == 0); + bt_field_class_put_ref(ir_fc); + } + + ctx->scope = CTF_SCOPE_EVENT_PAYLOAD; + ir_fc = scope_ctf_field_class_to_ir(ctx); + if (ir_fc) { + ret = bt_event_class_set_payload_field_class(ir_ec, ir_fc); + BT_ASSERT(ret == 0); + bt_field_class_put_ref(ir_fc); + } + + if (ctx->ec->name->len > 0) { + ret = bt_event_class_set_name(ir_ec, ctx->ec->name->str); + BT_ASSERT(ret == 0); + } + + if (ctx->ec->emf_uri->len > 0) { + ret = bt_event_class_set_emf_uri(ir_ec, ctx->ec->emf_uri->str); + BT_ASSERT(ret == 0); + } + + if (ctx->ec->is_log_level_set) { + bt_event_class_set_log_level(ir_ec, ctx->ec->log_level); + } + + ctx->ec->is_translated = true; + ctx->ec->ir_ec = ir_ec; + +end: + return; +} + +static inline void ctf_stream_class_to_ir(struct ctx *ctx) +{ + int ret; + bt_field_class *ir_fc; + + BT_ASSERT(ctx->sc); + + if (ctx->sc->is_translated) { + ctx->ir_sc = bt_trace_class_borrow_stream_class_by_id(ctx->ir_tc, ctx->sc->id); + BT_ASSERT(ctx->ir_sc); + goto end; + } + + ctx->ir_sc = bt_stream_class_create_with_id(ctx->ir_tc, ctx->sc->id); + BT_ASSERT(ctx->ir_sc); + bt_stream_class_put_ref(ctx->ir_sc); + + if (ctx->sc->default_clock_class) { + BT_ASSERT(ctx->sc->default_clock_class->ir_cc); + ret = bt_stream_class_set_default_clock_class(ctx->ir_sc, + ctx->sc->default_clock_class->ir_cc); + BT_ASSERT(ret == 0); + } + + bt_stream_class_set_supports_packets(ctx->ir_sc, BT_TRUE, ctx->sc->packets_have_ts_begin, + ctx->sc->packets_have_ts_end); + bt_stream_class_set_supports_discarded_events(ctx->ir_sc, ctx->sc->has_discarded_events, + ctx->sc->discarded_events_have_default_cs); + bt_stream_class_set_supports_discarded_packets(ctx->ir_sc, ctx->sc->has_discarded_packets, + ctx->sc->discarded_packets_have_default_cs); + ctx->scope = CTF_SCOPE_PACKET_CONTEXT; + ir_fc = scope_ctf_field_class_to_ir(ctx); + if (ir_fc) { + ret = bt_stream_class_set_packet_context_field_class(ctx->ir_sc, ir_fc); + BT_ASSERT(ret == 0); + bt_field_class_put_ref(ir_fc); + } + + ctx->scope = CTF_SCOPE_EVENT_COMMON_CONTEXT; + ir_fc = scope_ctf_field_class_to_ir(ctx); + if (ir_fc) { + ret = bt_stream_class_set_event_common_context_field_class(ctx->ir_sc, ir_fc); + BT_ASSERT(ret == 0); + bt_field_class_put_ref(ir_fc); + } + + bt_stream_class_set_assigns_automatic_event_class_id(ctx->ir_sc, BT_FALSE); + bt_stream_class_set_assigns_automatic_stream_id(ctx->ir_sc, BT_FALSE); + + ctx->sc->is_translated = true; + ctx->sc->ir_sc = ctx->ir_sc; + +end: + return; +} + +static inline void ctf_clock_class_to_ir(bt_clock_class *ir_cc, struct ctf_clock_class *cc) +{ + int ret; + + if (strlen(cc->name->str) > 0) { + ret = bt_clock_class_set_name(ir_cc, cc->name->str); + BT_ASSERT(ret == 0); + } + + if (strlen(cc->description->str) > 0) { + ret = bt_clock_class_set_description(ir_cc, cc->description->str); + BT_ASSERT(ret == 0); + } + + bt_clock_class_set_frequency(ir_cc, cc->frequency); + bt_clock_class_set_precision(ir_cc, cc->precision); + bt_clock_class_set_offset(ir_cc, cc->offset_seconds, cc->offset_cycles); + + if (cc->has_uuid) { + bt_clock_class_set_uuid(ir_cc, cc->uuid); + } + + bt_clock_class_set_origin_is_unix_epoch(ir_cc, cc->is_absolute); +} + +static inline int ctf_trace_class_to_ir(struct ctx *ctx) +{ + int ret = 0; + uint64_t i; + + BT_ASSERT(ctx->tc); + BT_ASSERT(ctx->ir_tc); + + if (ctx->tc->is_translated) { + goto end; + } + + for (i = 0; i < ctx->tc->clock_classes->len; i++) { + ctf_clock_class *cc = (ctf_clock_class *) ctx->tc->clock_classes->pdata[i]; + + cc->ir_cc = bt_clock_class_create(ctx->self_comp); + ctf_clock_class_to_ir(cc->ir_cc, cc); + } + + bt_trace_class_set_assigns_automatic_stream_class_id(ctx->ir_tc, BT_FALSE); + ctx->tc->is_translated = true; + ctx->tc->ir_tc = ctx->ir_tc; + +end: + return ret; +} + +int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc, + struct ctf_trace_class *tc) +{ + int ret = 0; + uint64_t i; + struct ctx ctx = {}; + + ctx.self_comp = self_comp; + ctx.tc = tc; + ctx.ir_tc = ir_tc; + ret = ctf_trace_class_to_ir(&ctx); + if (ret) { + goto end; + } + + for (i = 0; i < tc->stream_classes->len; i++) { + uint64_t j; + ctx.sc = (ctf_stream_class *) tc->stream_classes->pdata[i]; + + ctf_stream_class_to_ir(&ctx); + + for (j = 0; j < ctx.sc->event_classes->len; j++) { + ctx.ec = (ctf_event_class *) ctx.sc->event_classes->pdata[j]; + + ctf_event_class_to_ir(&ctx); + ctx.ec = NULL; + } + + ctx.sc = NULL; + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp new file mode 100644 index 00000000..bea62bf9 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp @@ -0,0 +1,161 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2020 Philippe Proulx + */ + +#include + +#include "ctf-meta-visitors.hpp" + +static inline int set_alignments(struct ctf_field_class *fc) +{ + int ret = 0; + uint64_t i; + + if (!fc) { + goto end; + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + ret = set_alignments(named_fc->fc); + if (ret) { + goto end; + } + + if (named_fc->fc->alignment > fc->alignment) { + fc->alignment = named_fc->fc->alignment; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + for (i = 0; i < var_fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + ret = set_alignments(named_fc->fc); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + ret = set_alignments(array_fc->elem_fc); + if (ret) { + goto end; + } + + /* + * Use the alignment of the array/sequence field class's + * element FC as its own alignment. + * + * This is especially important when the array/sequence + * field's effective length is zero: as per CTF 1.8, the + * stream data decoding process still needs to align the + * cursor using the element's alignment [1]: + * + * > Arrays are always aligned on their element + * > alignment requirement. + * + * For example: + * + * struct { + * integer { size = 8; } a; + * integer { size = 8; align = 16; } b[0]; + * integer { size = 8; } c; + * }; + * + * When using this to decode the bytes 1, 2, and 3, then + * the decoded values are: + * + * `a`: 1 + * `b`: [] + * `c`: 3 + * + * [1]: https://diamon.org/ctf/#spec4.2.3 + */ + array_fc->base.alignment = array_fc->elem_fc->alignment; + break; + } + default: + break; + } + +end: + return ret; +} + +int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc) +{ + int ret = 0; + uint64_t i; + + if (!ctf_tc->is_translated) { + ret = set_alignments(ctf_tc->packet_header_fc); + if (ret) { + goto end; + } + } + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + uint64_t j; + + if (!sc->is_translated) { + ret = set_alignments(sc->packet_context_fc); + if (ret) { + goto end; + } + + ret = set_alignments(sc->event_header_fc); + if (ret) { + goto end; + } + + ret = set_alignments(sc->event_common_context_fc); + if (ret) { + goto end; + } + } + + for (j = 0; j < sc->event_classes->len; j++) { + struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; + + if (ec->is_translated) { + continue; + } + + ret = set_alignments(ec->spec_context_fc); + if (ret) { + goto end; + } + + ret = set_alignments(ec->payload_fc); + if (ret) { + goto end; + } + } + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp new file mode 100644 index 00000000..ab10dd4f --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp @@ -0,0 +1,180 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) +#define BT_COMP_LOG_SELF_COMP_CLASS (log_cfg->self_comp_class) +#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/UPDATE-DEF-CC" +#include "logging.hpp" + +#include "ctf-meta-visitors.hpp" + +static inline int find_mapped_clock_class(struct ctf_field_class *fc, + struct ctf_clock_class **clock_class, + struct meta_log_config *log_cfg) +{ + int ret = 0; + uint64_t i; + + if (!fc) { + goto end; + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_INT: + case CTF_FIELD_CLASS_TYPE_ENUM: + { + struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + + if (int_fc->mapped_clock_class) { + if (*clock_class && *clock_class != int_fc->mapped_clock_class) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class contains more than one " + "clock class: expected-cc-name=\"%s\", " + "other-cc-name=\"%s\"", + (*clock_class)->name->str, + int_fc->mapped_clock_class->name->str); + ret = -1; + goto end; + } + + *clock_class = int_fc->mapped_clock_class; + } + + break; + } + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + ret = find_mapped_clock_class(named_fc->fc, clock_class, log_cfg); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + for (i = 0; i < var_fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + ret = find_mapped_clock_class(named_fc->fc, clock_class, log_cfg); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + ret = find_mapped_clock_class(array_fc->elem_fc, clock_class, log_cfg); + if (ret) { + goto end; + } + + break; + } + default: + break; + } + +end: + return ret; +} + +static inline int update_stream_class_default_clock_class(struct ctf_stream_class *stream_class, + struct meta_log_config *log_cfg) +{ + int ret = 0; + struct ctf_clock_class *clock_class = stream_class->default_clock_class; + uint64_t i; + + ret = find_mapped_clock_class(stream_class->packet_context_fc, &clock_class, log_cfg); + if (ret) { + goto end; + } + + ret = find_mapped_clock_class(stream_class->event_header_fc, &clock_class, log_cfg); + if (ret) { + goto end; + } + + ret = find_mapped_clock_class(stream_class->event_common_context_fc, &clock_class, log_cfg); + if (ret) { + goto end; + } + + for (i = 0; i < stream_class->event_classes->len; i++) { + struct ctf_event_class *event_class = + (ctf_event_class *) stream_class->event_classes->pdata[i]; + + ret = find_mapped_clock_class(event_class->spec_context_fc, &clock_class, log_cfg); + if (ret) { + goto end; + } + + ret = find_mapped_clock_class(event_class->payload_fc, &clock_class, log_cfg); + if (ret) { + goto end; + } + } + + if (!stream_class->default_clock_class) { + stream_class->default_clock_class = clock_class; + } + +end: + return ret; +} + +int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc, + struct meta_log_config *log_cfg) +{ + uint64_t i; + int ret = 0; + struct ctf_clock_class *clock_class = NULL; + + ret = find_mapped_clock_class(ctf_tc->packet_header_fc, &clock_class, log_cfg); + if (ret) { + goto end; + } + + if (clock_class) { + ret = -1; + goto end; + } + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + struct ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + + ret = update_stream_class_default_clock_class( + (ctf_stream_class *) ctf_tc->stream_classes->pdata[i], log_cfg); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Stream class contains more than one " + "clock class: stream-class-id=%" PRIu64, + sc->id); + goto end; + } + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp new file mode 100644 index 00000000..c7902383 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp @@ -0,0 +1,259 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include +#include + +#include "common/assert.h" +#include "compat/glib.h" + +#include "ctf-meta-visitors.hpp" + +static void force_update_field_class_in_ir(struct ctf_field_class *fc, bool in_ir) +{ + uint64_t i; + + if (!fc) { + goto end; + } + + fc->in_ir = in_ir; + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + force_update_field_class_in_ir(named_fc->fc, in_ir); + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_named_field_class *named_fc; + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + for (i = 0; i < var_fc->options->len; i++) { + named_fc = ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + force_update_field_class_in_ir(named_fc->fc, in_ir); + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + force_update_field_class_in_ir(array_fc->elem_fc, in_ir); + break; + } + default: + break; + } + +end: + return; +} + +static void update_field_class_in_ir(struct ctf_field_class *fc, GHashTable *ft_dependents) +{ + int64_t i; + + if (!fc) { + goto end; + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_INT: + case CTF_FIELD_CLASS_TYPE_ENUM: + { + struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + + /* + * Conditions to be in trace IR; one of: + * + * 1. Does NOT have a mapped clock class AND does not + * have a special meaning. + * 2. Another field class depends on it. + */ + if ((!int_fc->mapped_clock_class && int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE) || + bt_g_hash_table_contains(ft_dependents, fc)) { + fc->in_ir = true; + } + + break; + } + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + /* + * Make it part of IR if it's empty because it was + * originally empty. + */ + if (struct_fc->members->len == 0) { + fc->in_ir = true; + } + + /* Reverse order */ + for (i = (int64_t) struct_fc->members->len - 1; i >= 0; i--) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + update_field_class_in_ir(named_fc->fc, ft_dependents); + + if (named_fc->fc->in_ir) { + /* At least one member is part of IR */ + fc->in_ir = true; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_named_field_class *named_fc; + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + /* + * Reverse order, although it is not important for this + * loop because a field class within a variant field + * type's option cannot depend on a field class in + * another option of the same variant field class. + */ + for (i = (int64_t) var_fc->options->len - 1; i >= 0; i--) { + named_fc = ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + update_field_class_in_ir(named_fc->fc, ft_dependents); + + if (named_fc->fc->in_ir) { + /* At least one option is part of IR */ + fc->in_ir = true; + } + } + + if (fc->in_ir) { + /* + * At least one option will make it to IR. In + * this case, make all options part of IR + * because the variant's tag could still select + * (dynamically) a removed option. This can mean + * having an empty structure as an option, for + * example, but at least all the options are + * selectable. + */ + for (i = 0; i < var_fc->options->len; i++) { + ctf_field_class_variant_borrow_option_by_index(var_fc, i)->fc->in_ir = true; + } + + /* + * This variant field class is part of IR and + * depends on a tag field class (which must also + * be part of IR). + */ + g_hash_table_insert(ft_dependents, var_fc->tag_fc, var_fc->tag_fc); + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + update_field_class_in_ir(array_fc->elem_fc, ft_dependents); + fc->in_ir = array_fc->elem_fc->in_ir; + + if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) { + struct ctf_field_class_array *arr_fc = ctf_field_class_as_array(fc); + + assert(arr_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE || + arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID); + + /* + * UUID field class: nothing depends on this, so + * it's not part of IR. + */ + if (arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID) { + fc->in_ir = false; + array_fc->elem_fc->in_ir = false; + } + } else if (fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { + if (fc->in_ir) { + struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); + + /* + * This sequence field class is part of + * IR and depends on a length field class + * (which must also be part of IR). + */ + g_hash_table_insert(ft_dependents, seq_fc->length_fc, seq_fc->length_fc); + } + } + + break; + } + default: + fc->in_ir = true; + break; + } + +end: + return; +} + +/* + * Scopes and field classes are processed in reverse order because we need + * to know if a given integer field class has dependents (sequence or + * variant field classes) when we reach it. Dependents can only be located + * after the length/tag field class in the metadata tree. + */ +int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc) +{ + int ret = 0; + uint64_t i; + + GHashTable *ft_dependents = g_hash_table_new(g_direct_hash, g_direct_equal); + + BT_ASSERT(ft_dependents); + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + uint64_t j; + + for (j = 0; j < sc->event_classes->len; j++) { + ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; + + if (ec->is_translated) { + continue; + } + + update_field_class_in_ir(ec->payload_fc, ft_dependents); + update_field_class_in_ir(ec->spec_context_fc, ft_dependents); + } + + if (!sc->is_translated) { + update_field_class_in_ir(sc->event_common_context_fc, ft_dependents); + force_update_field_class_in_ir(sc->event_header_fc, false); + update_field_class_in_ir(sc->packet_context_fc, ft_dependents); + } + } + + if (!ctf_tc->is_translated) { + force_update_field_class_in_ir(ctf_tc->packet_header_fc, false); + } + + g_hash_table_destroy(ft_dependents); + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp new file mode 100644 index 00000000..23c65745 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp @@ -0,0 +1,204 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#include "ctf-meta-visitors.hpp" + +static int set_int_field_class_meaning_by_name(struct ctf_field_class *fc, const char *field_name, + const char *id_name, + enum ctf_field_class_meaning meaning) +{ + int ret = 0; + uint64_t i; + + if (!fc) { + goto end; + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_INT: + case CTF_FIELD_CLASS_TYPE_ENUM: + { + struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + + if (field_name && strcmp(field_name, id_name) == 0) { + int_fc->meaning = meaning; + } + + break; + } + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + ret = set_int_field_class_meaning_by_name(named_fc->fc, named_fc->name->str, id_name, + meaning); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + for (i = 0; i < var_fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + ret = set_int_field_class_meaning_by_name(named_fc->fc, NULL, id_name, meaning); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + ret = set_int_field_class_meaning_by_name(array_fc->elem_fc, NULL, id_name, meaning); + if (ret) { + goto end; + } + + break; + } + default: + break; + } + +end: + return ret; +} + +static int update_stream_class_meanings(struct ctf_stream_class *sc) +{ + int ret = 0; + struct ctf_field_class_int *int_fc; + uint64_t i; + + if (!sc->is_translated) { + if (sc->packet_context_fc) { + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_END_TIME; + + /* + * Remove mapped clock class to avoid updating + * the clock immediately when decoding. + */ + int_fc->mapped_clock_class = NULL; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "packet_seq_num"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "packet_size"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "content_size"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE; + } + } + + if (sc->event_header_fc) { + ret = set_int_field_class_meaning_by_name(sc->event_header_fc, NULL, "id", + CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID); + if (ret) { + goto end; + } + } + } + + for (i = 0; i < sc->event_classes->len; i++) { + struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[i]; + + if (ec->is_translated) { + continue; + } + } + +end: + return ret; +} + +int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc) +{ + int ret = 0; + struct ctf_field_class_int *int_fc; + struct ctf_named_field_class *named_fc; + uint64_t i; + + if (!ctf_tc->is_translated && ctf_tc->packet_header_fc) { + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "magic"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_MAGIC; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_id"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_instance_id"); + if (int_fc) { + int_fc->meaning = CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID; + } + + named_fc = ctf_field_class_struct_borrow_member_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "uuid"); + if (named_fc && named_fc->fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) { + struct ctf_field_class_array *array_fc = ctf_field_class_as_array(named_fc->fc); + + array_fc->meaning = CTF_FIELD_CLASS_MEANING_UUID; + } + } + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + ret = update_stream_class_meanings((ctf_stream_class *) ctf_tc->stream_classes->pdata[i]); + if (ret) { + goto end; + } + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp new file mode 100644 index 00000000..a8f5add6 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Philippe Proulx + */ + +#include + +#include "ctf-meta-visitors.hpp" + +int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc) +{ + struct ctf_field_class_int *int_fc; + uint64_t i; + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + struct ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + + if (sc->is_translated) { + continue; + } + + if (!sc->packet_context_fc) { + continue; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin"); + if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME) { + sc->packets_have_ts_begin = true; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end"); + if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_PACKET_END_TIME) { + sc->packets_have_ts_end = true; + } + + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded"); + if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT) { + sc->has_discarded_events = true; + } + + sc->discarded_events_have_default_cs = + sc->has_discarded_events && sc->packets_have_ts_begin && sc->packets_have_ts_end; + int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "packet_seq_num"); + if (int_fc && int_fc->meaning == CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT) { + sc->has_discarded_packets = true; + } + + sc->discarded_packets_have_default_cs = + sc->has_discarded_packets && sc->packets_have_ts_begin && sc->packets_have_ts_end; + } + + return 0; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp new file mode 100644 index 00000000..6c3bfc97 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp @@ -0,0 +1,146 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include + +#include "ctf-meta-visitors.hpp" + +static inline int set_text_array_sequence_field_class(struct ctf_field_class *fc) +{ + int ret = 0; + uint64_t i; + + if (!fc) { + goto end; + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + ret = set_text_array_sequence_field_class(named_fc->fc); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + for (i = 0; i < var_fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + ret = set_text_array_sequence_field_class(named_fc->fc); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + if (array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_INT || + array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_ENUM) { + struct ctf_field_class_int *int_fc = ctf_field_class_as_int(array_fc->elem_fc); + + if (int_fc->base.base.alignment == 8 && int_fc->base.size == 8 && + int_fc->encoding == CTF_ENCODING_UTF8) { + array_fc->is_text = true; + + /* + * Force integer element to be unsigned; + * this makes the decoder enter a single + * path when reading a text + * array/sequence and we can safely + * decode bytes as characters anyway. + */ + int_fc->is_signed = false; + } + } + + ret = set_text_array_sequence_field_class(array_fc->elem_fc); + if (ret) { + goto end; + } + + break; + } + default: + break; + } + +end: + return ret; +} + +int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc) +{ + int ret = 0; + uint64_t i; + + if (!ctf_tc->is_translated) { + ret = set_text_array_sequence_field_class(ctf_tc->packet_header_fc); + if (ret) { + goto end; + } + } + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + uint64_t j; + + if (!sc->is_translated) { + ret = set_text_array_sequence_field_class(sc->packet_context_fc); + if (ret) { + goto end; + } + + ret = set_text_array_sequence_field_class(sc->event_header_fc); + if (ret) { + goto end; + } + + ret = set_text_array_sequence_field_class(sc->event_common_context_fc); + if (ret) { + goto end; + } + } + + for (j = 0; j < sc->event_classes->len; j++) { + struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; + + if (ec->is_translated) { + continue; + } + + ret = set_text_array_sequence_field_class(ec->spec_context_fc); + if (ret) { + goto end; + } + + ret = set_text_array_sequence_field_class(ec->payload_fc); + if (ret) { + goto end; + } + } + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp new file mode 100644 index 00000000..65e4c9fe --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp @@ -0,0 +1,149 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#include "common/assert.h" + +#include "ctf-meta-visitors.hpp" + +static int update_field_class_stored_value_index(struct ctf_field_class *fc, + struct ctf_trace_class *tc, + struct ctf_stream_class *sc, + struct ctf_event_class *ec) +{ + int ret = 0; + uint64_t i; + struct ctf_field_path *field_path = NULL; + struct ctf_field_class_int *tgt_fc = NULL; + uint64_t *stored_value_index = NULL; + + if (!fc) { + goto end; + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + field_path = &var_fc->tag_path; + stored_value_index = &var_fc->stored_tag_index; + tgt_fc = &var_fc->tag_fc->base; + break; + } + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); + + field_path = &seq_fc->length_path; + stored_value_index = &seq_fc->stored_length_index; + tgt_fc = seq_fc->length_fc; + break; + } + default: + break; + } + + if (field_path) { + BT_ASSERT(tgt_fc); + BT_ASSERT(tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_INT || + tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_ENUM); + if (tgt_fc->storing_index >= 0) { + /* Already storing its value */ + *stored_value_index = (uint64_t) tgt_fc->storing_index; + } else { + /* Not storing its value: allocate new index */ + tgt_fc->storing_index = tc->stored_value_count; + *stored_value_index = (uint64_t) tgt_fc->storing_index; + tc->stored_value_count++; + } + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + ret = update_field_class_stored_value_index(named_fc->fc, tc, sc, ec); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + for (i = 0; i < var_fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + ret = update_field_class_stored_value_index(named_fc->fc, tc, sc, ec); + if (ret) { + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + ret = update_field_class_stored_value_index(array_fc->elem_fc, tc, sc, ec); + if (ret) { + goto end; + } + + break; + } + default: + break; + } + +end: + return ret; +} + +int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc) +{ + uint64_t i; + + if (!ctf_tc->is_translated) { + update_field_class_stored_value_index(ctf_tc->packet_header_fc, ctf_tc, NULL, NULL); + } + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + uint64_t j; + ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + + if (!sc->is_translated) { + update_field_class_stored_value_index(sc->packet_context_fc, ctf_tc, sc, NULL); + update_field_class_stored_value_index(sc->event_header_fc, ctf_tc, sc, NULL); + update_field_class_stored_value_index(sc->event_common_context_fc, ctf_tc, sc, NULL); + } + + for (j = 0; j < sc->event_classes->len; j++) { + struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j]; + + if (!ec->is_translated) { + update_field_class_stored_value_index(ec->spec_context_fc, ctf_tc, sc, ec); + update_field_class_stored_value_index(ec->payload_fc, ctf_tc, sc, ec); + } + } + } + + return 0; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp new file mode 100644 index 00000000..9a01c593 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp @@ -0,0 +1,333 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include + +#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) +#define BT_COMP_LOG_SELF_COMP_CLASS (log_cfg->self_comp_class) +#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/VALIDATE" +#include "logging.hpp" + +#include "ctf-meta-visitors.hpp" + +static int validate_stream_class(struct ctf_stream_class *sc, struct meta_log_config *log_cfg) +{ + int ret = 0; + struct ctf_field_class_int *int_fc; + struct ctf_field_class *fc; + + if (sc->is_translated) { + goto end; + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet context field class: " + "`timestamp_begin` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " + "`timestamp_begin` member is signed."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet context field class: " + "`timestamp_end` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " + "`timestamp_end` member is signed."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet context field class: " + "`events_discarded` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " + "`events_discarded` member is signed."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "packet_seq_num"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet context field class: " + "`packet_seq_num` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " + "`packet_seq_num` member is signed."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "packet_size"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet context field class: " + "`packet_size` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " + "`packet_size` member is signed."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(sc->packet_context_fc), "content_size"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet context field class: " + "`content_size` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: " + "`content_size` member is signed."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(sc->event_header_fc), "id"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: " + "`id` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: " + "`id` member is signed."); + goto invalid; + } + } else { + if (sc->event_classes->len > 1) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: " + "missing `id` member as there's " + "more than one event class."); + goto invalid; + } + } + + goto end; + +invalid: + ret = -1; + +end: + return ret; +} + +int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, struct meta_log_config *log_cfg) +{ + int ret = 0; + struct ctf_field_class_int *int_fc; + uint64_t i; + + if (!ctf_tc->is_translated) { + struct ctf_field_class *fc; + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "magic"); + if (fc) { + struct ctf_named_field_class *named_fc = ctf_field_class_struct_borrow_member_by_index( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), 0); + + if (named_fc->fc != fc) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`magic` member is not the first member."); + goto invalid; + } + + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet header field class: " + "`magic` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`magic` member is signed."); + goto invalid; + } + + if (int_fc->base.size != 32) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`magic` member is not 32-bit."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_id"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet header field class: " + "`stream_id` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`stream_id` member is signed."); + goto invalid; + } + } else { + if (ctf_tc->stream_classes->len > 1) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "missing `stream_id` member as there's " + "more than one stream class."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "stream_instance_id"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet header field class: " + "`stream_instance_id` member is not an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`stream_instance_id` member is signed."); + goto invalid; + } + } + + fc = ctf_field_class_struct_borrow_member_field_class_by_name( + ctf_field_class_as_struct(ctf_tc->packet_header_fc), "uuid"); + if (fc) { + if (fc->type != CTF_FIELD_CLASS_TYPE_ARRAY) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet header field class: " + "`uuid` member is not an array field class."); + goto invalid; + } + + ctf_field_class_array *array_fc = ctf_field_class_as_array(fc); + + if (array_fc->length != 16) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet header field class: " + "`uuid` member is not a 16-element array field class."); + goto invalid; + } + + if (array_fc->base.elem_fc->type != CTF_FIELD_CLASS_TYPE_INT) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid packet header field class: " + "`uuid` member's element field class is not " + "an integer field class."); + goto invalid; + } + + int_fc = ctf_field_class_as_int(array_fc->base.elem_fc); + + if (int_fc->is_signed) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`uuid` member's element field class " + "is a signed integer field class."); + goto invalid; + } + + if (int_fc->base.size != 8) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`uuid` member's element field class " + "is not an 8-bit integer field class."); + goto invalid; + } + + if (int_fc->base.base.alignment != 8) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: " + "`uuid` member's element field class's " + "alignment is not 8."); + goto invalid; + } + } + } + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + struct ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + + ret = validate_stream_class(sc, log_cfg); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid stream class: sc-id=%" PRIu64, + sc->id); + goto invalid; + } + } + + goto end; + +invalid: + ret = -1; + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp new file mode 100644 index 00000000..5294ecec --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#ifndef _CTF_META_VISITORS_H +#define _CTF_META_VISITORS_H + +#include + +#include "ctf-meta.hpp" + +struct meta_log_config; + +int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc, + struct meta_log_config *log_cfg); + +int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc, + struct ctf_trace_class *tc); + +int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc, + struct meta_log_config *log_cfg); + +int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc); + +int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc); + +int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc); + +int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc); + +int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc); + +int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc); + +int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, struct meta_log_config *log_cfg); + +void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc, + struct meta_log_config *log_cfg); + +#endif /* _CTF_META_VISITORS_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp new file mode 100644 index 00000000..6d7e274a --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp @@ -0,0 +1,123 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) +#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/WARN-MEANINGLESS-HEADER-FIELDS" +#include "logging.hpp" +#include "logging/comp-logging.h" + +#include "common/assert.h" + +#include "ctf-meta-visitors.hpp" + +static inline void warn_meaningless_field(const char *name, const char *scope_name, + struct meta_log_config *log_cfg) +{ + BT_ASSERT(name); + BT_COMP_LOGW("User field found in %s: ignoring: name=\"%s\"", scope_name, name); +} + +static inline void warn_meaningless_fields(struct ctf_field_class *fc, const char *name, + const char *scope_name, struct meta_log_config *log_cfg) +{ + uint64_t i; + + if (!fc) { + goto end; + } + + /* + * 'name' is guaranteed to be non-NULL whenever the field class is not a + * structure. In the case of a structure field class, its members' names + * are used. + */ + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_FLOAT: + case CTF_FIELD_CLASS_TYPE_STRING: + warn_meaningless_field(name, scope_name, log_cfg); + break; + case CTF_FIELD_CLASS_TYPE_INT: + case CTF_FIELD_CLASS_TYPE_ENUM: + { + struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + + if (int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE && !int_fc->mapped_clock_class) { + warn_meaningless_field(name, scope_name, log_cfg); + } + + break; + } + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc); + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + warn_meaningless_fields(named_fc->fc, named_fc->name->str, scope_name, log_cfg); + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + + for (i = 0; i < var_fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + warn_meaningless_fields(named_fc->fc, named_fc->name->str, scope_name, log_cfg); + } + + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + { + struct ctf_field_class_array *array_fc = ctf_field_class_as_array(fc); + + if (array_fc->meaning != CTF_FIELD_CLASS_MEANING_NONE) { + goto end; + } + } + /* fall-through */ + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + warn_meaningless_fields(array_fc->elem_fc, name, scope_name, log_cfg); + break; + } + default: + bt_common_abort(); + } + +end: + return; +} + +void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc, + struct meta_log_config *log_cfg) +{ + uint64_t i; + + if (!ctf_tc->is_translated) { + warn_meaningless_fields(ctf_tc->packet_header_fc, NULL, "packet header", log_cfg); + } + + for (i = 0; i < ctf_tc->stream_classes->len; i++) { + ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i]; + + if (!sc->is_translated) { + warn_meaningless_fields(sc->event_header_fc, NULL, "event header", log_cfg); + } + } +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp new file mode 100644 index 00000000..87469d3b --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp @@ -0,0 +1,1748 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#ifndef _CTF_META_H +#define _CTF_META_H + +#include +#include +#include + +#include + +#include "common/assert.h" +#include "common/common.h" +#include "common/uuid.h" + +enum ctf_field_class_type +{ + CTF_FIELD_CLASS_TYPE_INT, + CTF_FIELD_CLASS_TYPE_ENUM, + CTF_FIELD_CLASS_TYPE_FLOAT, + CTF_FIELD_CLASS_TYPE_STRING, + CTF_FIELD_CLASS_TYPE_STRUCT, + CTF_FIELD_CLASS_TYPE_ARRAY, + CTF_FIELD_CLASS_TYPE_SEQUENCE, + CTF_FIELD_CLASS_TYPE_VARIANT, +}; + +enum ctf_field_class_meaning +{ + CTF_FIELD_CLASS_MEANING_NONE, + CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME, + CTF_FIELD_CLASS_MEANING_PACKET_END_TIME, + CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID, + CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID, + CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID, + CTF_FIELD_CLASS_MEANING_MAGIC, + CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT, + CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT, + CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE, + CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE, + CTF_FIELD_CLASS_MEANING_UUID, +}; + +enum ctf_byte_order +{ + CTF_BYTE_ORDER_UNKNOWN, + CTF_BYTE_ORDER_DEFAULT, + CTF_BYTE_ORDER_LITTLE, + CTF_BYTE_ORDER_BIG, +}; + +enum ctf_encoding +{ + CTF_ENCODING_NONE, + CTF_ENCODING_UTF8, +}; + +enum ctf_scope +{ + CTF_SCOPE_PACKET_UNKNOWN = -1, + CTF_SCOPE_PACKET_HEADER = 0, + CTF_SCOPE_PACKET_CONTEXT, + CTF_SCOPE_EVENT_HEADER, + CTF_SCOPE_EVENT_COMMON_CONTEXT, + CTF_SCOPE_EVENT_SPECIFIC_CONTEXT, + CTF_SCOPE_EVENT_PAYLOAD, +}; + +struct ctf_clock_class +{ + GString *name; + GString *description; + uint64_t frequency; + uint64_t precision; + int64_t offset_seconds; + uint64_t offset_cycles; + bt_uuid_t uuid; + bool has_uuid; + bool is_absolute; + + /* Weak, set during translation */ + bt_clock_class *ir_cc; +}; + +struct ctf_field_class +{ + enum ctf_field_class_type type; + unsigned int alignment; + bool is_compound; + bool in_ir; + + /* Weak, set during translation. NULL if `in_ir` is false below. */ + bt_field_class *ir_fc; +}; + +struct ctf_field_class_bit_array +{ + struct ctf_field_class base; + enum ctf_byte_order byte_order; + unsigned int size; +}; + +struct ctf_field_class_int +{ + struct ctf_field_class_bit_array base; + enum ctf_field_class_meaning meaning; + bool is_signed; + bt_field_class_integer_preferred_display_base disp_base; + enum ctf_encoding encoding; + int64_t storing_index; + + /* Weak */ + struct ctf_clock_class *mapped_clock_class; +}; + +struct ctf_range +{ + union + { + uint64_t u; + int64_t i; + } lower; + + union + { + uint64_t u; + int64_t i; + } upper; +}; + +struct ctf_field_class_enum_mapping +{ + GString *label; + + /* Array of `struct ctf_range` */ + GArray *ranges; +}; + +struct ctf_field_class_enum +{ + struct ctf_field_class_int base; + + /* Array of `struct ctf_field_class_enum_mapping` */ + GArray *mappings; +}; + +struct ctf_field_class_float +{ + struct ctf_field_class_bit_array base; +}; + +struct ctf_field_class_string +{ + struct ctf_field_class base; + enum ctf_encoding encoding; +}; + +struct ctf_named_field_class +{ + /* Original name which can include a leading `_` */ + GString *orig_name; + + /* Name as translated to trace IR (leading `_` removed) */ + GString *name; + + /* Owned by this */ + struct ctf_field_class *fc; +}; + +struct ctf_field_class_struct +{ + struct ctf_field_class base; + + /* Array of `struct ctf_named_field_class` */ + GArray *members; +}; + +struct ctf_field_path +{ + enum ctf_scope root; + + /* Array of `int64_t` */ + GArray *path; +}; + +struct ctf_field_class_variant_range +{ + struct ctf_range range; + uint64_t option_index; +}; + +struct ctf_field_class_variant +{ + struct ctf_field_class base; + GString *tag_ref; + struct ctf_field_path tag_path; + uint64_t stored_tag_index; + + /* Array of `struct ctf_named_field_class` */ + GArray *options; + + /* Array of `struct ctf_field_class_variant_range` */ + GArray *ranges; + + /* Weak */ + struct ctf_field_class_enum *tag_fc; +}; + +struct ctf_field_class_array_base +{ + struct ctf_field_class base; + struct ctf_field_class *elem_fc; + bool is_text; +}; + +struct ctf_field_class_array +{ + struct ctf_field_class_array_base base; + enum ctf_field_class_meaning meaning; + uint64_t length; +}; + +struct ctf_field_class_sequence +{ + struct ctf_field_class_array_base base; + GString *length_ref; + struct ctf_field_path length_path; + uint64_t stored_length_index; + + /* Weak */ + struct ctf_field_class_int *length_fc; +}; + +struct ctf_event_class +{ + GString *name; + uint64_t id; + GString *emf_uri; + bt_event_class_log_level log_level; + bool is_translated; + bool is_log_level_set; + + /* Owned by this */ + struct ctf_field_class *spec_context_fc; + + /* Owned by this */ + struct ctf_field_class *payload_fc; + + /* Weak, set during translation */ + bt_event_class *ir_ec; +}; + +struct ctf_stream_class +{ + uint64_t id; + bool is_translated; + bool packets_have_ts_begin; + bool packets_have_ts_end; + bool has_discarded_events; + bool has_discarded_packets; + bool discarded_events_have_default_cs; + bool discarded_packets_have_default_cs; + + /* Owned by this */ + struct ctf_field_class *packet_context_fc; + + /* Owned by this */ + struct ctf_field_class *event_header_fc; + + /* Owned by this */ + struct ctf_field_class *event_common_context_fc; + + /* Array of `struct ctf_event_class *`, owned by this */ + GPtrArray *event_classes; + + /* + * Hash table mapping event class IDs to `struct ctf_event_class *`, + * weak. + */ + GHashTable *event_classes_by_id; + + /* Weak */ + struct ctf_clock_class *default_clock_class; + + /* Weak, set during translation */ + bt_stream_class *ir_sc; +}; + +enum ctf_trace_class_env_entry_type +{ + CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT, + CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR, +}; + +struct ctf_trace_class_env_entry +{ + enum ctf_trace_class_env_entry_type type; + GString *name; + + struct + { + int64_t i; + GString *str; + } value; +}; + +struct ctf_trace_class +{ + unsigned int major; + unsigned int minor; + bt_uuid_t uuid; + bool is_uuid_set; + enum ctf_byte_order default_byte_order; + + /* Owned by this */ + struct ctf_field_class *packet_header_fc; + + uint64_t stored_value_count; + + /* Array of `struct ctf_clock_class *` (owned by this) */ + GPtrArray *clock_classes; + + /* Array of `struct ctf_stream_class *` */ + GPtrArray *stream_classes; + + /* Array of `struct ctf_trace_class_env_entry` */ + GArray *env_entries; + + bool is_translated; + + /* Weak, set during translation */ + bt_trace_class *ir_tc; + + struct + { + bool lttng_crash; + bool lttng_event_after_packet; + bool barectf_event_before_packet; + } quirks; +}; + +static inline ctf_field_class_bit_array *ctf_field_class_as_bit_array(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || + (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM || + fc->type == CTF_FIELD_CLASS_TYPE_FLOAT)); + return (ctf_field_class_bit_array *) fc; +} + +static inline ctf_field_class_int *ctf_field_class_as_int(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || + (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM)); + return (ctf_field_class_int *) fc; +} + +static inline ctf_field_class_enum *ctf_field_class_as_enum(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ENUM); + return (ctf_field_class_enum *) fc; +} + +static inline ctf_field_class_float *ctf_field_class_as_float(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_FLOAT); + return (ctf_field_class_float *) fc; +} + +static inline ctf_field_class_string *ctf_field_class_as_string(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRING); + return (ctf_field_class_string *) fc; +} + +static inline ctf_field_class_struct *ctf_field_class_as_struct(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRUCT); + return (ctf_field_class_struct *) fc; +} + +static inline ctf_field_class_array_base *ctf_field_class_as_array_base(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || + fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE)); + return (ctf_field_class_array_base *) fc; +} + +static inline ctf_field_class_array *ctf_field_class_as_array(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ARRAY); + return (ctf_field_class_array *) fc; +} + +static inline ctf_field_class_sequence *ctf_field_class_as_sequence(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE); + return (ctf_field_class_sequence *) fc; +} + +static inline ctf_field_class_variant *ctf_field_class_as_variant(ctf_field_class *fc) +{ + BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_VARIANT); + return (ctf_field_class_variant *) fc; +} + +static inline void ctf_field_class_destroy(struct ctf_field_class *fc); + +static inline void _ctf_field_class_init(struct ctf_field_class *fc, enum ctf_field_class_type type, + unsigned int alignment) +{ + BT_ASSERT(fc); + fc->type = type; + fc->alignment = alignment; + fc->in_ir = false; +} + +static inline void _ctf_field_class_bit_array_init(struct ctf_field_class_bit_array *fc, + enum ctf_field_class_type type) +{ + _ctf_field_class_init(&fc->base, type, 1); +} + +static inline void _ctf_field_class_int_init(struct ctf_field_class_int *fc, + enum ctf_field_class_type type) +{ + _ctf_field_class_bit_array_init(&fc->base, type); + fc->meaning = CTF_FIELD_CLASS_MEANING_NONE; + fc->storing_index = -1; +} + +static inline void ctf_field_path_init(struct ctf_field_path *field_path) +{ + BT_ASSERT(field_path); + field_path->path = g_array_new(FALSE, TRUE, sizeof(int64_t)); + BT_ASSERT(field_path->path); +} + +static inline void ctf_field_path_fini(struct ctf_field_path *field_path) +{ + BT_ASSERT(field_path); + + if (field_path->path) { + g_array_free(field_path->path, TRUE); + } +} + +static inline void _ctf_named_field_class_init(struct ctf_named_field_class *named_fc) +{ + BT_ASSERT(named_fc); + named_fc->name = g_string_new(NULL); + BT_ASSERT(named_fc->name); + named_fc->orig_name = g_string_new(NULL); + BT_ASSERT(named_fc->orig_name); +} + +static inline void _ctf_named_field_class_fini(struct ctf_named_field_class *named_fc) +{ + BT_ASSERT(named_fc); + + if (named_fc->name) { + g_string_free(named_fc->name, TRUE); + } + + if (named_fc->orig_name) { + g_string_free(named_fc->orig_name, TRUE); + } + + ctf_field_class_destroy(named_fc->fc); +} + +static inline void _ctf_field_class_enum_mapping_init(struct ctf_field_class_enum_mapping *mapping) +{ + BT_ASSERT(mapping); + mapping->label = g_string_new(NULL); + BT_ASSERT(mapping->label); + mapping->ranges = g_array_new(FALSE, TRUE, sizeof(struct ctf_range)); + BT_ASSERT(mapping->ranges); +} + +static inline void _ctf_field_class_enum_mapping_fini(struct ctf_field_class_enum_mapping *mapping) +{ + BT_ASSERT(mapping); + + if (mapping->label) { + g_string_free(mapping->label, TRUE); + } + + if (mapping->ranges) { + g_array_free(mapping->ranges, TRUE); + } +} + +static inline struct ctf_field_class_int *ctf_field_class_int_create(void) +{ + struct ctf_field_class_int *fc = g_new0(struct ctf_field_class_int, 1); + + BT_ASSERT(fc); + _ctf_field_class_int_init(fc, CTF_FIELD_CLASS_TYPE_INT); + return fc; +} + +static inline struct ctf_field_class_float *ctf_field_class_float_create(void) +{ + struct ctf_field_class_float *fc = g_new0(struct ctf_field_class_float, 1); + + BT_ASSERT(fc); + _ctf_field_class_bit_array_init(&fc->base, CTF_FIELD_CLASS_TYPE_FLOAT); + return fc; +} + +static inline struct ctf_field_class_string *ctf_field_class_string_create(void) +{ + struct ctf_field_class_string *fc = g_new0(struct ctf_field_class_string, 1); + + BT_ASSERT(fc); + _ctf_field_class_init(&fc->base, CTF_FIELD_CLASS_TYPE_STRING, 8); + return fc; +} + +static inline struct ctf_field_class_enum *ctf_field_class_enum_create(void) +{ + struct ctf_field_class_enum *fc = g_new0(struct ctf_field_class_enum, 1); + + BT_ASSERT(fc); + _ctf_field_class_int_init(&fc->base, CTF_FIELD_CLASS_TYPE_ENUM); + fc->mappings = g_array_new(FALSE, TRUE, sizeof(struct ctf_field_class_enum_mapping)); + BT_ASSERT(fc->mappings); + return fc; +} + +static inline struct ctf_field_class_struct *ctf_field_class_struct_create(void) +{ + struct ctf_field_class_struct *fc = g_new0(struct ctf_field_class_struct, 1); + + BT_ASSERT(fc); + _ctf_field_class_init(&fc->base, CTF_FIELD_CLASS_TYPE_STRUCT, 1); + fc->members = g_array_new(FALSE, TRUE, sizeof(struct ctf_named_field_class)); + BT_ASSERT(fc->members); + fc->base.is_compound = true; + return fc; +} + +static inline struct ctf_field_class_variant *ctf_field_class_variant_create(void) +{ + struct ctf_field_class_variant *fc = g_new0(struct ctf_field_class_variant, 1); + + BT_ASSERT(fc); + _ctf_field_class_init(&fc->base, CTF_FIELD_CLASS_TYPE_VARIANT, 1); + fc->options = g_array_new(FALSE, TRUE, sizeof(struct ctf_named_field_class)); + BT_ASSERT(fc->options); + fc->ranges = g_array_new(FALSE, TRUE, sizeof(struct ctf_field_class_variant_range)); + BT_ASSERT(fc->ranges); + fc->tag_ref = g_string_new(NULL); + BT_ASSERT(fc->tag_ref); + ctf_field_path_init(&fc->tag_path); + fc->base.is_compound = true; + return fc; +} + +static inline struct ctf_field_class_array *ctf_field_class_array_create(void) +{ + struct ctf_field_class_array *fc = g_new0(struct ctf_field_class_array, 1); + + BT_ASSERT(fc); + _ctf_field_class_init(&fc->base.base, CTF_FIELD_CLASS_TYPE_ARRAY, 1); + fc->base.base.is_compound = true; + return fc; +} + +static inline struct ctf_field_class_sequence *ctf_field_class_sequence_create(void) +{ + struct ctf_field_class_sequence *fc = g_new0(struct ctf_field_class_sequence, 1); + + BT_ASSERT(fc); + _ctf_field_class_init(&fc->base.base, CTF_FIELD_CLASS_TYPE_SEQUENCE, 1); + fc->length_ref = g_string_new(NULL); + BT_ASSERT(fc->length_ref); + ctf_field_path_init(&fc->length_path); + fc->base.base.is_compound = true; + return fc; +} + +static inline void _ctf_field_class_int_destroy(struct ctf_field_class_int *fc) +{ + BT_ASSERT(fc); + g_free(fc); +} + +static inline void _ctf_field_class_enum_destroy(struct ctf_field_class_enum *fc) +{ + BT_ASSERT(fc); + + if (fc->mappings) { + uint64_t i; + + for (i = 0; i < fc->mappings->len; i++) { + struct ctf_field_class_enum_mapping *mapping = + &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, i); + + _ctf_field_class_enum_mapping_fini(mapping); + } + + g_array_free(fc->mappings, TRUE); + } + + g_free(fc); +} + +static inline void _ctf_field_class_float_destroy(struct ctf_field_class_float *fc) +{ + BT_ASSERT(fc); + g_free(fc); +} + +static inline void _ctf_field_class_string_destroy(struct ctf_field_class_string *fc) +{ + BT_ASSERT(fc); + g_free(fc); +} + +static inline void _ctf_field_class_struct_destroy(struct ctf_field_class_struct *fc) +{ + BT_ASSERT(fc); + + if (fc->members) { + uint64_t i; + + for (i = 0; i < fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + &bt_g_array_index(fc->members, struct ctf_named_field_class, i); + + _ctf_named_field_class_fini(named_fc); + } + + g_array_free(fc->members, TRUE); + } + + g_free(fc); +} + +static inline void _ctf_field_class_array_base_fini(struct ctf_field_class_array_base *fc) +{ + BT_ASSERT(fc); + ctf_field_class_destroy(fc->elem_fc); +} + +static inline void _ctf_field_class_array_destroy(struct ctf_field_class_array *fc) +{ + BT_ASSERT(fc); + _ctf_field_class_array_base_fini(&fc->base); + g_free(fc); +} + +static inline void _ctf_field_class_sequence_destroy(struct ctf_field_class_sequence *fc) +{ + BT_ASSERT(fc); + _ctf_field_class_array_base_fini(&fc->base); + + if (fc->length_ref) { + g_string_free(fc->length_ref, TRUE); + } + + ctf_field_path_fini(&fc->length_path); + g_free(fc); +} + +static inline void _ctf_field_class_variant_destroy(struct ctf_field_class_variant *fc) +{ + BT_ASSERT(fc); + + if (fc->options) { + uint64_t i; + + for (i = 0; i < fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + &bt_g_array_index(fc->options, struct ctf_named_field_class, i); + + _ctf_named_field_class_fini(named_fc); + } + + g_array_free(fc->options, TRUE); + } + + if (fc->ranges) { + g_array_free(fc->ranges, TRUE); + } + + if (fc->tag_ref) { + g_string_free(fc->tag_ref, TRUE); + } + + ctf_field_path_fini(&fc->tag_path); + g_free(fc); +} + +static inline void ctf_field_class_destroy(struct ctf_field_class *fc) +{ + if (!fc) { + return; + } + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_INT: + _ctf_field_class_int_destroy(ctf_field_class_as_int(fc)); + break; + case CTF_FIELD_CLASS_TYPE_ENUM: + _ctf_field_class_enum_destroy(ctf_field_class_as_enum(fc)); + break; + case CTF_FIELD_CLASS_TYPE_FLOAT: + _ctf_field_class_float_destroy(ctf_field_class_as_float(fc)); + break; + case CTF_FIELD_CLASS_TYPE_STRING: + _ctf_field_class_string_destroy(ctf_field_class_as_string(fc)); + break; + case CTF_FIELD_CLASS_TYPE_STRUCT: + _ctf_field_class_struct_destroy(ctf_field_class_as_struct(fc)); + break; + case CTF_FIELD_CLASS_TYPE_ARRAY: + _ctf_field_class_array_destroy(ctf_field_class_as_array(fc)); + break; + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + _ctf_field_class_sequence_destroy(ctf_field_class_as_sequence(fc)); + break; + case CTF_FIELD_CLASS_TYPE_VARIANT: + _ctf_field_class_variant_destroy(ctf_field_class_as_variant(fc)); + break; + default: + bt_common_abort(); + } +} + +static inline struct ctf_range * +ctf_field_class_enum_mapping_borrow_range_by_index(struct ctf_field_class_enum_mapping *mapping, + uint64_t index) +{ + BT_ASSERT_DBG(mapping); + BT_ASSERT_DBG(index < mapping->ranges->len); + return &bt_g_array_index(mapping->ranges, struct ctf_range, index); +} + +static inline struct ctf_field_class_enum_mapping * +ctf_field_class_enum_borrow_mapping_by_index(struct ctf_field_class_enum *fc, uint64_t index) +{ + BT_ASSERT_DBG(fc); + BT_ASSERT_DBG(index < fc->mappings->len); + return &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, index); +} + +static inline struct ctf_field_class_enum_mapping * +ctf_field_class_enum_borrow_mapping_by_label(struct ctf_field_class_enum *fc, const char *label) +{ + struct ctf_field_class_enum_mapping *ret_mapping = NULL; + uint64_t i; + + BT_ASSERT_DBG(fc); + BT_ASSERT_DBG(label); + + for (i = 0; i < fc->mappings->len; i++) { + struct ctf_field_class_enum_mapping *mapping = + ctf_field_class_enum_borrow_mapping_by_index(fc, i); + + if (strcmp(mapping->label->str, label) == 0) { + ret_mapping = mapping; + goto end; + } + } + +end: + return ret_mapping; +} + +static inline void ctf_field_class_enum_map_range(struct ctf_field_class_enum *fc, + const char *label, uint64_t u_lower, + uint64_t u_upper) +{ + struct ctf_field_class_enum_mapping *mapping = NULL; + struct ctf_range range = { + .lower = + { + .u = u_lower, + }, + .upper = + { + .u = u_upper, + }, + }; + uint64_t i; + + BT_ASSERT(fc); + BT_ASSERT(label); + + for (i = 0; i < fc->mappings->len; i++) { + mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, i); + + if (strcmp(mapping->label->str, label) == 0) { + break; + } + } + + if (i == fc->mappings->len) { + mapping = NULL; + } + + if (!mapping) { + g_array_set_size(fc->mappings, fc->mappings->len + 1); + mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, fc->mappings->len - 1); + _ctf_field_class_enum_mapping_init(mapping); + g_string_assign(mapping->label, label); + } + + g_array_append_val(mapping->ranges, range); +} + +static inline struct ctf_named_field_class * +ctf_field_class_struct_borrow_member_by_index(struct ctf_field_class_struct *fc, uint64_t index) +{ + BT_ASSERT_DBG(fc); + BT_ASSERT_DBG(index < fc->members->len); + return &bt_g_array_index(fc->members, struct ctf_named_field_class, index); +} + +static inline struct ctf_named_field_class * +ctf_field_class_struct_borrow_member_by_name(struct ctf_field_class_struct *fc, const char *name) +{ + uint64_t i; + struct ctf_named_field_class *ret_named_fc = NULL; + + BT_ASSERT_DBG(fc); + BT_ASSERT_DBG(name); + + for (i = 0; i < fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(fc, i); + + if (strcmp(name, named_fc->name->str) == 0) { + ret_named_fc = named_fc; + goto end; + } + } + +end: + return ret_named_fc; +} + +static inline struct ctf_field_class * +ctf_field_class_struct_borrow_member_field_class_by_name(struct ctf_field_class_struct *struct_fc, + const char *name) +{ + struct ctf_named_field_class *named_fc = NULL; + struct ctf_field_class *fc = NULL; + + if (!struct_fc) { + goto end; + } + + named_fc = ctf_field_class_struct_borrow_member_by_name(struct_fc, name); + if (!named_fc) { + goto end; + } + + fc = named_fc->fc; + +end: + return fc; +} + +static inline struct ctf_field_class_int * +ctf_field_class_struct_borrow_member_int_field_class_by_name( + struct ctf_field_class_struct *struct_fc, const char *name) +{ + ctf_field_class *member_fc = + ctf_field_class_struct_borrow_member_field_class_by_name(struct_fc, name); + + if (!member_fc) { + return nullptr; + } + + if (member_fc->type != CTF_FIELD_CLASS_TYPE_INT && + member_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + return nullptr; + } + + return ctf_field_class_as_int(member_fc); +} + +static inline void _ctf_named_field_class_unescape_orig_name(struct ctf_named_field_class *named_fc) +{ + const char *name = named_fc->orig_name->str; + + if (name[0] == '_') { + name++; + } + + g_string_assign(named_fc->name, name); +} + +static inline void ctf_field_class_struct_append_member(struct ctf_field_class_struct *fc, + const char *orig_name, + struct ctf_field_class *member_fc) +{ + struct ctf_named_field_class *named_fc; + + BT_ASSERT(fc); + BT_ASSERT(orig_name); + g_array_set_size(fc->members, fc->members->len + 1); + + named_fc = &bt_g_array_index(fc->members, struct ctf_named_field_class, fc->members->len - 1); + _ctf_named_field_class_init(named_fc); + g_string_assign(named_fc->orig_name, orig_name); + _ctf_named_field_class_unescape_orig_name(named_fc); + named_fc->fc = member_fc; + + if (member_fc->alignment > fc->base.alignment) { + fc->base.alignment = member_fc->alignment; + } +} + +static inline struct ctf_named_field_class * +ctf_field_class_variant_borrow_option_by_index(struct ctf_field_class_variant *fc, uint64_t index) +{ + BT_ASSERT_DBG(fc); + BT_ASSERT_DBG(index < fc->options->len); + return &bt_g_array_index(fc->options, struct ctf_named_field_class, index); +} + +static inline struct ctf_named_field_class * +ctf_field_class_variant_borrow_option_by_name(struct ctf_field_class_variant *fc, const char *name) +{ + uint64_t i; + struct ctf_named_field_class *ret_named_fc = NULL; + + BT_ASSERT_DBG(fc); + BT_ASSERT_DBG(name); + + for (i = 0; i < fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(fc, i); + + if (strcmp(name, named_fc->name->str) == 0) { + ret_named_fc = named_fc; + goto end; + } + } + +end: + return ret_named_fc; +} + +static inline struct ctf_field_class_variant_range * +ctf_field_class_variant_borrow_range_by_index(struct ctf_field_class_variant *fc, uint64_t index) +{ + BT_ASSERT_DBG(fc); + BT_ASSERT_DBG(index < fc->ranges->len); + return &bt_g_array_index(fc->ranges, struct ctf_field_class_variant_range, index); +} + +static inline void ctf_field_class_variant_append_option(struct ctf_field_class_variant *fc, + const char *orig_name, + struct ctf_field_class *option_fc) +{ + struct ctf_named_field_class *named_fc; + + BT_ASSERT(fc); + BT_ASSERT(orig_name); + g_array_set_size(fc->options, fc->options->len + 1); + + named_fc = &bt_g_array_index(fc->options, struct ctf_named_field_class, fc->options->len - 1); + _ctf_named_field_class_init(named_fc); + g_string_assign(named_fc->orig_name, orig_name); + _ctf_named_field_class_unescape_orig_name(named_fc); + named_fc->fc = option_fc; +} + +static inline void ctf_field_class_variant_set_tag_field_class(struct ctf_field_class_variant *fc, + struct ctf_field_class_enum *tag_fc) +{ + uint64_t option_i; + + BT_ASSERT(fc); + BT_ASSERT(tag_fc); + fc->tag_fc = tag_fc; + + for (option_i = 0; option_i < fc->options->len; option_i++) { + uint64_t range_i; + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(fc, option_i); + struct ctf_field_class_enum_mapping *mapping; + + mapping = ctf_field_class_enum_borrow_mapping_by_label(tag_fc, named_fc->orig_name->str); + if (!mapping) { + continue; + } + + for (range_i = 0; range_i < mapping->ranges->len; range_i++) { + struct ctf_range *range = + ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i); + struct ctf_field_class_variant_range var_range; + + var_range.range = *range; + var_range.option_index = option_i; + g_array_append_val(fc->ranges, var_range); + } + } +} + +static inline struct ctf_field_class * +ctf_field_class_compound_borrow_field_class_by_index(struct ctf_field_class *comp_fc, + uint64_t index) +{ + struct ctf_field_class *fc = NULL; + + switch (comp_fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_named_field_class *named_fc = ctf_field_class_struct_borrow_member_by_index( + (struct ctf_field_class_struct *) comp_fc, index); + + BT_ASSERT_DBG(named_fc); + fc = named_fc->fc; + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_named_field_class *named_fc = ctf_field_class_variant_borrow_option_by_index( + (struct ctf_field_class_variant *) comp_fc, index); + + BT_ASSERT_DBG(named_fc); + fc = named_fc->fc; + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + { + struct ctf_field_class_array_base *array_fc = (struct ctf_field_class_array_base *) comp_fc; + + fc = array_fc->elem_fc; + break; + } + default: + break; + } + + return fc; +} + +static inline uint64_t ctf_field_class_compound_get_field_class_count(struct ctf_field_class *fc) +{ + uint64_t field_count; + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = (struct ctf_field_class_struct *) fc; + + field_count = struct_fc->members->len; + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) fc; + + field_count = var_fc->options->len; + break; + } + case CTF_FIELD_CLASS_TYPE_ARRAY: + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + /* + * Array and sequence types always contain a single + * member (the element type). + */ + field_count = 1; + break; + default: + bt_common_abort(); + } + + return field_count; +} + +static inline int64_t +ctf_field_class_compound_get_field_class_index_from_orig_name(struct ctf_field_class *fc, + const char *orig_name) +{ + int64_t ret_index = -1; + uint64_t i; + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_STRUCT: + { + struct ctf_field_class_struct *struct_fc = (struct ctf_field_class_struct *) fc; + + for (i = 0; i < struct_fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + + if (strcmp(orig_name, named_fc->orig_name->str) == 0) { + ret_index = (int64_t) i; + goto end; + } + } + + break; + } + case CTF_FIELD_CLASS_TYPE_VARIANT: + { + struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) fc; + + for (i = 0; i < var_fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + ctf_field_class_variant_borrow_option_by_index(var_fc, i); + + if (strcmp(orig_name, named_fc->orig_name->str) == 0) { + ret_index = (int64_t) i; + goto end; + } + } + + break; + } + default: + break; + } + +end: + return ret_index; +} + +static inline void ctf_field_path_append_index(struct ctf_field_path *fp, int64_t index) +{ + BT_ASSERT(fp); + g_array_append_val(fp->path, index); +} + +static inline int64_t ctf_field_path_borrow_index_by_index(struct ctf_field_path *fp, + uint64_t index) +{ + BT_ASSERT_DBG(fp); + BT_ASSERT_DBG(index < fp->path->len); + return bt_g_array_index(fp->path, int64_t, index); +} + +static inline void ctf_field_path_clear(struct ctf_field_path *fp) +{ + BT_ASSERT(fp); + g_array_set_size(fp->path, 0); +} + +static inline const char *ctf_scope_string(enum ctf_scope scope) +{ + switch (scope) { + case CTF_SCOPE_PACKET_HEADER: + return "PACKET_HEADER"; + case CTF_SCOPE_PACKET_CONTEXT: + return "PACKET_CONTEXT"; + case CTF_SCOPE_EVENT_HEADER: + return "EVENT_HEADER"; + case CTF_SCOPE_EVENT_COMMON_CONTEXT: + return "EVENT_COMMON_CONTEXT"; + case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: + return "EVENT_SPECIFIC_CONTEXT"; + case CTF_SCOPE_EVENT_PAYLOAD: + return "EVENT_PAYLOAD"; + default: + bt_common_abort(); + } +} + +static inline GString *ctf_field_path_string(struct ctf_field_path *path) +{ + GString *str = g_string_new(NULL); + uint64_t i; + + BT_ASSERT(path); + + if (!str) { + goto end; + } + + g_string_append_printf(str, "[%s", ctf_scope_string(path->root)); + + for (i = 0; i < path->path->len; i++) { + g_string_append_printf(str, ", %" PRId64, ctf_field_path_borrow_index_by_index(path, i)); + } + + g_string_append(str, "]"); + +end: + return str; +} + +static inline struct ctf_field_class * +ctf_field_path_borrow_field_class(struct ctf_field_path *field_path, struct ctf_trace_class *tc, + struct ctf_stream_class *sc, struct ctf_event_class *ec) +{ + uint64_t i; + struct ctf_field_class *fc; + + switch (field_path->root) { + case CTF_SCOPE_PACKET_HEADER: + fc = tc->packet_header_fc; + break; + case CTF_SCOPE_PACKET_CONTEXT: + fc = sc->packet_context_fc; + break; + case CTF_SCOPE_EVENT_HEADER: + fc = sc->event_header_fc; + break; + case CTF_SCOPE_EVENT_COMMON_CONTEXT: + fc = sc->event_common_context_fc; + break; + case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT: + fc = ec->spec_context_fc; + break; + case CTF_SCOPE_EVENT_PAYLOAD: + fc = ec->payload_fc; + break; + default: + bt_common_abort(); + } + + BT_ASSERT_DBG(fc); + + for (i = 0; i < field_path->path->len; i++) { + int64_t child_index = ctf_field_path_borrow_index_by_index(field_path, i); + struct ctf_field_class *child_fc = + ctf_field_class_compound_borrow_field_class_by_index(fc, child_index); + BT_ASSERT_DBG(child_fc); + fc = child_fc; + } + + BT_ASSERT_DBG(fc); + return fc; +} + +static inline struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc); + +static inline void ctf_field_class_bit_array_copy_content(struct ctf_field_class_bit_array *dst_fc, + struct ctf_field_class_bit_array *src_fc) +{ + BT_ASSERT(dst_fc); + BT_ASSERT(src_fc); + dst_fc->byte_order = src_fc->byte_order; + dst_fc->size = src_fc->size; +} + +static inline void ctf_field_class_int_copy_content(struct ctf_field_class_int *dst_fc, + struct ctf_field_class_int *src_fc) +{ + ctf_field_class_bit_array_copy_content(&dst_fc->base, &src_fc->base); + dst_fc->meaning = src_fc->meaning; + dst_fc->is_signed = src_fc->is_signed; + dst_fc->disp_base = src_fc->disp_base; + dst_fc->encoding = src_fc->encoding; + dst_fc->mapped_clock_class = src_fc->mapped_clock_class; + dst_fc->storing_index = src_fc->storing_index; +} + +static inline struct ctf_field_class_int *_ctf_field_class_int_copy(struct ctf_field_class_int *fc) +{ + struct ctf_field_class_int *copy_fc = ctf_field_class_int_create(); + + BT_ASSERT(copy_fc); + ctf_field_class_int_copy_content(copy_fc, fc); + return copy_fc; +} + +static inline struct ctf_field_class_enum * +_ctf_field_class_enum_copy(struct ctf_field_class_enum *fc) +{ + struct ctf_field_class_enum *copy_fc = ctf_field_class_enum_create(); + uint64_t i; + + BT_ASSERT(copy_fc); + ctf_field_class_int_copy_content(©_fc->base, &fc->base); + + for (i = 0; i < fc->mappings->len; i++) { + uint64_t range_i; + + struct ctf_field_class_enum_mapping *mapping = + &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, i); + + for (range_i = 0; range_i < mapping->ranges->len; range_i++) { + struct ctf_range *range = &bt_g_array_index(mapping->ranges, struct ctf_range, range_i); + + ctf_field_class_enum_map_range(copy_fc, mapping->label->str, range->lower.u, + range->upper.u); + } + } + + return copy_fc; +} + +static inline struct ctf_field_class_float * +_ctf_field_class_float_copy(struct ctf_field_class_float *fc) +{ + struct ctf_field_class_float *copy_fc = ctf_field_class_float_create(); + + BT_ASSERT(copy_fc); + ctf_field_class_bit_array_copy_content(©_fc->base, &fc->base); + return copy_fc; +} + +static inline struct ctf_field_class_string * +_ctf_field_class_string_copy(struct ctf_field_class_string *) +{ + struct ctf_field_class_string *copy_fc = ctf_field_class_string_create(); + + BT_ASSERT(copy_fc); + return copy_fc; +} + +static inline struct ctf_field_class_struct * +_ctf_field_class_struct_copy(struct ctf_field_class_struct *fc) +{ + struct ctf_field_class_struct *copy_fc = ctf_field_class_struct_create(); + uint64_t i; + + BT_ASSERT(copy_fc); + + for (i = 0; i < fc->members->len; i++) { + struct ctf_named_field_class *named_fc = + &bt_g_array_index(fc->members, struct ctf_named_field_class, i); + + ctf_field_class_struct_append_member(copy_fc, named_fc->name->str, + ctf_field_class_copy(named_fc->fc)); + } + + return copy_fc; +} + +static inline void ctf_field_path_copy_content(struct ctf_field_path *dst_fp, + struct ctf_field_path *src_fp) +{ + uint64_t i; + + BT_ASSERT(dst_fp); + BT_ASSERT(src_fp); + dst_fp->root = src_fp->root; + ctf_field_path_clear(dst_fp); + + for (i = 0; i < src_fp->path->len; i++) { + int64_t index = ctf_field_path_borrow_index_by_index(src_fp, i); + + ctf_field_path_append_index(dst_fp, index); + } +} + +static inline struct ctf_field_class_variant * +_ctf_field_class_variant_copy(struct ctf_field_class_variant *fc) +{ + struct ctf_field_class_variant *copy_fc = ctf_field_class_variant_create(); + uint64_t i; + + BT_ASSERT(copy_fc); + + for (i = 0; i < fc->options->len; i++) { + struct ctf_named_field_class *named_fc = + &bt_g_array_index(fc->options, struct ctf_named_field_class, i); + + ctf_field_class_variant_append_option(copy_fc, named_fc->name->str, + ctf_field_class_copy(named_fc->fc)); + } + + for (i = 0; i < fc->ranges->len; i++) { + struct ctf_field_class_variant_range *range = + &bt_g_array_index(fc->ranges, struct ctf_field_class_variant_range, i); + + g_array_append_val(copy_fc->ranges, *range); + } + + ctf_field_path_copy_content(©_fc->tag_path, &fc->tag_path); + g_string_assign(copy_fc->tag_ref, fc->tag_ref->str); + copy_fc->stored_tag_index = fc->stored_tag_index; + return copy_fc; +} + +static inline void +ctf_field_class_array_base_copy_content(struct ctf_field_class_array_base *dst_fc, + struct ctf_field_class_array_base *src_fc) +{ + BT_ASSERT(dst_fc); + BT_ASSERT(src_fc); + dst_fc->elem_fc = ctf_field_class_copy(src_fc->elem_fc); + dst_fc->is_text = src_fc->is_text; +} + +static inline struct ctf_field_class_array * +_ctf_field_class_array_copy(struct ctf_field_class_array *fc) +{ + struct ctf_field_class_array *copy_fc = ctf_field_class_array_create(); + + BT_ASSERT(copy_fc); + ctf_field_class_array_base_copy_content(©_fc->base, &fc->base); + copy_fc->length = fc->length; + return copy_fc; +} + +static inline struct ctf_field_class_sequence * +_ctf_field_class_sequence_copy(struct ctf_field_class_sequence *fc) +{ + struct ctf_field_class_sequence *copy_fc = ctf_field_class_sequence_create(); + + BT_ASSERT(copy_fc); + ctf_field_class_array_base_copy_content(©_fc->base, &fc->base); + ctf_field_path_copy_content(©_fc->length_path, &fc->length_path); + g_string_assign(copy_fc->length_ref, fc->length_ref->str); + copy_fc->stored_length_index = fc->stored_length_index; + return copy_fc; +} + +static inline struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc) +{ + struct ctf_field_class *copy_fc = NULL; + + if (!fc) { + goto end; + } + + /* + * Translation should not have happened yet. + */ + BT_ASSERT(!fc->ir_fc); + + switch (fc->type) { + case CTF_FIELD_CLASS_TYPE_INT: + copy_fc = &_ctf_field_class_int_copy(ctf_field_class_as_int(fc))->base.base; + break; + case CTF_FIELD_CLASS_TYPE_ENUM: + copy_fc = &_ctf_field_class_enum_copy(ctf_field_class_as_enum(fc))->base.base.base; + break; + case CTF_FIELD_CLASS_TYPE_FLOAT: + copy_fc = &_ctf_field_class_float_copy(ctf_field_class_as_float(fc))->base.base; + break; + case CTF_FIELD_CLASS_TYPE_STRING: + copy_fc = &_ctf_field_class_string_copy(ctf_field_class_as_string(fc))->base; + break; + case CTF_FIELD_CLASS_TYPE_STRUCT: + copy_fc = &_ctf_field_class_struct_copy(ctf_field_class_as_struct(fc))->base; + break; + case CTF_FIELD_CLASS_TYPE_ARRAY: + copy_fc = &_ctf_field_class_array_copy(ctf_field_class_as_array(fc))->base.base; + break; + case CTF_FIELD_CLASS_TYPE_SEQUENCE: + copy_fc = &_ctf_field_class_sequence_copy(ctf_field_class_as_sequence(fc))->base.base; + break; + case CTF_FIELD_CLASS_TYPE_VARIANT: + copy_fc = &_ctf_field_class_variant_copy(ctf_field_class_as_variant(fc))->base; + break; + default: + bt_common_abort(); + } + + copy_fc->type = fc->type; + copy_fc->alignment = fc->alignment; + copy_fc->in_ir = fc->in_ir; + +end: + return copy_fc; +} + +static inline struct ctf_event_class *ctf_event_class_create(void) +{ + struct ctf_event_class *ec = g_new0(struct ctf_event_class, 1); + + BT_ASSERT(ec); + ec->name = g_string_new(NULL); + BT_ASSERT(ec->name); + ec->emf_uri = g_string_new(NULL); + BT_ASSERT(ec->emf_uri); + ec->is_log_level_set = false; + return ec; +} + +static inline void ctf_event_class_set_log_level(struct ctf_event_class *ec, + enum bt_event_class_log_level log_level) +{ + BT_ASSERT(ec); + ec->log_level = log_level; + ec->is_log_level_set = true; +} + +static inline void ctf_event_class_destroy(struct ctf_event_class *ec) +{ + if (!ec) { + return; + } + + if (ec->name) { + g_string_free(ec->name, TRUE); + } + + if (ec->emf_uri) { + g_string_free(ec->emf_uri, TRUE); + } + + ctf_field_class_destroy(ec->spec_context_fc); + ctf_field_class_destroy(ec->payload_fc); + g_free(ec); +} + +static inline struct ctf_stream_class *ctf_stream_class_create(void) +{ + struct ctf_stream_class *sc = g_new0(struct ctf_stream_class, 1); + + BT_ASSERT(sc); + sc->event_classes = g_ptr_array_new_with_free_func((GDestroyNotify) ctf_event_class_destroy); + BT_ASSERT(sc->event_classes); + sc->event_classes_by_id = g_hash_table_new(g_direct_hash, g_direct_equal); + BT_ASSERT(sc->event_classes_by_id); + return sc; +} + +static inline void ctf_stream_class_destroy(struct ctf_stream_class *sc) +{ + if (!sc) { + return; + } + + if (sc->event_classes) { + g_ptr_array_free(sc->event_classes, TRUE); + } + + if (sc->event_classes_by_id) { + g_hash_table_destroy(sc->event_classes_by_id); + } + + ctf_field_class_destroy(sc->packet_context_fc); + ctf_field_class_destroy(sc->event_header_fc); + ctf_field_class_destroy(sc->event_common_context_fc); + g_free(sc); +} + +static inline void ctf_stream_class_append_event_class(struct ctf_stream_class *sc, + struct ctf_event_class *ec) +{ + g_ptr_array_add(sc->event_classes, ec); + g_hash_table_insert(sc->event_classes_by_id, GUINT_TO_POINTER((guint) ec->id), ec); +} + +static inline struct ctf_event_class * +ctf_stream_class_borrow_event_class_by_id(struct ctf_stream_class *sc, uint64_t type) +{ + BT_ASSERT_DBG(sc); + return (struct ctf_event_class *) g_hash_table_lookup(sc->event_classes_by_id, + GUINT_TO_POINTER((guint) type)); +} + +static inline void _ctf_trace_class_env_entry_init(struct ctf_trace_class_env_entry *entry) +{ + BT_ASSERT(entry); + entry->name = g_string_new(NULL); + BT_ASSERT(entry->name); + entry->value.str = g_string_new(NULL); + BT_ASSERT(entry->value.str); +} + +static inline void _ctf_trace_class_env_entry_fini(struct ctf_trace_class_env_entry *entry) +{ + BT_ASSERT(entry); + + if (entry->name) { + g_string_free(entry->name, TRUE); + } + + if (entry->value.str) { + g_string_free(entry->value.str, TRUE); + } +} + +static inline struct ctf_clock_class *ctf_clock_class_create(void) +{ + struct ctf_clock_class *cc = g_new0(struct ctf_clock_class, 1); + + BT_ASSERT(cc); + cc->name = g_string_new(NULL); + BT_ASSERT(cc->name); + cc->description = g_string_new(NULL); + BT_ASSERT(cc->description); + return cc; +} + +static inline void ctf_clock_class_destroy(struct ctf_clock_class *cc) +{ + if (!cc) { + return; + } + + if (cc->name) { + g_string_free(cc->name, TRUE); + } + + if (cc->description) { + g_string_free(cc->description, TRUE); + } + + bt_clock_class_put_ref(cc->ir_cc); + g_free(cc); +} + +static inline struct ctf_trace_class *ctf_trace_class_create(void) +{ + struct ctf_trace_class *tc = g_new0(struct ctf_trace_class, 1); + + BT_ASSERT(tc); + tc->default_byte_order = CTF_BYTE_ORDER_UNKNOWN; + tc->clock_classes = g_ptr_array_new_with_free_func((GDestroyNotify) ctf_clock_class_destroy); + BT_ASSERT(tc->clock_classes); + tc->stream_classes = g_ptr_array_new_with_free_func((GDestroyNotify) ctf_stream_class_destroy); + BT_ASSERT(tc->stream_classes); + tc->env_entries = g_array_new(FALSE, TRUE, sizeof(struct ctf_trace_class_env_entry)); + return tc; +} + +static inline void ctf_trace_class_destroy(struct ctf_trace_class *tc) +{ + if (!tc) { + return; + } + + ctf_field_class_destroy(tc->packet_header_fc); + + if (tc->clock_classes) { + g_ptr_array_free(tc->clock_classes, TRUE); + } + + if (tc->stream_classes) { + g_ptr_array_free(tc->stream_classes, TRUE); + } + + if (tc->env_entries) { + uint64_t i; + + for (i = 0; i < tc->env_entries->len; i++) { + struct ctf_trace_class_env_entry *entry = + &bt_g_array_index(tc->env_entries, struct ctf_trace_class_env_entry, i); + + _ctf_trace_class_env_entry_fini(entry); + } + + g_array_free(tc->env_entries, TRUE); + } + + g_free(tc); +} + +static inline void ctf_trace_class_append_env_entry(struct ctf_trace_class *tc, const char *name, + enum ctf_trace_class_env_entry_type type, + const char *str_value, int64_t i_value) +{ + struct ctf_trace_class_env_entry *entry; + + BT_ASSERT(tc); + BT_ASSERT(name); + g_array_set_size(tc->env_entries, tc->env_entries->len + 1); + + entry = &bt_g_array_index(tc->env_entries, struct ctf_trace_class_env_entry, + tc->env_entries->len - 1); + entry->type = type; + _ctf_trace_class_env_entry_init(entry); + g_string_assign(entry->name, name); + + if (str_value) { + g_string_assign(entry->value.str, str_value); + } + + entry->value.i = i_value; +} + +static inline struct ctf_stream_class * +ctf_trace_class_borrow_stream_class_by_id(struct ctf_trace_class *tc, uint64_t id) +{ + uint64_t i; + struct ctf_stream_class *ret_sc = NULL; + + BT_ASSERT_DBG(tc); + + for (i = 0; i < tc->stream_classes->len; i++) { + struct ctf_stream_class *sc = (struct ctf_stream_class *) tc->stream_classes->pdata[i]; + + if (sc->id == id) { + ret_sc = sc; + goto end; + } + } + +end: + return ret_sc; +} + +static inline struct ctf_clock_class * +ctf_trace_class_borrow_clock_class_by_name(struct ctf_trace_class *tc, const char *name) +{ + uint64_t i; + struct ctf_clock_class *ret_cc = NULL; + + BT_ASSERT_DBG(tc); + BT_ASSERT_DBG(name); + + for (i = 0; i < tc->clock_classes->len; i++) { + struct ctf_clock_class *cc = (struct ctf_clock_class *) tc->clock_classes->pdata[i]; + + BT_ASSERT_DBG(cc->name); + if (strcmp(cc->name->str, name) == 0) { + ret_cc = cc; + goto end; + } + } + +end: + return ret_cc; +} + +static inline struct ctf_trace_class_env_entry * +ctf_trace_class_borrow_env_entry_by_index(struct ctf_trace_class *tc, uint64_t index) +{ + BT_ASSERT_DBG(tc); + BT_ASSERT_DBG(index < tc->env_entries->len); + return &bt_g_array_index(tc->env_entries, struct ctf_trace_class_env_entry, index); +} + +static inline struct ctf_trace_class_env_entry * +ctf_trace_class_borrow_env_entry_by_name(struct ctf_trace_class *tc, const char *name) +{ + struct ctf_trace_class_env_entry *ret_entry = NULL; + uint64_t i; + + BT_ASSERT_DBG(tc); + BT_ASSERT_DBG(name); + + for (i = 0; i < tc->env_entries->len; i++) { + struct ctf_trace_class_env_entry *env_entry = + ctf_trace_class_borrow_env_entry_by_index(tc, i); + + if (strcmp(env_entry->name->str, name) == 0) { + ret_entry = env_entry; + goto end; + } + } + +end: + return ret_entry; +} + +#endif /* _CTF_META_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp new file mode 100644 index 00000000..2150465b --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp @@ -0,0 +1,267 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2017 Philippe Proulx + */ + +#include +#include +#include +#include + +#include + +#define BT_COMP_LOG_SELF_COMP self_comp +#define BT_COMP_LOG_SELF_COMP_CLASS self_comp_class +#define BT_LOG_OUTPUT_LEVEL log_level +#define BT_LOG_TAG "PLUGIN/CTF/META/DECODER-DECODE-PACKET" +#include "logging.hpp" +#include "logging/comp-logging.h" + +#include "common/uuid.h" +#include "compat/memstream.h" + +#include "decoder-packetized-file-stream-to-buf.hpp" +#include "decoder.hpp" + +#define TSDL_MAGIC 0x75d11d57 + +struct ctf_metadata_decoder +{ + struct ctf_visitor_generate_ir *visitor; + bt_uuid_t uuid; + bool is_uuid_set; + int bo; + struct ctf_metadata_decoder_config config; +}; + +struct packet_header +{ + uint32_t magic; + bt_uuid_t uuid; + 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__)); + +static int decode_packet(FILE *in_fp, FILE *out_fp, int byte_order, bool *is_uuid_set, + uint8_t *uuid, bt_logging_level log_level, bt_self_component *self_comp, + bt_self_component_class *self_comp_class) +{ + struct packet_header header; + size_t readlen, writelen, toread; + uint8_t buf[512 + 1]; /* + 1 for debug-mode \0 */ + int ret = 0; + const long offset = ftell(in_fp); + + if (offset < 0) { + BT_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP, + "Failed to get current metadata file position", "."); + goto error; + } + BT_COMP_LOGD("Decoding metadata packet: offset=%ld", offset); + readlen = fread(&header, sizeof(header), 1, in_fp); + if (feof(in_fp) != 0) { + BT_COMP_LOGI("Reached end of file: offset=%ld", ftell(in_fp)); + goto end; + } + if (readlen < 1) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot decode metadata packet: offset=%ld", + offset); + 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) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Metadata packet compression is not supported as of this version: " + "compression-scheme=%u, offset=%ld", + (unsigned int) header.compression_scheme, offset); + goto error; + } + + if (header.encryption_scheme) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Metadata packet encryption is not supported as of this version: " + "encryption-scheme=%u, offset=%ld", + (unsigned int) header.encryption_scheme, offset); + goto error; + } + + if (header.checksum || header.checksum_scheme) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Metadata packet checksum verification is not supported as of this version: " + "checksum-scheme=%u, checksum=%x, offset=%ld", + (unsigned int) header.checksum_scheme, header.checksum, offset); + goto error; + } + + if (!ctf_metadata_decoder_is_packet_version_valid(header.major, header.minor)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid metadata packet version: " + "version=%u.%u, offset=%ld", + header.major, header.minor, offset); + goto error; + } + + /* Set expected trace UUID if not set; otherwise validate it */ + if (is_uuid_set) { + if (!*is_uuid_set) { + bt_uuid_copy(uuid, header.uuid); + *is_uuid_set = true; + } else if (bt_uuid_compare(header.uuid, uuid)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Metadata UUID mismatch between packets of the same stream: " + "packet-uuid=\"" BT_UUID_FMT "\", " + "expected-uuid=\"" BT_UUID_FMT "\", " + "offset=%ld", + BT_UUID_FMT_VALUES(header.uuid), BT_UUID_FMT_VALUES(uuid), offset); + goto error; + } + } + + if ((header.content_size / CHAR_BIT) < sizeof(header)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Bad metadata packet content size: content-size=%u, " + "offset=%ld", + header.content_size, offset); + goto error; + } + + toread = header.content_size / CHAR_BIT - sizeof(header); + + for (;;) { + size_t loop_read; + + loop_read = MIN(sizeof(buf) - 1, toread); + readlen = fread(buf, sizeof(uint8_t), loop_read, in_fp); + if (ferror(in_fp)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot read metadata packet buffer: " + "offset=%ld, read-size=%zu", + ftell(in_fp), loop_read); + goto error; + } + if (readlen > loop_read) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("fread returned more byte than expected: " + "read-size-asked=%zu, read-size-returned=%zu", + loop_read, readlen); + goto error; + } + + writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp); + if (writelen < readlen || ferror(out_fp)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot write decoded metadata text to buffer: " + "read-offset=%ld, write-size=%zu", + ftell(in_fp), readlen); + 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) { + BT_COMP_LOGW_STR("Missing padding at the end of the metadata stream."); + } + break; + } + } + + goto end; + +error: + ret = -1; + +end: + return ret; +} + +int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order, + bool *is_uuid_set, uint8_t *uuid, + bt_logging_level log_level, + bt_self_component *self_comp, + bt_self_component_class *self_comp_class) +{ + 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) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot open memory stream: %s.", strerror(errno)); + goto error; + } + + for (;;) { + if (feof(fp) != 0) { + break; + } + + tret = decode_packet(fp, out_fp, byte_order, is_uuid_set, uuid, log_level, self_comp, + self_comp_class); + if (tret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot decode packet: index=%zu", + packet_index); + goto error; + } + + packet_index++; + } + + /* Make sure the whole string ends with a null character */ + tret = fputc('\0', out_fp); + if (tret == EOF) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot append '\\0' to the decoded metadata buffer."); + goto error; + } + + /* Close stream, which also flushes the buffer */ + ret = bt_close_memstream(buf, &size, out_fp); + /* + * See fclose(3). Further access to out_fp after both success + * and error, even through another bt_close_memstream(), results + * in undefined behavior. Nullify out_fp to ensure we don't + * fclose it twice on error. + */ + out_fp = NULL; + if (ret < 0) { + BT_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP, "Cannot close memory stream", "."); + goto error; + } + + goto end; + +error: + ret = -1; + + if (out_fp) { + if (bt_close_memstream(buf, &size, out_fp)) { + BT_COMP_LOGE_ERRNO("Cannot close memory stream", "."); + } + } + + if (*buf) { + free(*buf); + *buf = NULL; + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp new file mode 100644 index 00000000..8d831536 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Efficios Inc. + */ + +#ifndef SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF +#define SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF + +#include + +#include + +#include + +int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order, + bool *is_uuid_set, uint8_t *uuid, + bt_logging_level log_level, + bt_self_component *self_comp, + bt_self_component_class *self_comp_class); + +#endif /* SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/decoder.cpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder.cpp new file mode 100644 index 00000000..deaeedb4 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder.cpp @@ -0,0 +1,473 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2017 Philippe Proulx + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define BT_COMP_LOG_SELF_COMP (mdec->config.self_comp) +#define BT_COMP_LOG_SELF_COMP_CLASS (mdec->config.self_comp_class) +#define BT_LOG_OUTPUT_LEVEL ((enum bt_log_level) mdec->config.log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/DECODER" +#include "logging.hpp" +#include "logging/comp-logging.h" + +#include "common/assert.h" +#include "common/uuid.h" +#include "compat/memstream.h" + +#include "ast.hpp" +#include "decoder-packetized-file-stream-to-buf.hpp" +#include "decoder.hpp" +#include "parser-wrap.hpp" +#include "scanner.hpp" + +#define TSDL_MAGIC 0x75d11d57 + +struct ctf_metadata_decoder +{ + struct ctf_scanner *scanner; + GString *text; + struct ctf_visitor_generate_ir *visitor; + bt_uuid_t uuid; + bool is_uuid_set; + int bo; + struct ctf_metadata_decoder_config config; + struct meta_log_config log_cfg; + bool has_checked_plaintext_signature; +}; + +struct packet_header +{ + uint32_t magic; + bt_uuid_t uuid; + 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__)); + +int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order, + bt_logging_level log_level, bt_self_component *self_comp) +{ + uint32_t magic; + size_t len; + int ret = 0; + + *is_packetized = false; + len = fread(&magic, sizeof(magic), 1, fp); + if (len != 1) { + BT_COMP_LOG_CUR_LVL( + BT_LOG_INFO, log_level, self_comp, + "Cannot read first metadata packet header: assuming the stream is not packetized."); + ret = -1; + goto end; + } + + if (byte_order) { + if (magic == TSDL_MAGIC) { + *is_packetized = true; + *byte_order = BYTE_ORDER; + } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) { + *is_packetized = true; + *byte_order = BYTE_ORDER == BIG_ENDIAN ? LITTLE_ENDIAN : BIG_ENDIAN; + } + } + +end: + rewind(fp); + + return ret; +} + +struct ctf_metadata_decoder * +ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config) +{ + struct ctf_metadata_decoder *mdec = g_new0(struct ctf_metadata_decoder, 1); + + BT_ASSERT(config); + BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, config->log_level, config->self_comp, + "Creating CTF metadata decoder: " + "clock-class-offset-s=%" PRId64 ", " + "clock-class-offset-ns=%" PRId64, + config->clock_class_offset_s, config->clock_class_offset_ns); + + if (!mdec) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, config->log_level, config->self_comp, + "Failed to allocate one CTF metadata decoder."); + goto end; + } + + mdec->log_cfg.log_level = config->log_level; + mdec->log_cfg.self_comp = config->self_comp; + mdec->log_cfg.self_comp_class = config->self_comp_class; + mdec->scanner = ctf_scanner_alloc(); + if (!mdec->scanner) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot allocate a metadata lexical scanner: " + "mdec-addr=%p", + mdec); + goto error; + } + + mdec->text = g_string_new(NULL); + if (!mdec->text) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one GString: " + "mdec-addr=%p", + mdec); + goto error; + } + + mdec->bo = -1; + mdec->config = *config; + mdec->visitor = ctf_visitor_generate_ir_create(config); + if (!mdec->visitor) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to create a CTF IR metadata AST visitor: " + "mdec-addr=%p", + mdec); + goto error; + } + + BT_COMP_LOGD("Creating CTF metadata decoder: " + "clock-class-offset-s=%" PRId64 ", " + "clock-class-offset-ns=%" PRId64 ", addr=%p", + config->clock_class_offset_s, config->clock_class_offset_ns, mdec); + goto end; + +error: + ctf_metadata_decoder_destroy(mdec); + mdec = NULL; + +end: + return mdec; +} + +void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *mdec) +{ + if (!mdec) { + return; + } + + if (mdec->scanner) { + ctf_scanner_free(mdec->scanner); + } + + if (mdec->text) { + g_string_free(mdec->text, TRUE); + } + + BT_COMP_LOGD("Destroying CTF metadata decoder: addr=%p", mdec); + ctf_visitor_generate_ir_destroy(mdec->visitor); + g_free(mdec); +} + +enum ctf_metadata_decoder_status +ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *mdec, FILE *fp) +{ + enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK; + int ret; + char *buf = NULL; + bool close_fp = false; + long start_pos = -1; + bool is_packetized; + + BT_ASSERT(mdec); + ret = ctf_metadata_decoder_is_packetized(fp, &is_packetized, &mdec->bo, mdec->config.log_level, + mdec->config.self_comp); + if (ret) { + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + if (is_packetized) { + BT_COMP_LOGI("Metadata stream is packetized: mdec-addr=%p", mdec); + ret = ctf_metadata_decoder_packetized_file_stream_to_buf( + fp, &buf, mdec->bo, &mdec->is_uuid_set, mdec->uuid, mdec->config.log_level, + mdec->config.self_comp, mdec->config.self_comp_class); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot decode packetized metadata packets to metadata text: " + "mdec-addr=%p, ret=%d", + mdec, ret); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + if (strlen(buf) == 0) { + /* An empty metadata packet is OK. */ + goto end; + } + + /* Convert the real file pointer to a memory file pointer */ + fp = bt_fmemopen(buf, strlen(buf), "rb"); + close_fp = true; + if (!fp) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot memory-open metadata buffer: %s: " + "mdec-addr=%p", + strerror(errno), mdec); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + } else if (!mdec->has_checked_plaintext_signature) { + unsigned int major, minor; + ssize_t nr_items; + const long init_pos = ftell(fp); + + BT_COMP_LOGI("Metadata stream is plain text: mdec-addr=%p", mdec); + + if (init_pos < 0) { + BT_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP, + "Failed to get current file position", "."); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + /* Check text-only metadata header and version */ + nr_items = fscanf(fp, "/* CTF %10u.%10u", &major, &minor); + if (nr_items < 2) { + BT_COMP_LOGW( + "Missing \"/* CTF major.minor\" signature in plain text metadata file stream: " + "mdec-addr=%p", + mdec); + } + + BT_COMP_LOGI("Found metadata stream version in signature: version=%u.%u", major, minor); + + if (!ctf_metadata_decoder_is_packet_version_valid(major, minor)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Invalid metadata version found in plain text signature: " + "version=%u.%u, mdec-addr=%p", + major, minor, mdec); + status = CTF_METADATA_DECODER_STATUS_INVAL_VERSION; + goto end; + } + + if (fseek(fp, init_pos, SEEK_SET)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot seek metadata file stream to initial position: %s: " + "mdec-addr=%p", + strerror(errno), mdec); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + mdec->has_checked_plaintext_signature = true; + } + +#if YYDEBUG + if (BT_LOG_ON_TRACE) { + yydebug = 1; + } +#endif + + /* Save the file's position: we'll seek back to append the plain text */ + BT_ASSERT(fp); + + if (mdec->config.keep_plain_text) { + start_pos = ftell(fp); + } + + /* Append the metadata text content */ + ret = ctf_scanner_append_ast(mdec->scanner, fp); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot create the metadata AST out of the metadata text: " + "mdec-addr=%p", + mdec); + status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; + goto end; + } + + /* We know it's complete: append plain text */ + if (mdec->config.keep_plain_text) { + BT_ASSERT(start_pos != -1); + ret = fseek(fp, start_pos, SEEK_SET); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to seek file: ret=%d, mdec-addr=%p", + ret, mdec); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + ret = bt_common_append_file_content_to_g_string(mdec->text, fp); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to append to current plain text: " + "ret=%d, mdec-addr=%p", + ret, mdec); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + } + + ret = ctf_visitor_semantic_check(0, &mdec->scanner->ast->root, &mdec->log_cfg); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Validation of the metadata semantics failed: " + "mdec-addr=%p", + mdec); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + if (mdec->config.create_trace_class) { + ret = ctf_visitor_generate_ir_visit_node(mdec->visitor, &mdec->scanner->ast->root); + switch (ret) { + case 0: + /* Success */ + break; + case -EINCOMPLETE: + BT_COMP_LOGD("While visiting metadata AST: incomplete data: " + "mdec-addr=%p", + mdec); + status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; + goto end; + default: + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Failed to visit AST node to create CTF IR objects: " + "mdec-addr=%p, ret=%d", + mdec, ret); + status = CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR; + goto end; + } + } + +end: +#if YYDEBUG + yydebug = 0; +#endif + + if (fp && close_fp) { + if (fclose(fp)) { + BT_COMP_LOGE("Cannot close metadata file stream: " + "mdec-addr=%p", + mdec); + } + } + + free(buf); + + return status; +} + +bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec) +{ + BT_ASSERT_DBG(mdec); + BT_ASSERT_DBG(mdec->config.create_trace_class); + return ctf_visitor_generate_ir_get_ir_trace_class(mdec->visitor); +} + +struct ctf_trace_class * +ctf_metadata_decoder_borrow_ctf_trace_class(struct ctf_metadata_decoder *mdec) +{ + BT_ASSERT_DBG(mdec); + BT_ASSERT_DBG(mdec->config.create_trace_class); + return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor); +} + +const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec) +{ + BT_ASSERT_DBG(mdec); + BT_ASSERT_DBG(mdec->config.keep_plain_text); + return mdec->text->str; +} + +int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec) +{ + BT_ASSERT_DBG(mdec); + return mdec->bo; +} + +int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid) +{ + int ret = 0; + + BT_ASSERT_DBG(mdec); + + if (!mdec->is_uuid_set) { + ret = -1; + goto end; + } + + bt_uuid_copy(uuid, mdec->uuid); + +end: + return ret; +} + +static enum ctf_metadata_decoder_status find_uuid_in_trace_decl(struct ctf_metadata_decoder *mdec, + struct ctf_node *trace_node, + bt_uuid_t uuid) +{ + enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK; + struct ctf_node *entry_node; + struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list; + char *left = NULL; + + bt_list_for_each_entry (entry_node, decl_list, siblings) { + if (entry_node->type == NODE_CTF_EXPRESSION) { + int ret; + + left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left); + if (!left) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot concatenate unary strings."); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + if (strcmp(left, "uuid") == 0) { + ret = ctf_ast_get_unary_uuid(&entry_node->u.ctf_expression.right, uuid, + mdec->config.log_level, mdec->config.self_comp); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid trace's `uuid` attribute."); + status = CTF_METADATA_DECODER_STATUS_ERROR; + goto end; + } + + goto end; + } + + g_free(left); + left = NULL; + } + } + + status = CTF_METADATA_DECODER_STATUS_NONE; + +end: + g_free(left); + return status; +} + +enum ctf_metadata_decoder_status +ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid) +{ + enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; + struct ctf_node *root_node = &mdec->scanner->ast->root; + struct ctf_node *trace_node; + + if (!root_node) { + status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; + goto end; + } + + trace_node = bt_list_entry(root_node->u.root.trace.next, struct ctf_node, siblings); + if (!trace_node) { + status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; + goto end; + } + + status = find_uuid_in_trace_decl(mdec, trace_node, uuid); + +end: + return status; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/decoder.hpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder.hpp new file mode 100644 index 00000000..d4385f4c --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder.hpp @@ -0,0 +1,161 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2017 Philippe Proulx + */ + +#ifndef _METADATA_DECODER_H +#define _METADATA_DECODER_H + +#include +#include + +#include + +#include "common/uuid.h" + +/* CTF metadata decoder status */ +enum ctf_metadata_decoder_status +{ + CTF_METADATA_DECODER_STATUS_OK = 0, + CTF_METADATA_DECODER_STATUS_NONE = 1, + 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, +}; + +/* Decoding configuration */ +struct ctf_metadata_decoder_config +{ + /* Active log level to use */ + bt_logging_level log_level; + + /* + * Component or component class to use for logging (exactly one of + * them must be non-`NULL`); weak + */ + bt_self_component *self_comp; + bt_self_component_class *self_comp_class; + + /* Additional clock class offset to apply */ + int64_t clock_class_offset_s; + int64_t clock_class_offset_ns; + bool force_clock_class_origin_unix_epoch; + + /* True to create trace class objects */ + bool create_trace_class; + + /* + * True to keep the plain text when content is appended with + * ctf_metadata_decoder_append_content(). + */ + bool keep_plain_text; +}; + +/* + * Creates a CTF metadata decoder. + * + * Returns `NULL` on error. + */ +struct ctf_metadata_decoder * +ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config); + +/* + * Destroys a CTF metadata decoder that you created with + * ctf_metadata_decoder_create(). + */ +void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *metadata_decoder); + +/* + * Appends content to the metadata decoder. + * + * This function reads the metadata from the current position of `fp` + * until the end of this file stream. + * + * The metadata can be packetized or not. + * + * The metadata chunk needs to be complete and lexically 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 everything goes as expected, this function returns + * `CTF_METADATA_DECODER_STATUS_OK`. + */ +enum ctf_metadata_decoder_status +ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *metadata_decoder, FILE *fp); + +/* + * Returns the trace IR trace class of this metadata decoder (new + * reference). + * + * Returns `NULL` if there's none yet or if the metadata decoder is not + * configured to create trace classes. + */ +bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec); + +/* + * Returns the CTF IR trace class of this metadata decoder. + * + * Returns `NULL` if there's none yet or if the metadata decoder is not + * configured to create trace classes. + */ +struct ctf_trace_class * +ctf_metadata_decoder_borrow_ctf_trace_class(struct ctf_metadata_decoder *mdec); + +/* + * Checks whether or not a given metadata file stream `fp` is + * packetized, setting `is_packetized` accordingly on success. On + * success, also sets `*byte_order` to the byte order of the first + * packet. + * + * This function uses `log_level` and `self_comp` for logging purposes. + * `self_comp` can be `NULL` if not available. + */ +int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order, + bt_logging_level log_level, bt_self_component *self_comp); + +/* + * Returns the byte order of the decoder's metadata stream as set by the + * last call to ctf_metadata_decoder_append_content(). + * + * Returns -1 if unknown (plain text content). + */ +int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec); + +/* + * Returns the UUID of the decoder's metadata stream as set by the last + * call to ctf_metadata_decoder_append_content(). + */ +int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid); + +/* + * Returns the UUID of the decoder's trace class, if available. + * + * Returns: + * + * * `CTF_METADATA_DECODER_STATUS_OK`: success. + * * `CTF_METADATA_DECODER_STATUS_NONE`: no UUID. + * * `CTF_METADATA_DECODER_STATUS_INCOMPLETE`: missing metadata content. + */ +enum ctf_metadata_decoder_status +ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid); + +/* + * Returns the metadata decoder's current metadata text. + */ +const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec); + +static inline bool ctf_metadata_decoder_is_packet_version_valid(unsigned int major, + unsigned int minor) +{ + return major == 1 && minor == 8; +} + +#endif /* _METADATA_DECODER_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/lexer.lpp b/src/plugins/ctf/common/src/metadata/tsdl/lexer.lpp new file mode 100644 index 00000000..0f6070b5 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/lexer.lpp @@ -0,0 +1,121 @@ +%{ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * + * Common Trace Formal Lexer + */ + +#include +#include + +#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level +#define BT_LOG_TAG "PLUGIN-CTF-METADATA-LEXER" +#include "plugins/ctf/common/src/metadata/tsdl/logging.hpp" + +#include "plugins/ctf/common/src/metadata/tsdl/scanner.hpp" +#include "plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp" +#include "plugins/ctf/common/src/metadata/tsdl/ast.hpp" + +#define YY_FATAL_ERROR(_msg) BT_LOGF_STR(_msg) + +#define PARSE_INTEGER_LITERAL(base) \ + do { \ + errno = 0; \ + yylval->ull = strtoull(yytext, NULL, base); \ + if (errno) { \ + _BT_LOGE_APPEND_CAUSE_LINENO(yylineno, \ + "Cannot parser constant integer: " \ + "base=%d, text=\"%s\"", base, yytext); \ + return CTF_ERROR; \ + } \ + } while (0) +%} + +%x comment_ml comment_sl string_lit char_const +%option reentrant yylineno noyywrap bison-bridge +%option extra-type="struct ctf_scanner *" + /* bison-locations */ +INTEGER_SUFFIX (U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu) +DIGIT [0-9] +NONDIGIT [a-zA-Z_] +HEXDIGIT [0-9A-Fa-f] +OCTALDIGIT [0-7] +UCHARLOWERCASE \\u{HEXDIGIT}{4} +UCHARUPPERCASE \\U{HEXDIGIT}{8} +ID_NONDIGIT {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE} +IDENTIFIER {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})* +%% + + /* + * Using start conditions to deal with comments + * and strings. + */ + +"/*" BEGIN(comment_ml); +[^*\n]* /* eat anything that's not a '*' */ +"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ +\n +"*"+"/" BEGIN(INITIAL); + +"//"[^\n]*\n /* skip comment */ + +L?\"(\\.|[^\\"])*\" { if (import_string(yyextra, yylval, yytext, '\"') < 0) return CTF_ERROR; else return CTF_STRING_LITERAL; } +L?\'(\\.|[^\\'])*\' { if (import_string(yyextra, yylval, yytext, '\'') < 0) return CTF_ERROR; else return CTF_CHARACTER_LITERAL; } + +"[" return CTF_LSBRAC; +"]" return CTF_RSBRAC; +"(" return CTF_LPAREN; +")" return CTF_RPAREN; +"{" return CTF_LBRAC; +"}" return CTF_RBRAC; +"->" return CTF_RARROW; +"*" return CTF_STAR; +"+" return CTF_PLUS; +"-" return CTF_MINUS; +"<" return CTF_LT; +">" return CTF_GT; +:= return CTF_TYPEASSIGN; +: return CTF_COLON; +; return CTF_SEMICOLON; +"..." return CTF_DOTDOTDOT; +"." return CTF_DOT; += return CTF_EQUAL; +"," return CTF_COMMA; +align setstring(yyextra, yylval, yytext); return CTF_TOK_ALIGN; +const setstring(yyextra, yylval, yytext); return CTF_CONST; +char setstring(yyextra, yylval, yytext); return CTF_CHAR; +clock setstring(yyextra, yylval, yytext); return CTF_CLOCK; +double setstring(yyextra, yylval, yytext); return CTF_DOUBLE; +enum setstring(yyextra, yylval, yytext); return CTF_ENUM; +env setstring(yyextra, yylval, yytext); return CTF_ENV; +event setstring(yyextra, yylval, yytext); return CTF_EVENT; +floating_point setstring(yyextra, yylval, yytext); return CTF_FLOATING_POINT; +float setstring(yyextra, yylval, yytext); return CTF_FLOAT; +integer setstring(yyextra, yylval, yytext); return CTF_INTEGER; +int setstring(yyextra, yylval, yytext); return CTF_INT; +long setstring(yyextra, yylval, yytext); return CTF_LONG; +short setstring(yyextra, yylval, yytext); return CTF_SHORT; +signed setstring(yyextra, yylval, yytext); return CTF_SIGNED; +stream setstring(yyextra, yylval, yytext); return CTF_STREAM; +string setstring(yyextra, yylval, yytext); return CTF_STRING; +struct setstring(yyextra, yylval, yytext); return CTF_STRUCT; +trace setstring(yyextra, yylval, yytext); return CTF_TRACE; +callsite setstring(yyextra, yylval, yytext); return CTF_CALLSITE; +typealias setstring(yyextra, yylval, yytext); return CTF_TYPEALIAS; +typedef setstring(yyextra, yylval, yytext); return CTF_TYPEDEF; +unsigned setstring(yyextra, yylval, yytext); return CTF_UNSIGNED; +variant setstring(yyextra, yylval, yytext); return CTF_VARIANT; +void setstring(yyextra, yylval, yytext); return CTF_VOID; +_Bool setstring(yyextra, yylval, yytext); return CTF_BOOL; +_Complex setstring(yyextra, yylval, yytext); return CTF_COMPLEX; +_Imaginary setstring(yyextra, yylval, yytext); return CTF_IMAGINARY; +[1-9]{DIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(10); return CTF_INTEGER_LITERAL; +0{OCTALDIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(8); return CTF_INTEGER_LITERAL; +0[xX]{HEXDIGIT}+{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(16); return CTF_INTEGER_LITERAL; + +{IDENTIFIER} BT_LOGT("Got identifier: id=\"%s\"", yytext); setstring(yyextra, yylval, yytext); if (is_type(yyextra, yytext)) return ID_TYPE; else return IDENTIFIER; +[ \t\r\n] ; /* ignore */ +. _BT_LOGE_APPEND_CAUSE_LINENO(yylineno, "Invalid character: char=\"%c\", val=0x%02x", isprint((unsigned char) yytext[0]) ? yytext[0] : '\0', yytext[0]); return CTF_ERROR; +%% diff --git a/src/plugins/ctf/common/src/metadata/tsdl/logging.cpp b/src/plugins/ctf/common/src/metadata/tsdl/logging.cpp new file mode 100644 index 00000000..058a6b4b --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/logging.cpp @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2017 Jérémie Galarneau + */ + +#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level +#include "logging/log-api.h" + +BT_LOG_INIT_LOG_LEVEL(ctf_plugin_metadata_log_level, "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL"); diff --git a/src/plugins/ctf/common/src/metadata/tsdl/logging.hpp b/src/plugins/ctf/common/src/metadata/tsdl/logging.hpp new file mode 100644 index 00000000..234a1d60 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/logging.hpp @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2017 Jérémie Galarneau + */ + +#ifndef CTF_METADATA_LOGGING_H +#define CTF_METADATA_LOGGING_H + +#include + +#include "logging/comp-logging.h" +#include "logging/log.h" + +/* + * This global log level is for the generated lexer and parser: we can't + * use a contextual log level for their "tracing", so they rely on this. + */ +BT_LOG_LEVEL_EXTERN_SYMBOL(ctf_plugin_metadata_log_level); + +/* + * To be used by functions without a context structure to pass all the + * logging configuration at once. + */ +struct meta_log_config +{ + bt_logging_level log_level; + + /* Weak, exactly one of these must be set */ + bt_self_component *self_comp; + bt_self_component_class *self_comp_class; +}; + +#define _BT_LOGT_LINENO(_lineno, _msg, args...) \ + BT_LOGT("At line %u in metadata stream: " _msg, _lineno, ##args) + +#define _BT_LOGW_LINENO(_lineno, _msg, args...) \ + BT_LOGW("At line %u in metadata stream: " _msg, _lineno, ##args) + +#define _BT_LOGE_APPEND_CAUSE_LINENO(_lineno, _msg, args...) \ + do { \ + BT_LOGE("At line %u in metadata stream: " _msg, _lineno, ##args); \ + (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( \ + "CTF metadata parser", "At line %u in metadata stream: " _msg, _lineno, ##args); \ + } while (0) + +#define _BT_COMP_LOGT_LINENO(_lineno, _msg, args...) \ + BT_COMP_LOGT("At line %u in metadata stream: " _msg, _lineno, ##args) + +#define _BT_COMP_LOGW_LINENO(_lineno, _msg, args...) \ + BT_COMP_LOGW("At line %u in metadata stream: " _msg, _lineno, ##args) + +#define _BT_COMP_LOGE_LINENO(_lineno, _msg, args...) \ + BT_COMP_LOGE("At line %u in metadata stream: " _msg, _lineno, ##args) + +#define _BT_COMP_LOGE_APPEND_CAUSE_LINENO(_lineno, _msg, args...) \ + BT_COMP_LOGE_APPEND_CAUSE(BT_COMP_LOG_SELF_COMP, "At line %u in metadata stream: " _msg, \ + _lineno, ##args) + +#define _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(_msg, args...) \ + BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(BT_COMP_LOG_SELF_COMP, BT_COMP_LOG_SELF_COMP_CLASS, \ + _msg, ##args) + +#endif /* CTF_METADATA_LOGGING_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/objstack.cpp b/src/plugins/ctf/common/src/metadata/tsdl/objstack.cpp new file mode 100644 index 00000000..bdf31e02 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/objstack.cpp @@ -0,0 +1,123 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2013 Mathieu Desnoyers + * + * Common Trace Format Object Stack. + */ + +#include + +#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level +#define BT_LOG_TAG "PLUGIN/CTF/META/OBJSTACK" +#include "logging.hpp" + +#include "common/align.h" +#include "common/list.h" + +#include "objstack.hpp" + +#define OBJSTACK_ALIGN 8 /* Object stack alignment */ +#define OBJSTACK_INIT_LEN 128 +#define OBJSTACK_POISON 0xcc + +struct objstack +{ + struct bt_list_head head; /* list of struct objstack_node */ +}; + +struct objstack_node +{ + struct bt_list_head node; + size_t len; + size_t used_len; + char __attribute__((aligned(OBJSTACK_ALIGN))) data[]; +}; + +struct objstack *objstack_create(void) +{ + struct objstack *objstack; + struct objstack_node *node; + + objstack = (struct objstack *) calloc(1, sizeof(*objstack)); + if (!objstack) { + BT_LOGE_STR("Failed to allocate one object stack."); + return NULL; + } + node = (objstack_node *) calloc(sizeof(struct objstack_node) + OBJSTACK_INIT_LEN, sizeof(char)); + if (!node) { + BT_LOGE_STR("Failed to allocate one object stack node."); + free(objstack); + return NULL; + } + BT_INIT_LIST_HEAD(&objstack->head); + bt_list_add_tail(&node->node, &objstack->head); + node->len = OBJSTACK_INIT_LEN; + return objstack; +} + +static void objstack_node_free(struct objstack_node *node) +{ + size_t offset, len; + char *p; + + if (!node) + return; + p = (char *) node; + len = sizeof(*node) + node->len; + for (offset = 0; offset < len; offset++) + p[offset] = OBJSTACK_POISON; + free(node); +} + +void objstack_destroy(struct objstack *objstack) +{ + struct objstack_node *node, *p; + + if (!objstack) + return; + bt_list_for_each_entry_safe (node, p, &objstack->head, node) { + bt_list_del(&node->node); + objstack_node_free(node); + } + free(objstack); +} + +static struct objstack_node *objstack_append_node(struct objstack *objstack) +{ + struct objstack_node *last_node, *new_node; + + /* Get last node */ + last_node = bt_list_entry(objstack->head.prev, struct objstack_node, node); + + /* Allocate new node with double of size of last node */ + new_node = (objstack_node *) calloc(sizeof(struct objstack_node) + (last_node->len << 1), + sizeof(char)); + if (!new_node) { + BT_LOGE_STR("Failed to allocate one object stack node."); + return NULL; + } + bt_list_add_tail(&new_node->node, &objstack->head); + new_node->len = last_node->len << 1; + return new_node; +} + +void *objstack_alloc(struct objstack *objstack, size_t len) +{ + struct objstack_node *last_node; + void *p; + + len = BT_ALIGN(len, OBJSTACK_ALIGN); + + /* Get last node */ + last_node = bt_list_entry(objstack->head.prev, struct objstack_node, node); + while (last_node->len - last_node->used_len < len) { + last_node = objstack_append_node(objstack); + if (!last_node) { + return NULL; + } + } + p = &last_node->data[last_node->used_len]; + last_node->used_len += len; + return p; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/objstack.hpp b/src/plugins/ctf/common/src/metadata/tsdl/objstack.hpp new file mode 100644 index 00000000..2c91e140 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/objstack.hpp @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2013 Mathieu Desnoyers + * + * Common Trace Format Object Stack. + */ + +#ifndef _OBJSTACK_H +#define _OBJSTACK_H + +#include + +struct objstack *objstack_create(void); +void objstack_destroy(struct objstack *objstack); + +/* + * Allocate len bytes of zeroed memory. + * Return NULL on error. + */ +void *objstack_alloc(struct objstack *objstack, size_t len); + +#endif /* _OBJSTACK_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp b/src/plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp new file mode 100644 index 00000000..7b6b580b --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 EfficiOS Inc. + */ + +#ifndef BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H +#define BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H + +/* + * Small wrapper around the bison-generated parser.h to conditionally define + * YYDEBUG (and therefore the yydebug declaration). + */ + +#include "logging/log.h" + +#if BT_LOG_ENABLED_TRACE +# define YYDEBUG 1 +# define YYFPRINTF(_stream, _fmt, args...) BT_LOGT(_fmt, ##args) +#else +# define YYDEBUG 0 +#endif + +#define ALLOW_INCLUDE_PARSER_H +#include "plugins/ctf/common/src/metadata/tsdl/parser.hpp" +#undef ALLOW_INCLUDE_PARSER_H + +#endif diff --git a/src/plugins/ctf/common/src/metadata/tsdl/parser.ypp b/src/plugins/ctf/common/src/metadata/tsdl/parser.ypp new file mode 100644 index 00000000..b0583695 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/parser.ypp @@ -0,0 +1,2608 @@ +%{ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 - Mathieu Desnoyers + * + * Common Trace Format Metadata Grammar. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level +#define BT_LOG_TAG "PLUGIN/CTF/META/PARSER" +#include "plugins/ctf/common/src/metadata/tsdl/logging.hpp" + +#include "common/list.h" +#include "common/assert.h" + +#include "plugins/ctf/common/src/metadata/tsdl/scanner.hpp" +#include "plugins/ctf/common/src/metadata/tsdl/ast.hpp" +#include "plugins/ctf/common/src/metadata/tsdl/objstack.hpp" +#include "plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp" + +/* + * Avoid warning about "yynerrs" being unused, seen with bison 3.5.1 + clang 15 + * on Ubuntu 20.04. + */ +BT_DIAG_IGNORE_UNUSED_BUT_SET_VARIABLE + +/* Join two lists, put "add" at the end of "head". */ +static inline void +_bt_list_splice_tail (struct bt_list_head *add, struct bt_list_head *head) +{ + /* Do nothing if the list which gets added is empty. */ + if (add != add->next) { + add->next->prev = head->prev; + add->prev->next = head; + head->prev->next = add->next; + head->prev = add->prev; + } +} + +int yylex(union YYSTYPE *yyval, yyscan_t yyscanner); +int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals); +int yylex_destroy(yyscan_t yyscanner); +void yyrestart(FILE * in_str, yyscan_t yyscanner); +int yyget_lineno(yyscan_t yyscanner); +char *yyget_text(yyscan_t yyscanner); + +/* + * Static node for out of memory errors. Only "type" is used. lineno is + * always left at 0. The rest of the node content can be overwritten, + * but is never used. + */ +static struct ctf_node error_node = { + .parent = nullptr, + .siblings = {}, + .tmp_head = {}, + .lineno = 0, + .visited = 0, + .type = NODE_ERROR, +}; + +const char *node_type(struct ctf_node *node) +{ + switch (node->type) { +#define ENTRY(S) case S: return #S; + FOREACH_CTF_NODES(ENTRY) +#undef ENTRY + }; + + bt_common_abort(); +} + +void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src) +{ + lvalp->s = (char *) objstack_alloc(scanner->objstack, strlen(src) + 1); + strcpy(lvalp->s, src); +} + +static +int str_check(size_t str_len, size_t offset, size_t len) +{ + /* check overflow */ + if (offset + len < offset) + return -1; + if (offset + len > str_len) + return -1; + return 0; +} + +static +int bt_isodigit(int c) +{ + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + return 1; + default: + return 0; + } +} + +static +int parse_base_sequence(const char *src, size_t len, size_t pos, + char *buffer, size_t *buf_len, int base) +{ + const size_t max_char = 3; + int nr_char = 0; + + while (!str_check(len, pos, 1) && nr_char < max_char) { + char c = src[pos++]; + + if (base == 8) { + if (bt_isodigit(c)) + buffer[nr_char++] = c; + else + break; + } else if (base == 16) { + if (isxdigit(c)) + buffer[nr_char++] = c; + else + break; + + } else { + /* Unsupported base */ + return -1; + } + } + BT_ASSERT_DBG(nr_char > 0); + buffer[nr_char] = '\0'; + *buf_len = nr_char; + return 0; +} + +static +int import_basic_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, + size_t len, const char *src, char delim) +{ + size_t pos = 0, dpos = 0; + + if (str_check(len, pos, 1)) + return -1; + if (src[pos++] != delim) + return -1; + + while (src[pos] != delim) { + char c; + + if (str_check(len, pos, 1)) + return -1; + c = src[pos++]; + if (c == '\\') { + if (str_check(len, pos, 1)) + return -1; + c = src[pos++]; + + switch (c) { + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case '\\': + c = '\\'; + break; + case '\'': + c = '\''; + break; + case '\"': + c = '\"'; + break; + case '?': + c = '?'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + char oct_buffer[4]; + size_t oct_len; + + if (parse_base_sequence(src, len, pos - 1, + oct_buffer, &oct_len, 8)) + return -1; + c = strtoul(&oct_buffer[0], NULL, 8); + pos += oct_len - 1; + break; + } + case 'x': + { + char hex_buffer[4]; + size_t hex_len; + + if (parse_base_sequence(src, len, pos, + hex_buffer, &hex_len, 16)) + return -1; + c = strtoul(&hex_buffer[0], NULL, 16); + pos += hex_len; + break; + } + default: + return -1; + } + } + if (str_check(len, dpos, 1)) + return -1; + lvalp->s[dpos++] = c; + } + + if (str_check(len, dpos, 1)) + return -1; + lvalp->s[dpos++] = '\0'; + + if (str_check(len, pos, 1)) + return -1; + if (src[pos++] != delim) + return -1; + + if (str_check(len, pos, 1)) + return -1; + if (src[pos] != '\0') + return -1; + return 0; +} + +int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, + const char *src, char delim) +{ + size_t len; + + len = strlen(src) + 1; + lvalp->s = (char *) objstack_alloc(scanner->objstack, len); + if (src[0] == 'L') { + // TODO: import wide string + _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner), + "wide characters are not supported as of this version: " + "scanner-addr=%p", scanner); + return -1; + } else { + return import_basic_string(scanner, lvalp, len, src, delim); + } +} + +static void init_scope(struct ctf_scanner_scope *scope, + struct ctf_scanner_scope *parent) +{ + scope->parent = parent; + scope->classes = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, NULL); +} + +static void finalize_scope(struct ctf_scanner_scope *scope) +{ + g_hash_table_destroy(scope->classes); +} + +static void push_scope(struct ctf_scanner *scanner) +{ + struct ctf_scanner_scope *ns; + + BT_LOGT("Pushing scope: scanner-addr=%p", scanner); + ns = (ctf_scanner_scope *) malloc(sizeof(struct ctf_scanner_scope)); + init_scope(ns, scanner->cs); + scanner->cs = ns; +} + +static void pop_scope(struct ctf_scanner *scanner) +{ + struct ctf_scanner_scope *os; + + BT_LOGT("Popping scope: scanner-addr=%p", scanner); + os = scanner->cs; + scanner->cs = os->parent; + finalize_scope(os); + free(os); +} + +static int lookup_type(struct ctf_scanner_scope *s, const char *id) +{ + int ret; + + ret = GPOINTER_TO_INT(g_hash_table_lookup(s->classes, id)); + BT_LOGT("Looked up type: scanner-addr=%p, id=\"%s\", ret=%d", + s, id, ret); + return ret; +} + +int is_type(struct ctf_scanner *scanner, const char *id) +{ + struct ctf_scanner_scope *it; + int ret = 0; + + for (it = scanner->cs; it; it = it->parent) { + if (lookup_type(it, id)) { + ret = 1; + break; + } + } + BT_LOGT("Found if ID is type: scanner-addr=%p, id=\"%s\", ret=%d", + scanner, id, ret); + return ret; +} + +static void add_type(struct ctf_scanner *scanner, char *id) +{ + BT_LOGT("Adding type: scanner-addr=%p, id=\"%s\"", + scanner, id); + if (lookup_type(scanner->cs, id)) + return; + g_hash_table_insert(scanner->cs->classes, id, id); +} + +static struct ctf_node *make_node(struct ctf_scanner *scanner, + enum node_type type) +{ + struct ctf_node *node; + + node = (ctf_node *) objstack_alloc(scanner->objstack, sizeof(*node)); + if (!node) { + _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner->scanner), + "failed to allocate one stack entry: " + "scanner-addr=%p", scanner); + return &error_node; + } + node->type = type; + node->lineno = yyget_lineno(scanner->scanner); + BT_INIT_LIST_HEAD(&node->tmp_head); + bt_list_add(&node->siblings, &node->tmp_head); + + switch (type) { + case NODE_ROOT: + node->type = NODE_ERROR; + BT_LOGE("Trying to create root node: scanner-addr=%p", + scanner); + break; + case NODE_EVENT: + BT_INIT_LIST_HEAD(&node->u.event.declaration_list); + break; + case NODE_STREAM: + BT_INIT_LIST_HEAD(&node->u.stream.declaration_list); + break; + case NODE_ENV: + BT_INIT_LIST_HEAD(&node->u.env.declaration_list); + break; + case NODE_TRACE: + BT_INIT_LIST_HEAD(&node->u.trace.declaration_list); + break; + case NODE_CLOCK: + BT_INIT_LIST_HEAD(&node->u.clock.declaration_list); + break; + case NODE_CALLSITE: + BT_INIT_LIST_HEAD(&node->u.callsite.declaration_list); + break; + case NODE_CTF_EXPRESSION: + BT_INIT_LIST_HEAD(&node->u.ctf_expression.left); + BT_INIT_LIST_HEAD(&node->u.ctf_expression.right); + break; + case NODE_UNARY_EXPRESSION: + break; + case NODE_TYPEDEF: + BT_INIT_LIST_HEAD(&node->u.field_class_def.field_class_declarators); + break; + case NODE_TYPEALIAS_TARGET: + BT_INIT_LIST_HEAD(&node->u.field_class_alias_target.field_class_declarators); + break; + case NODE_TYPEALIAS_ALIAS: + BT_INIT_LIST_HEAD(&node->u.field_class_alias_name.field_class_declarators); + break; + case NODE_TYPEALIAS: + break; + case NODE_TYPE_SPECIFIER: + break; + case NODE_TYPE_SPECIFIER_LIST: + BT_INIT_LIST_HEAD(&node->u.field_class_specifier_list.head); + break; + case NODE_POINTER: + break; + case NODE_TYPE_DECLARATOR: + BT_INIT_LIST_HEAD(&node->u.field_class_declarator.pointers); + break; + case NODE_FLOATING_POINT: + BT_INIT_LIST_HEAD(&node->u.floating_point.expressions); + break; + case NODE_INTEGER: + BT_INIT_LIST_HEAD(&node->u.integer.expressions); + break; + case NODE_STRING: + BT_INIT_LIST_HEAD(&node->u.string.expressions); + break; + case NODE_ENUMERATOR: + BT_INIT_LIST_HEAD(&node->u.enumerator.values); + break; + case NODE_ENUM: + BT_INIT_LIST_HEAD(&node->u._enum.enumerator_list); + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + BT_INIT_LIST_HEAD(&node->u.struct_or_variant_declaration.field_class_declarators); + break; + case NODE_VARIANT: + BT_INIT_LIST_HEAD(&node->u.variant.declaration_list); + break; + case NODE_STRUCT: + BT_INIT_LIST_HEAD(&node->u._struct.declaration_list); + BT_INIT_LIST_HEAD(&node->u._struct.min_align); + break; + case NODE_UNKNOWN: + default: + node->type = NODE_ERROR; + BT_LOGE("Unknown node type: scanner-addr=%p, node-type=%d", + scanner, type); + break; + } + + return node; +} + +static int reparent_ctf_expression(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_EVENT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); + break; + case NODE_FLOATING_POINT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.floating_point.expressions); + break; + case NODE_INTEGER: + _bt_list_splice_tail(&node->tmp_head, &parent->u.integer.expressions); + break; + case NODE_STRING: + _bt_list_splice_tail(&node->tmp_head, &parent->u.string.expressions); + break; + + case NODE_ROOT: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_VARIANT: + case NODE_STRUCT: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_typedef(struct ctf_node *node, struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_ROOT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list); + break; + case NODE_EVENT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); + break; + case NODE_VARIANT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); + break; + case NODE_STRUCT: + _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); + break; + + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_alias(struct ctf_node *node, struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_ROOT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list); + break; + case NODE_EVENT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); + break; + case NODE_VARIANT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); + break; + case NODE_STRUCT: + _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); + break; + + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_specifier(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_TYPE_SPECIFIER_LIST: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_specifier_list.head); + break; + + case NODE_TYPE_SPECIFIER: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_VARIANT: + case NODE_STRUCT: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPE_DECLARATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPEALIAS: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_POINTER: + case NODE_ENUMERATOR: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_specifier_list(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_ROOT: + bt_list_add_tail(&node->siblings, &parent->u.root.declaration_list); + break; + case NODE_EVENT: + bt_list_add_tail(&node->siblings, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + bt_list_add_tail(&node->siblings, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + bt_list_add_tail(&node->siblings, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + bt_list_add_tail(&node->siblings, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + bt_list_add_tail(&node->siblings, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + bt_list_add_tail(&node->siblings, &parent->u.callsite.declaration_list); + break; + case NODE_VARIANT: + bt_list_add_tail(&node->siblings, &parent->u.variant.declaration_list); + break; + case NODE_STRUCT: + bt_list_add_tail(&node->siblings, &parent->u._struct.declaration_list); + break; + case NODE_TYPEDEF: + parent->u.field_class_def.field_class_specifier_list = node; + break; + case NODE_TYPEALIAS_TARGET: + parent->u.field_class_alias_target.field_class_specifier_list = node; + break; + case NODE_TYPEALIAS_ALIAS: + parent->u.field_class_alias_name.field_class_specifier_list = node; + break; + case NODE_ENUM: + parent->u._enum.container_field_class = node; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + parent->u.struct_or_variant_declaration.field_class_specifier_list = node; + break; + case NODE_TYPE_DECLARATOR: + case NODE_TYPE_SPECIFIER: + case NODE_TYPEALIAS: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_POINTER: + case NODE_ENUMERATOR: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_declarator(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_TYPE_DECLARATOR: + parent->u.field_class_declarator.type = TYPEDEC_NESTED; + parent->u.field_class_declarator.u.nested.field_class_declarator = node; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + _bt_list_splice_tail(&node->tmp_head, &parent->u.struct_or_variant_declaration.field_class_declarators); + break; + case NODE_TYPEDEF: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_def.field_class_declarators); + break; + case NODE_TYPEALIAS_TARGET: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_target.field_class_declarators); + break; + case NODE_TYPEALIAS_ALIAS: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_name.field_class_declarators); + break; + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_VARIANT: + case NODE_STRUCT: + case NODE_TYPEALIAS: + case NODE_ENUM: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_ENUMERATOR: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +/* + * set_parent_node + * + * Link node to parent. Returns 0 on success, -EPERM if it is not permitted to + * create the link declared by the input, -ENOENT if node or parent is NULL, + * -EINVAL if there is an internal structure problem. + */ +static int set_parent_node(struct ctf_node *node, + struct ctf_node *parent) +{ + if (!node || !parent) + return -ENOENT; + + /* Note: Linking to parent will be done only by an external visitor */ + + switch (node->type) { + case NODE_ROOT: + BT_LOGE_STR("Trying to reparent root node."); + return -EINVAL; + + case NODE_EVENT: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.event); + } else { + return -EPERM; + } + break; + case NODE_STREAM: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.stream); + } else { + return -EPERM; + } + break; + case NODE_ENV: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.env); + } else { + return -EPERM; + } + break; + case NODE_TRACE: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.trace); + } else { + return -EPERM; + } + break; + case NODE_CLOCK: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.clock); + } else { + return -EPERM; + } + break; + case NODE_CALLSITE: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.callsite); + } else { + return -EPERM; + } + break; + + case NODE_CTF_EXPRESSION: + return reparent_ctf_expression(node, parent); + case NODE_UNARY_EXPRESSION: + if (parent->type == NODE_TYPE_DECLARATOR) + parent->u.field_class_declarator.bitfield_len = node; + else + return -EPERM; + break; + + case NODE_TYPEDEF: + return reparent_typedef(node, parent); + case NODE_TYPEALIAS_TARGET: + if (parent->type == NODE_TYPEALIAS) + parent->u.field_class_alias.target = node; + else + return -EINVAL; + /* fall-through */ + case NODE_TYPEALIAS_ALIAS: + if (parent->type == NODE_TYPEALIAS) + parent->u.field_class_alias.alias = node; + else + return -EINVAL; + /* fall-through */ + case NODE_TYPEALIAS: + return reparent_field_class_alias(node, parent); + + case NODE_POINTER: + if (parent->type == NODE_TYPE_DECLARATOR) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_declarator.pointers); + } else + return -EPERM; + break; + case NODE_TYPE_DECLARATOR: + return reparent_field_class_declarator(node, parent); + + case NODE_TYPE_SPECIFIER_LIST: + return reparent_field_class_specifier_list(node, parent); + + case NODE_TYPE_SPECIFIER: + return reparent_field_class_specifier(node, parent); + + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + return -EINVAL; /* Dealt with internally within grammar */ + + case NODE_ENUMERATOR: + if (parent->type == NODE_ENUM) { + _bt_list_splice_tail(&node->tmp_head, &parent->u._enum.enumerator_list); + } else { + return -EPERM; + } + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + switch (parent->type) { + case NODE_STRUCT: + _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); + break; + case NODE_VARIANT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); + break; + default: + return -EINVAL; + } + break; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static +void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str) +{ + _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner->scanner), + "%s: token=\"%s\"", str, yyget_text(scanner->scanner)); +} + +#define reparent_error(scanner, str) \ +do { \ + yyerror(scanner, scanner->scanner, YY_("reparent_error: " str)); \ + YYERROR; \ +} while (0) + +static struct ctf_ast *ctf_ast_alloc(struct ctf_scanner *scanner) +{ + struct ctf_ast *ast; + + ast = (ctf_ast *) objstack_alloc(scanner->objstack, sizeof(*ast)); + if (!ast) + return NULL; + ast->root.type = NODE_ROOT; + BT_INIT_LIST_HEAD(&ast->root.tmp_head); + BT_INIT_LIST_HEAD(&ast->root.u.root.declaration_list); + BT_INIT_LIST_HEAD(&ast->root.u.root.trace); + BT_INIT_LIST_HEAD(&ast->root.u.root.env); + BT_INIT_LIST_HEAD(&ast->root.u.root.stream); + BT_INIT_LIST_HEAD(&ast->root.u.root.event); + BT_INIT_LIST_HEAD(&ast->root.u.root.clock); + BT_INIT_LIST_HEAD(&ast->root.u.root.callsite); + return ast; +} + +int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input) +{ + /* Start processing new stream */ + yyrestart(input, scanner->scanner); + return yyparse(scanner, scanner->scanner); +} + +struct ctf_scanner *ctf_scanner_alloc(void) +{ + struct ctf_scanner *scanner; + int ret; + + scanner = (ctf_scanner *) malloc(sizeof(*scanner)); + if (!scanner) + return NULL; + memset(scanner, 0, sizeof(*scanner)); + ret = yylex_init_extra(scanner, &scanner->scanner); + if (ret) { + BT_LOGE("yylex_init_extra() failed: ret=%d", ret); + goto cleanup_scanner; + } + scanner->objstack = objstack_create(); + if (!scanner->objstack) + goto cleanup_lexer; + scanner->ast = ctf_ast_alloc(scanner); + if (!scanner->ast) + goto cleanup_objstack; + init_scope(&scanner->root_scope, NULL); + scanner->cs = &scanner->root_scope; + + return scanner; + +cleanup_objstack: + objstack_destroy(scanner->objstack); +cleanup_lexer: + ret = yylex_destroy(scanner->scanner); + if (!ret) + BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d", + scanner, ret); +cleanup_scanner: + free(scanner); + return NULL; +} + +void ctf_scanner_free(struct ctf_scanner *scanner) +{ + int ret; + + if (!scanner) + return; + + struct ctf_scanner_scope *scope = scanner->cs; + + do { + struct ctf_scanner_scope *parent = scope->parent; + finalize_scope(scope); + + /* + * The root scope is allocated within the ctf_scanner structure, + * do doesn't need freeing. All others are allocated on their + * own. + */ + if (scope != &scanner->root_scope) + free(scope); + + scope = parent; + } while (scope); + + objstack_destroy(scanner->objstack); + ret = yylex_destroy(scanner->scanner); + if (ret) + BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d", + scanner, ret); + free(scanner); +} + +/* + * The bison-provided version of strlen (yystrlen) generates a benign + * -Wnull-dereference warning. That version is used when building on cygwin, + * for example, but you can also enable it by hand (to test) by removing the + * preprocessor conditional around it. + * + * Define yystrlen such that it will always use strlen. As far as we know, + * strlen provided by all the platforms we use is reliable. + */ +#define yystrlen strlen + +%} + +/* + * This ends up in parser.h and makes sure those who want to include it pass + * through parser-wrap.h. + */ +%code requires { +#ifndef ALLOW_INCLUDE_PARSER_H +# error "Don't include parser.h directly, include parser-wrap.h instead." +#endif + +#include "plugins/ctf/common/src/metadata/tsdl/scanner.hpp" +} + +%code provides { + void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src); + + int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim); +} + +%define api.pure + /* %locations */ +%error-verbose +%parse-param {struct ctf_scanner *scanner} +%parse-param {yyscan_t yyscanner} +%lex-param {yyscan_t yyscanner} +/* + * Expect two shift-reduce conflicts. Caused by enum name-opt : type {} + * vs struct { int :value; } (unnamed bit-field). The default is to + * shift, so whenever we encounter an enumeration, we are doing the + * proper thing (shift). It is illegal to declare an enumeration + * "bit-field", so it is OK if this situation ends up in a parsing + * error. + */ +%expect 2 +%start file +%token CTF_INTEGER_LITERAL CTF_STRING_LITERAL CTF_CHARACTER_LITERAL CTF_LSBRAC CTF_RSBRAC CTF_LPAREN CTF_RPAREN CTF_LBRAC CTF_RBRAC CTF_RARROW CTF_STAR CTF_PLUS CTF_MINUS CTF_LT CTF_GT CTF_TYPEASSIGN CTF_COLON CTF_SEMICOLON CTF_DOTDOTDOT CTF_DOT CTF_EQUAL CTF_COMMA CTF_CONST CTF_CHAR CTF_DOUBLE CTF_ENUM CTF_ENV CTF_EVENT CTF_FLOATING_POINT CTF_FLOAT CTF_INTEGER CTF_INT CTF_LONG CTF_SHORT CTF_SIGNED CTF_STREAM CTF_STRING CTF_STRUCT CTF_TRACE CTF_CALLSITE CTF_CLOCK CTF_TYPEALIAS CTF_TYPEDEF CTF_UNSIGNED CTF_VARIANT CTF_VOID CTF_BOOL CTF_COMPLEX CTF_IMAGINARY CTF_TOK_ALIGN +%token IDENTIFIER ID_TYPE +%token CTF_ERROR +%union +{ + long long ll; + unsigned long long ull; + char c; + char *s; + struct ctf_node *n; +} + +%type CTF_STRING_LITERAL CTF_CHARACTER_LITERAL + +%type keywords + +%type CTF_INTEGER_LITERAL +%type postfix_expression unary_expression unary_expression_or_range + +%type declaration +%type event_declaration +%type stream_declaration +%type env_declaration +%type trace_declaration +%type clock_declaration +%type callsite_declaration +%type integer_declaration_specifiers +%type declaration_specifiers +%type alias_declaration_specifiers + +%type field_class_declarator_list +%type integer_field_class_specifier +%type field_class_specifier +%type struct_class_specifier +%type variant_field_class_specifier +%type enum_field_class_specifier +%type struct_or_variant_declaration_list +%type struct_or_variant_declaration +%type struct_or_variant_declarator_list +%type struct_or_variant_declarator +%type enumerator_list +%type enumerator +%type abstract_declarator_list +%type abstract_declarator +%type direct_abstract_declarator +%type alias_abstract_declarator_list +%type alias_abstract_declarator +%type direct_alias_abstract_declarator +%type declarator +%type direct_declarator +%type field_class_declarator +%type direct_field_class_declarator +%type pointer +%type ctf_assignment_expression_list +%type ctf_assignment_expression + +%% + +file: + declaration + { + if (set_parent_node($1, &ctf_scanner_get_ast(scanner)->root)) + reparent_error(scanner, "error reparenting to root"); + } + | file declaration + { + if (set_parent_node($2, &ctf_scanner_get_ast(scanner)->root)) + reparent_error(scanner, "error reparenting to root"); + } + ; + +keywords: + CTF_VOID + { $$ = yylval.s; } + | CTF_CHAR + { $$ = yylval.s; } + | CTF_SHORT + { $$ = yylval.s; } + | CTF_INT + { $$ = yylval.s; } + | CTF_LONG + { $$ = yylval.s; } + | CTF_FLOAT + { $$ = yylval.s; } + | CTF_DOUBLE + { $$ = yylval.s; } + | CTF_SIGNED + { $$ = yylval.s; } + | CTF_UNSIGNED + { $$ = yylval.s; } + | CTF_BOOL + { $$ = yylval.s; } + | CTF_COMPLEX + { $$ = yylval.s; } + | CTF_IMAGINARY + { $$ = yylval.s; } + | CTF_FLOATING_POINT + { $$ = yylval.s; } + | CTF_INTEGER + { $$ = yylval.s; } + | CTF_STRING + { $$ = yylval.s; } + | CTF_ENUM + { $$ = yylval.s; } + | CTF_VARIANT + { $$ = yylval.s; } + | CTF_STRUCT + { $$ = yylval.s; } + | CTF_CONST + { $$ = yylval.s; } + | CTF_TYPEDEF + { $$ = yylval.s; } + | CTF_EVENT + { $$ = yylval.s; } + | CTF_STREAM + { $$ = yylval.s; } + | CTF_ENV + { $$ = yylval.s; } + | CTF_TRACE + { $$ = yylval.s; } + | CTF_CLOCK + { $$ = yylval.s; } + | CTF_CALLSITE + { $$ = yylval.s; } + | CTF_TOK_ALIGN + { $$ = yylval.s; } + ; + + +/* 2: Phrase structure grammar */ + +postfix_expression: + IDENTIFIER + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + } + | keywords + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + } + | CTF_INTEGER_LITERAL + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_UNSIGNED_CONSTANT; + $$->u.unary_expression.u.unsigned_constant = $1; + } + | CTF_STRING_LITERAL + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = $1; + } + | CTF_CHARACTER_LITERAL + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = $1; + } + | CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = $2; + } + | postfix_expression CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_SBRAC; + $$->u.unary_expression.u.sbrac_exp = $3; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_DOT IDENTIFIER + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_DOTLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_DOT ID_TYPE + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_DOTLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_DOT keywords + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_DOTLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_RARROW IDENTIFIER + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_ARROWLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_RARROW ID_TYPE + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_ARROWLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + ; + +unary_expression: + postfix_expression + { $$ = $1; } + | CTF_PLUS postfix_expression + { + $$ = $2; + if ($$->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT + && $$->u.unary_expression.type != UNARY_SIGNED_CONSTANT) { + reparent_error(scanner, "expecting numeric constant"); + } + } + | CTF_MINUS postfix_expression + { + $$ = $2; + if ($$->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT) { + $$->u.unary_expression.type = UNARY_SIGNED_CONSTANT; + $$->u.unary_expression.u.signed_constant = + -($$->u.unary_expression.u.unsigned_constant); + } else if ($$->u.unary_expression.type == UNARY_SIGNED_CONSTANT) { + $$->u.unary_expression.u.signed_constant = + -($$->u.unary_expression.u.signed_constant); + } else { + reparent_error(scanner, "expecting numeric constant"); + } + } + ; + +unary_expression_or_range: + unary_expression CTF_DOTDOTDOT unary_expression + { + $$ = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->tmp_head); + $3->u.unary_expression.link = UNARY_DOTDOTDOT; + } + | unary_expression + { $$ = $1; } + ; + +/* 2.2: Declarations */ + +declaration: + declaration_specifiers CTF_SEMICOLON + { $$ = $1; } + | event_declaration + { $$ = $1; } + | stream_declaration + { $$ = $1; } + | env_declaration + { $$ = $1; } + | trace_declaration + { $$ = $1; } + | clock_declaration + { $$ = $1; } + | callsite_declaration + { $$ = $1; } + | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEALIAS); + $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); + $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; + _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); + } + ; + +event_declaration: + event_declaration_begin event_declaration_end + { + $$ = make_node(scanner, NODE_EVENT); + } + | event_declaration_begin ctf_assignment_expression_list event_declaration_end + { + $$ = make_node(scanner, NODE_EVENT); + if (set_parent_node($2, $$)) + reparent_error(scanner, "event_declaration"); + } + ; + +event_declaration_begin: + CTF_EVENT CTF_LBRAC + { push_scope(scanner); } + ; + +event_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + + +stream_declaration: + stream_declaration_begin stream_declaration_end + { + $$ = make_node(scanner, NODE_STREAM); + } + | stream_declaration_begin ctf_assignment_expression_list stream_declaration_end + { + $$ = make_node(scanner, NODE_STREAM); + if (set_parent_node($2, $$)) + reparent_error(scanner, "stream_declaration"); + } + ; + +stream_declaration_begin: + CTF_STREAM CTF_LBRAC + { push_scope(scanner); } + ; + +stream_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +env_declaration: + env_declaration_begin env_declaration_end + { + $$ = make_node(scanner, NODE_ENV); + } + | env_declaration_begin ctf_assignment_expression_list env_declaration_end + { + $$ = make_node(scanner, NODE_ENV); + if (set_parent_node($2, $$)) + reparent_error(scanner, "env declaration"); + } + ; + +env_declaration_begin: + CTF_ENV CTF_LBRAC + { push_scope(scanner); } + ; + +env_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +trace_declaration: + trace_declaration_begin trace_declaration_end + { + $$ = make_node(scanner, NODE_TRACE); + } + | trace_declaration_begin ctf_assignment_expression_list trace_declaration_end + { + $$ = make_node(scanner, NODE_TRACE); + if (set_parent_node($2, $$)) + reparent_error(scanner, "trace_declaration"); + } + ; + +trace_declaration_begin: + CTF_TRACE CTF_LBRAC + { push_scope(scanner); } + ; + +trace_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +clock_declaration: + CTF_CLOCK clock_declaration_begin clock_declaration_end + { + $$ = make_node(scanner, NODE_CLOCK); + } + | CTF_CLOCK clock_declaration_begin ctf_assignment_expression_list clock_declaration_end + { + $$ = make_node(scanner, NODE_CLOCK); + if (set_parent_node($3, $$)) + reparent_error(scanner, "trace_declaration"); + } + ; + +clock_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +clock_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +callsite_declaration: + CTF_CALLSITE callsite_declaration_begin callsite_declaration_end + { + $$ = make_node(scanner, NODE_CALLSITE); + } + | CTF_CALLSITE callsite_declaration_begin ctf_assignment_expression_list callsite_declaration_end + { + $$ = make_node(scanner, NODE_CALLSITE); + if (set_parent_node($3, $$)) + reparent_error(scanner, "trace_declaration"); + } + ; + +callsite_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +callsite_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +integer_declaration_specifiers: + CTF_CONST + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | integer_field_class_specifier + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = $1; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | integer_declaration_specifiers CTF_CONST + { + struct ctf_node *node; + + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | integer_declaration_specifiers integer_field_class_specifier + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); + } + ; + +declaration_specifiers: + CTF_CONST + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | field_class_specifier + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = $1; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | declaration_specifiers CTF_CONST + { + struct ctf_node *node; + + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | declaration_specifiers field_class_specifier + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); + } + ; + +field_class_declarator_list: + field_class_declarator + { $$ = $1; } + | field_class_declarator_list CTF_COMMA field_class_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +integer_field_class_specifier: + CTF_CHAR + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_CHAR; + } + | CTF_SHORT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SHORT; + } + | CTF_INT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INT; + } + | CTF_LONG + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_LONG; + } + | CTF_SIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SIGNED; + } + | CTF_UNSIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED; + } + | CTF_BOOL + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_BOOL; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + $$->u.field_class_specifier.id_type = yylval.s; + } + | CTF_INTEGER CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + } + | CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "integer reparent error"); + } + ; + +field_class_specifier: + CTF_VOID + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_VOID; + } + | CTF_CHAR + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_CHAR; + } + | CTF_SHORT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SHORT; + } + | CTF_INT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INT; + } + | CTF_LONG + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_LONG; + } + | CTF_FLOAT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_FLOAT; + } + | CTF_DOUBLE + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_DOUBLE; + } + | CTF_SIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SIGNED; + } + | CTF_UNSIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED; + } + | CTF_BOOL + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_BOOL; + } + | CTF_COMPLEX + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_COMPLEX; + } + | CTF_IMAGINARY + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_IMAGINARY; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + $$->u.field_class_specifier.id_type = yylval.s; + } + | CTF_FLOATING_POINT CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT; + $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT); + } + | CTF_FLOATING_POINT CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT; + $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "floating point reparent error"); + } + | CTF_INTEGER CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + } + | CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "integer reparent error"); + } + | CTF_STRING + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRING; + $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); + } + | CTF_STRING CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRING; + $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); + } + | CTF_STRING CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRING; + $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "string reparent error"); + } + | CTF_ENUM enum_field_class_specifier + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_ENUM; + $$->u.field_class_specifier.node = $2; + } + | CTF_VARIANT variant_field_class_specifier + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_VARIANT; + $$->u.field_class_specifier.node = $2; + } + | CTF_STRUCT struct_class_specifier + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRUCT; + $$->u.field_class_specifier.node = $2; + } + ; + +struct_class_specifier: + struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + if ($2 && set_parent_node($2, $$)) + reparent_error(scanner, "struct reparent error"); + } + | IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + | ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + | IDENTIFIER + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 0; + $$->u._struct.name = $1; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 0; + $$->u._struct.name = $1; + } + | struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + bt_list_add_tail(&($6)->siblings, &$$->u._struct.min_align); + if ($2 && set_parent_node($2, $$)) + reparent_error(scanner, "struct reparent error"); + } + | IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align); + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + | ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align); + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + ; + +struct_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +struct_declaration_end: + CTF_RBRAC + { pop_scope(scanner); } + ; + +variant_field_class_specifier: + variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + if ($2 && set_parent_node($2, $$)) + reparent_error(scanner, "variant reparent error"); + } + | CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.choice = $2; + if ($5 && set_parent_node($5, $$)) + reparent_error(scanner, "variant reparent error"); + } + | CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.choice = $2; + if ($5 && set_parent_node($5, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER CTF_LT IDENTIFIER CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + | IDENTIFIER CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER CTF_LT ID_TYPE CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + | ID_TYPE variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "variant reparent error"); + } + | ID_TYPE CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | ID_TYPE CTF_LT IDENTIFIER CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + | ID_TYPE CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | ID_TYPE CTF_LT ID_TYPE CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + ; + +variant_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +variant_declaration_end: + CTF_RBRAC + { pop_scope(scanner); } + ; + +enum_field_class_specifier: + CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list); + } + | CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + ($$)->u._enum.container_field_class = $2; + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list); + } + | CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + ($$)->u._enum.container_field_class = $2; + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 0; + $$->u._enum.enum_id = $1; + } + | ID_TYPE CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 0; + $$->u._enum.enum_id = $1; + } + ; + +struct_or_variant_declaration_list: + /* empty */ + { $$ = NULL; } + | struct_or_variant_declaration_list struct_or_variant_declaration + { + if ($1) { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->tmp_head); + } else { + $$ = $2; + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + } + ; + +struct_or_variant_declaration: + declaration_specifiers struct_or_variant_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_STRUCT_OR_VARIANT_DECLARATION); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->tmp_head, &($$)->u.struct_or_variant_declaration.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_TYPEDEF); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEALIAS); + $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); + $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; + _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); + } + ; + +alias_declaration_specifiers: + CTF_CONST + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | field_class_specifier + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = $1; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | IDENTIFIER + { + struct ctf_node *node; + + add_type(scanner, $1); + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + node->u.field_class_specifier.id_type = yylval.s; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | alias_declaration_specifiers CTF_CONST + { + struct ctf_node *node; + + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | alias_declaration_specifiers field_class_specifier + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); + } + | alias_declaration_specifiers IDENTIFIER + { + struct ctf_node *node; + + add_type(scanner, $2); + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + node->u.field_class_specifier.id_type = yylval.s; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + ; + +struct_or_variant_declarator_list: + struct_or_variant_declarator + { $$ = $1; } + | struct_or_variant_declarator_list CTF_COMMA struct_or_variant_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +struct_or_variant_declarator: + declarator + { $$ = $1; } + | CTF_COLON unary_expression + { $$ = $2; } + | declarator CTF_COLON unary_expression + { + $$ = $1; + if (set_parent_node($3, $1)) + reparent_error(scanner, "struct_or_variant_declarator"); + } + ; + +enumerator_list: + enumerator + { $$ = $1; } + | enumerator_list CTF_COMMA enumerator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +enumerator: + IDENTIFIER + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | keywords + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | CTF_STRING_LITERAL + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | IDENTIFIER CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + | ID_TYPE CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + | keywords CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + | CTF_STRING_LITERAL CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + ; + +abstract_declarator_list: + abstract_declarator + { $$ = $1; } + | abstract_declarator_list CTF_COMMA abstract_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +abstract_declarator: + direct_abstract_declarator + { $$ = $1; } + | pointer direct_abstract_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_abstract_declarator: + /* empty */ + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + /* id is NULL */ + } + | IDENTIFIER + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + $$->u.field_class_declarator.u.id = $1; + } + | CTF_LPAREN abstract_declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + | direct_abstract_declarator CTF_LSBRAC CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + $$->u.field_class_declarator.u.nested.abstract_array = 1; + } + ; + +alias_abstract_declarator_list: + alias_abstract_declarator + { $$ = $1; } + | alias_abstract_declarator_list CTF_COMMA alias_abstract_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +alias_abstract_declarator: + direct_alias_abstract_declarator + { $$ = $1; } + | pointer direct_alias_abstract_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_alias_abstract_declarator: + /* empty */ + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + /* id is NULL */ + } + | CTF_LPAREN alias_abstract_declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_alias_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + | direct_alias_abstract_declarator CTF_LSBRAC CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + $$->u.field_class_declarator.u.nested.abstract_array = 1; + } + ; + +declarator: + direct_declarator + { $$ = $1; } + | pointer direct_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_declarator: + IDENTIFIER + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + $$->u.field_class_declarator.u.id = $1; + } + | CTF_LPAREN declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + ; + +field_class_declarator: + direct_field_class_declarator + { $$ = $1; } + | pointer direct_field_class_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_field_class_declarator: + IDENTIFIER + { + add_type(scanner, $1); + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + $$->u.field_class_declarator.u.id = $1; + } + | CTF_LPAREN field_class_declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_field_class_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + ; + +pointer: + CTF_STAR + { + $$ = make_node(scanner, NODE_POINTER); + } + | CTF_STAR pointer + { + $$ = make_node(scanner, NODE_POINTER); + bt_list_splice(&($2)->tmp_head, &($$)->tmp_head); + } + | CTF_STAR type_qualifier_list pointer + { + $$ = make_node(scanner, NODE_POINTER); + $$->u.pointer.const_qualifier = 1; + bt_list_splice(&($3)->tmp_head, &($$)->tmp_head); + } + ; + +type_qualifier_list: + /* pointer assumes only const type qualifier */ + CTF_CONST + | type_qualifier_list CTF_CONST + ; + +/* 2.3: CTF-specific declarations */ + +ctf_assignment_expression_list: + ctf_assignment_expression CTF_SEMICOLON + { $$ = $1; } + | ctf_assignment_expression_list ctf_assignment_expression CTF_SEMICOLON + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->tmp_head); + } + ; + +ctf_assignment_expression: + unary_expression CTF_EQUAL unary_expression + { + /* + * Because we have left and right, cannot use + * set_parent_node. + */ + $$ = make_node(scanner, NODE_CTF_EXPRESSION); + _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left); + if ($1->u.unary_expression.type != UNARY_STRING) + reparent_error(scanner, "ctf_assignment_expression left expects string"); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.ctf_expression.right); + } + | unary_expression CTF_TYPEASSIGN declaration_specifiers /* Only allow struct */ + { + /* + * Because we have left and right, cannot use + * set_parent_node. + */ + $$ = make_node(scanner, NODE_CTF_EXPRESSION); + _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left); + if ($1->u.unary_expression.type != UNARY_STRING) + reparent_error(scanner, "ctf_assignment_expression left expects string"); + bt_list_add_tail(&($3)->siblings, &($$)->u.ctf_expression.right); + } + | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_TYPEDEF); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEDEF declaration_specifiers field_class_declarator_list + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF field_class_declarator_list + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_TYPEDEF); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEALIAS); + $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); + $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; + _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); + } + ; diff --git a/src/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp b/src/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp new file mode 100644 index 00000000..1f6f144d --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2011-2012 Mathieu Desnoyers + */ + +#ifndef _CTF_SCANNER_SYMBOLS +#define _CTF_SCANNER_SYMBOLS + +#define yy_create_buffer bt_yy_create_buffer +#define yy_delete_buffer bt_yy_delete_buffer +#define yy_flush_buffer bt_yy_flush_buffer +#define yy_scan_buffer bt_yy_scan_buffer +#define yy_scan_bytes bt_yy_scan_bytes +#define yy_scan_string bt_yy_scan_string +#define yy_switch_to_buffer bt_yy_switch_to_buffer +#define yyalloc bt_yyalloc +#define yyfree bt_yyfree +#define yyget_column bt_yyget_column +#define yyget_debug bt_yyget_debug +#define yyget_extra bt_yyget_extra +#define yyget_in bt_yyget_in +#define yyget_leng bt_yyget_leng +#define yyget_lineno bt_yyget_lineno +#define yyget_lval bt_yyget_lval +#define yyget_out bt_yyget_out +#define yyget_text bt_yyget_text +#define yylex_init bt_yylex_init +#define yypop_buffer_state bt_yypop_buffer_state +#define yypush_buffer_state bt_yypush_buffer_state +#define yyrealloc bt_yyrealloc +#define yyset_column bt_yyset_column +#define yyset_debug bt_yyset_debug +#define yyset_extra bt_yyset_extra +#define yyset_in bt_yyset_in +#define yyset_lineno bt_yyset_lineno +#define yyset_lval bt_yyset_lval +#define yyset_out bt_yyset_out + +#endif /* _CTF_SCANNER_SYMBOLS */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/scanner.hpp b/src/plugins/ctf/common/src/metadata/tsdl/scanner.hpp new file mode 100644 index 00000000..dd16e977 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/scanner.hpp @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2011-2012 Mathieu Desnoyers + */ + +#ifndef _CTF_SCANNER_H +#define _CTF_SCANNER_H + +#include + +#include "ast.hpp" + +#ifndef YY_TYPEDEF_YY_SCANNER_T +# define YY_TYPEDEF_YY_SCANNER_T +typedef void *yyscan_t; +#endif + +struct ctf_scanner_scope; +struct ctf_scanner_scope +{ + struct ctf_scanner_scope *parent; + GHashTable *classes; +}; + +struct ctf_scanner +{ + yyscan_t scanner; + struct ctf_ast *ast; + struct ctf_scanner_scope root_scope; + struct ctf_scanner_scope *cs; + struct objstack *objstack; +}; + +struct ctf_scanner *ctf_scanner_alloc(void); + +void ctf_scanner_free(struct ctf_scanner *scanner); + +int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input); + +static inline struct ctf_ast *ctf_scanner_get_ast(struct ctf_scanner *scanner) +{ + return scanner->ast; +} + +int is_type(struct ctf_scanner *scanner, const char *id); + +#endif /* _CTF_SCANNER_H */ diff --git a/src/plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp b/src/plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp new file mode 100644 index 00000000..c53c4d8a --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp @@ -0,0 +1,4744 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * Copyright 2015-2018 Philippe Proulx + * + * Common Trace Format metadata visitor (generates CTF IR objects). + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#define BT_COMP_LOG_SELF_COMP (ctx->log_cfg.self_comp) +#define BT_COMP_LOG_SELF_COMP_CLASS (ctx->log_cfg.self_comp_class) +#define BT_LOG_OUTPUT_LEVEL (ctx->log_cfg.log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/IR-VISITOR" +#include "logging.hpp" +#include "logging/comp-logging.h" + +#include "common/assert.h" +#include "common/common.h" +#include "common/uuid.h" +#include "compat/endian.h" /* IWYU pragma: keep */ + +#include "ast.hpp" +#include "ctf-meta-visitors.hpp" +#include "ctf-meta.hpp" +#include "decoder.hpp" + +/* Bit value (left shift) */ +#define _BV(_val) (1 << (_val)) + +/* Bit is set in a set of bits */ +#define _IS_SET(_set, _mask) (*(_set) & (_mask)) + +/* Set bit in a set of bits */ +#define _SET(_set, _mask) (*(_set) |= (_mask)) + +/* Try to push scope, or go to the `error` label */ +#define _TRY_PUSH_SCOPE_OR_GOTO_ERROR() \ + do { \ + ret = ctx_push_scope(ctx); \ + if (ret) { \ + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot push scope."); \ + goto error; \ + } \ + } while (0) + +/* Bits for verifying existing attributes in various declarations */ +enum +{ + _CLOCK_NAME_SET = _BV(0), + _CLOCK_UUID_SET = _BV(1), + _CLOCK_FREQ_SET = _BV(2), + _CLOCK_PRECISION_SET = _BV(3), + _CLOCK_OFFSET_S_SET = _BV(4), + _CLOCK_OFFSET_SET = _BV(5), + _CLOCK_ABSOLUTE_SET = _BV(6), + _CLOCK_DESCRIPTION_SET = _BV(7), +}; + +enum +{ + _INTEGER_ALIGN_SET = _BV(0), + _INTEGER_SIZE_SET = _BV(1), + _INTEGER_BASE_SET = _BV(2), + _INTEGER_ENCODING_SET = _BV(3), + _INTEGER_BYTE_ORDER_SET = _BV(4), + _INTEGER_SIGNED_SET = _BV(5), + _INTEGER_MAP_SET = _BV(6), +}; + +enum +{ + _FLOAT_ALIGN_SET = _BV(0), + _FLOAT_MANT_DIG_SET = _BV(1), + _FLOAT_EXP_DIG_SET = _BV(2), + _FLOAT_BYTE_ORDER_SET = _BV(3), +}; + +enum +{ + _STRING_ENCODING_SET = _BV(0), +}; + +enum +{ + _TRACE_MINOR_SET = _BV(0), + _TRACE_MAJOR_SET = _BV(1), + _TRACE_BYTE_ORDER_SET = _BV(2), + _TRACE_UUID_SET = _BV(3), + _TRACE_PACKET_HEADER_SET = _BV(4), +}; + +enum +{ + _STREAM_ID_SET = _BV(0), + _STREAM_PACKET_CONTEXT_SET = _BV(1), + _STREAM_EVENT_HEADER_SET = _BV(2), + _STREAM_EVENT_CONTEXT_SET = _BV(3), +}; + +enum +{ + _EVENT_NAME_SET = _BV(0), + _EVENT_ID_SET = _BV(1), + _EVENT_MODEL_EMF_URI_SET = _BV(2), + _EVENT_STREAM_ID_SET = _BV(3), + _EVENT_LOG_LEVEL_SET = _BV(4), + _EVENT_CONTEXT_SET = _BV(5), + _EVENT_FIELDS_SET = _BV(6), +}; + +enum loglevel +{ + LOG_LEVEL_EMERG = 0, + LOG_LEVEL_ALERT = 1, + LOG_LEVEL_CRIT = 2, + LOG_LEVEL_ERR = 3, + LOG_LEVEL_WARNING = 4, + LOG_LEVEL_NOTICE = 5, + LOG_LEVEL_INFO = 6, + LOG_LEVEL_DEBUG_SYSTEM = 7, + LOG_LEVEL_DEBUG_PROGRAM = 8, + LOG_LEVEL_DEBUG_PROCESS = 9, + LOG_LEVEL_DEBUG_MODULE = 10, + LOG_LEVEL_DEBUG_UNIT = 11, + LOG_LEVEL_DEBUG_FUNCTION = 12, + LOG_LEVEL_DEBUG_LINE = 13, + LOG_LEVEL_DEBUG = 14, + _NR_LOGLEVELS = 15, +}; + +/* Prefixes of class aliases */ +#define _PREFIX_ALIAS 'a' +#define _PREFIX_ENUM 'e' +#define _PREFIX_STRUCT 's' +#define _PREFIX_VARIANT 'v' + +/* First entry in a BT list */ +#define _BT_LIST_FIRST_ENTRY(_ptr, _class, _member) bt_list_entry((_ptr)->next, _class, _member) + +#define _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(_node, _attr, _entity) \ + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( \ + (_node)->lineno, "Duplicate attribute in %s: attr-name=\"%s\"", _entity, _attr) + +#define _BT_COMP_LOGE_NODE(_node, _msg, args...) _BT_COMP_LOGE_LINENO((_node)->lineno, _msg, ##args) + +#define _BT_COMP_LOGE_APPEND_CAUSE_NODE(_node, _msg, args...) \ + _BT_COMP_LOGE_APPEND_CAUSE_LINENO((_node)->lineno, _msg, ##args) + +#define _BT_COMP_LOGW_NODE(_node, _msg, args...) _BT_COMP_LOGW_LINENO((_node)->lineno, _msg, ##args) + +#define _BT_COMP_LOGT_NODE(_node, _msg, args...) _BT_COMP_LOGT_LINENO((_node)->lineno, _msg, ##args) + +/* + * Declaration scope of a visitor context. This represents a TSDL + * lexical scope, so that aliases and named structures, variants, + * and enumerations may be registered and looked up hierarchically. + */ +struct ctx_decl_scope +{ + /* + * Alias name to field class. + * + * GQuark -> struct ctf_field_class * (owned by this) + */ + GHashTable *decl_map; + + /* Parent scope; NULL if this is the root declaration scope */ + struct ctx_decl_scope *parent_scope; +}; + +/* + * Visitor context (private). + */ +struct ctf_visitor_generate_ir +{ + struct meta_log_config log_cfg; + + /* Trace IR trace class being filled (owned by this) */ + bt_trace_class *trace_class; + + /* CTF meta trace being filled (owned by this) */ + struct ctf_trace_class *ctf_tc; + + /* Current declaration scope (top of the stack) (owned by this) */ + struct ctx_decl_scope *current_scope; + + /* True if trace declaration is visited */ + bool is_trace_visited; + + /* True if this is an LTTng trace */ + bool is_lttng; + + /* Config passed by the user */ + struct ctf_metadata_decoder_config decoder_config; +}; + +/* + * Visitor (public). + */ +struct ctf_visitor_generate_ir; + +/** + * Creates a new declaration scope. + * + * @param par_scope Parent scope (NULL if creating a root scope) + * @returns New declaration scope, or NULL on error + */ +static struct ctx_decl_scope *ctx_decl_scope_create(struct ctf_visitor_generate_ir *ctx, + struct ctx_decl_scope *par_scope) +{ + struct ctx_decl_scope *scope; + + scope = g_new(struct ctx_decl_scope, 1); + if (!scope) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one declaration scope."); + goto end; + } + + scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, + (GDestroyNotify) ctf_field_class_destroy); + scope->parent_scope = par_scope; + +end: + return scope; +} + +/** + * Destroys a declaration scope. + * + * This function does not destroy the parent scope. + * + * @param scope Scope to destroy + */ +static void ctx_decl_scope_destroy(struct ctx_decl_scope *scope) +{ + if (!scope) { + goto end; + } + + g_hash_table_destroy(scope->decl_map); + g_free(scope); + +end: + return; +} + +/** + * Returns the GQuark of a prefixed alias. + * + * @param prefix Prefix character + * @param name Name + * @returns Associated GQuark, or 0 on error + */ +static GQuark get_prefixed_named_quark(char prefix, const char *name) +{ + BT_ASSERT(name); + std::string prname = std::string {prefix} + name; + return g_quark_from_string(prname.c_str()); +} + +/** + * Looks up a prefixed class alias within a declaration scope. + * + * @param scope Declaration scope + * @param prefix Prefix character + * @param name Alias name + * @param levels Number of levels to dig into (-1 means infinite) + * @param copy True to return a copy + * @returns Declaration (owned by caller if \p copy is true), + * or NULL if not found + */ +static struct ctf_field_class *ctx_decl_scope_lookup_prefix_alias(struct ctx_decl_scope *scope, + char prefix, const char *name, + int levels, bool copy) +{ + GQuark qname = 0; + int cur_levels = 0; + struct ctf_field_class *decl = NULL; + struct ctx_decl_scope *cur_scope = scope; + + BT_ASSERT(scope); + BT_ASSERT(name); + qname = get_prefixed_named_quark(prefix, name); + if (!qname) { + goto end; + } + + if (levels < 0) { + levels = INT_MAX; + } + + while (cur_scope && cur_levels < levels) { + decl = (ctf_field_class *) g_hash_table_lookup(cur_scope->decl_map, + (gconstpointer) GUINT_TO_POINTER(qname)); + if (decl) { + /* Caller's reference */ + if (copy) { + decl = ctf_field_class_copy(decl); + BT_ASSERT(decl); + } + + goto end; + } + + cur_scope = cur_scope->parent_scope; + cur_levels++; + } + +end: + return decl; +} + +/** + * Looks up a class alias within a declaration scope. + * + * @param scope Declaration scope + * @param name Alias name + * @param levels Number of levels to dig into (-1 means infinite) + * @param copy True to return a copy + * @returns Declaration (owned by caller if \p copy is true), + * or NULL if not found + */ +static struct ctf_field_class *ctx_decl_scope_lookup_alias(struct ctx_decl_scope *scope, + const char *name, int levels, bool copy) +{ + return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS, name, levels, copy); +} + +/** + * Looks up an enumeration within a declaration scope. + * + * @param scope Declaration scope + * @param name Enumeration name + * @param levels Number of levels to dig into (-1 means infinite) + * @param copy True to return a copy + * @returns Declaration (owned by caller if \p copy is true), + * or NULL if not found + */ +static struct ctf_field_class_enum * +ctx_decl_scope_lookup_enum(struct ctx_decl_scope *scope, const char *name, int levels, bool copy) +{ + return ctf_field_class_as_enum( + ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM, name, levels, copy)); +} + +/** + * Looks up a structure within a declaration scope. + * + * @param scope Declaration scope + * @param name Structure name + * @param levels Number of levels to dig into (-1 means infinite) + * @param copy True to return a copy + * @returns Declaration (owned by caller if \p copy is true), + * or NULL if not found + */ +static struct ctf_field_class_struct * +ctx_decl_scope_lookup_struct(struct ctx_decl_scope *scope, const char *name, int levels, bool copy) +{ + return ctf_field_class_as_struct( + ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_STRUCT, name, levels, copy)); +} + +/** + * Looks up a variant within a declaration scope. + * + * @param scope Declaration scope + * @param name Variant name + * @param levels Number of levels to dig into (-1 means infinite) + * @param copy True to return a copy + * @returns Declaration (owned by caller if \p copy is true), + * or NULL if not found + */ +static struct ctf_field_class_variant * +ctx_decl_scope_lookup_variant(struct ctx_decl_scope *scope, const char *name, int levels, bool copy) +{ + return ctf_field_class_as_variant( + ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_VARIANT, name, levels, copy)); +} + +/** + * Registers a prefixed class alias within a declaration scope. + * + * @param scope Declaration scope + * @param prefix Prefix character + * @param name Alias name (non-NULL) + * @param decl Field class to register (copied) + * @returns 0 if registration went okay, negative value otherwise + */ +static int ctx_decl_scope_register_prefix_alias(struct ctx_decl_scope *scope, char prefix, + const char *name, struct ctf_field_class *decl) +{ + int ret = 0; + GQuark qname = 0; + + BT_ASSERT(scope); + BT_ASSERT(name); + BT_ASSERT(decl); + qname = get_prefixed_named_quark(prefix, name); + if (!qname) { + ret = -ENOMEM; + goto end; + } + + /* Make sure alias does not exist in local scope */ + if (ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1, false)) { + ret = -EEXIST; + goto end; + } + + decl = ctf_field_class_copy(decl); + BT_ASSERT(decl); + g_hash_table_insert(scope->decl_map, GUINT_TO_POINTER(qname), decl); + +end: + return ret; +} + +/** + * Registers a class alias within a declaration scope. + * + * @param scope Declaration scope + * @param name Alias name (non-NULL) + * @param decl Field class to register (copied) + * @returns 0 if registration went okay, negative value otherwise + */ +static int ctx_decl_scope_register_alias(struct ctx_decl_scope *scope, const char *name, + struct ctf_field_class *decl) +{ + return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ALIAS, name, decl); +} + +/** + * Registers an enumeration declaration within a declaration scope. + * + * @param scope Declaration scope + * @param name Enumeration name (non-NULL) + * @param decl Enumeration field class to register (copied) + * @returns 0 if registration went okay, negative value otherwise + */ +static int ctx_decl_scope_register_enum(struct ctx_decl_scope *scope, const char *name, + struct ctf_field_class_enum *decl) +{ + return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM, name, &decl->base.base.base); +} + +/** + * Registers a structure declaration within a declaration scope. + * + * @param scope Declaration scope + * @param name Structure name (non-NULL) + * @param decl Structure field class to register (copied) + * @returns 0 if registration went okay, negative value otherwise + */ +static int ctx_decl_scope_register_struct(struct ctx_decl_scope *scope, const char *name, + struct ctf_field_class_struct *decl) +{ + return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT, name, &decl->base); +} + +/** + * Registers a variant declaration within a declaration scope. + * + * @param scope Declaration scope + * @param name Variant name (non-NULL) + * @param decl Variant field class to register + * @returns 0 if registration went okay, negative value otherwise + */ +static int ctx_decl_scope_register_variant(struct ctx_decl_scope *scope, const char *name, + struct ctf_field_class_variant *decl) +{ + return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT, name, &decl->base); +} + +/** + * Destroys a visitor context. + * + * @param ctx Visitor context to destroy + */ +static void ctx_destroy(struct ctf_visitor_generate_ir *ctx) +{ + struct ctx_decl_scope *scope; + + if (!ctx) { + goto end; + } + + scope = ctx->current_scope; + + /* + * Destroy all scopes, from current one to the root scope. + */ + while (scope) { + struct ctx_decl_scope *parent_scope = scope->parent_scope; + + ctx_decl_scope_destroy(scope); + scope = parent_scope; + } + + bt_trace_class_put_ref(ctx->trace_class); + + if (ctx->ctf_tc) { + ctf_trace_class_destroy(ctx->ctf_tc); + } + + g_free(ctx); + +end: + return; +} + +/** + * Creates a new visitor context. + * + * @param trace Associated trace + * @returns New visitor context, or NULL on error + */ +static struct ctf_visitor_generate_ir * +ctx_create(const struct ctf_metadata_decoder_config *decoder_config) +{ + struct ctf_visitor_generate_ir *ctx = NULL; + + BT_ASSERT(decoder_config); + + ctx = g_new0(struct ctf_visitor_generate_ir, 1); + if (!ctx) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, decoder_config->log_level, decoder_config->self_comp, + "Failed to allocate one visitor context."); + goto error; + } + + ctx->log_cfg.log_level = decoder_config->log_level; + ctx->log_cfg.self_comp = decoder_config->self_comp; + ctx->log_cfg.self_comp_class = decoder_config->self_comp_class; + + if (decoder_config->self_comp) { + ctx->trace_class = bt_trace_class_create(decoder_config->self_comp); + if (!ctx->trace_class) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create empty trace class."); + goto error; + } + } + + ctx->ctf_tc = ctf_trace_class_create(); + if (!ctx->ctf_tc) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create CTF trace class."); + goto error; + } + + /* Root declaration scope */ + ctx->current_scope = ctx_decl_scope_create(ctx, NULL); + if (!ctx->current_scope) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create declaration scope."); + goto error; + } + + ctx->decoder_config = *decoder_config; + goto end; + +error: + ctx_destroy(ctx); + ctx = NULL; + +end: + return ctx; +} + +/** + * Pushes a new declaration scope on top of a visitor context's + * declaration scope stack. + * + * @param ctx Visitor context + * @returns 0 on success, or a negative value on error + */ +static int ctx_push_scope(struct ctf_visitor_generate_ir *ctx) +{ + int ret = 0; + struct ctx_decl_scope *new_scope; + + BT_ASSERT(ctx); + new_scope = ctx_decl_scope_create(ctx, ctx->current_scope); + if (!new_scope) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create declaration scope."); + ret = -ENOMEM; + goto end; + } + + ctx->current_scope = new_scope; + +end: + return ret; +} + +static void ctx_pop_scope(struct ctf_visitor_generate_ir *ctx) +{ + struct ctx_decl_scope *parent_scope = NULL; + + BT_ASSERT(ctx); + + if (!ctx->current_scope) { + goto end; + } + + parent_scope = ctx->current_scope->parent_scope; + ctx_decl_scope_destroy(ctx->current_scope); + ctx->current_scope = parent_scope; + +end: + return; +} + +static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *ts_list, + struct ctf_field_class **decl); + +static int is_unary_string(struct bt_list_head *head) +{ + int ret = TRUE; + struct ctf_node *node; + + bt_list_for_each_entry (node, head, siblings) { + if (node->type != NODE_UNARY_EXPRESSION) { + ret = FALSE; + } + + if (node->u.unary_expression.type != UNARY_STRING) { + ret = FALSE; + } + } + + return ret; +} + +static const char *get_map_clock_name_value(struct bt_list_head *head) +{ + int i = 0; + struct ctf_node *node; + const char *name = NULL; + + bt_list_for_each_entry (node, head, siblings) { + char *src_string; + int uexpr_type = node->u.unary_expression.type; + int uexpr_link = node->u.unary_expression.link; + int cond = node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_STRING || + !((uexpr_link != UNARY_LINK_UNKNOWN) ^ (i == 0)); + if (cond) { + goto error; + } + + /* Needs to be chained with . */ + switch (node->u.unary_expression.link) { + case UNARY_DOTLINK: + break; + case UNARY_ARROWLINK: + case UNARY_DOTDOTDOT: + goto error; + default: + break; + } + + src_string = node->u.unary_expression.u.string; + + switch (i) { + case 0: + if (strcmp("clock", src_string)) { + goto error; + } + break; + case 1: + name = src_string; + break; + case 2: + if (strcmp("value", src_string)) { + goto error; + } + break; + default: + /* Extra identifier, unknown */ + goto error; + } + + i++; + } + + return name; + +error: + return NULL; +} + +static int is_unary_unsigned(struct bt_list_head *head) +{ + int ret = TRUE; + struct ctf_node *node; + + bt_list_for_each_entry (node, head, siblings) { + if (node->type != NODE_UNARY_EXPRESSION) { + ret = FALSE; + } + + if (node->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { + ret = FALSE; + } + } + + return ret; +} + +static int get_unary_unsigned(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *head, + uint64_t *value) +{ + int i = 0; + int ret = 0; + struct ctf_node *node; + + *value = 0; + + if (bt_list_empty(head)) { + ret = -1; + goto end; + } + + bt_list_for_each_entry (node, head, siblings) { + int uexpr_type = node->u.unary_expression.type; + int uexpr_link = node->u.unary_expression.link; + int cond = node->type != NODE_UNARY_EXPRESSION || uexpr_type != UNARY_UNSIGNED_CONSTANT || + uexpr_link != UNARY_LINK_UNKNOWN || i != 0; + if (cond) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Invalid constant unsigned integer."); + ret = -EINVAL; + goto end; + } + + *value = node->u.unary_expression.u.unsigned_constant; + i++; + } + +end: + return ret; +} + +static int is_unary_signed(struct bt_list_head *head) +{ + int ret = TRUE; + struct ctf_node *node; + + bt_list_for_each_entry (node, head, siblings) { + if (node->type != NODE_UNARY_EXPRESSION) { + ret = FALSE; + } + + if (node->u.unary_expression.type != UNARY_SIGNED_CONSTANT) { + ret = FALSE; + } + } + + return ret; +} + +static int get_unary_signed(struct bt_list_head *head, int64_t *value) +{ + int i = 0; + int ret = 0; + struct ctf_node *node; + + bt_list_for_each_entry (node, head, siblings) { + int uexpr_type = node->u.unary_expression.type; + int uexpr_link = node->u.unary_expression.link; + int cond = node->type != NODE_UNARY_EXPRESSION || + (uexpr_type != UNARY_UNSIGNED_CONSTANT && uexpr_type != UNARY_SIGNED_CONSTANT) || + uexpr_link != UNARY_LINK_UNKNOWN || i != 0; + if (cond) { + ret = -EINVAL; + goto end; + } + + switch (uexpr_type) { + case UNARY_UNSIGNED_CONSTANT: + *value = (int64_t) node->u.unary_expression.u.unsigned_constant; + break; + case UNARY_SIGNED_CONSTANT: + *value = node->u.unary_expression.u.signed_constant; + break; + default: + ret = -EINVAL; + goto end; + } + + i++; + } + +end: + return ret; +} + +static int get_unary_uuid(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *head, + bt_uuid_t uuid) +{ + return ctf_ast_get_unary_uuid(head, uuid, ctx->log_cfg.log_level, ctx->log_cfg.self_comp); +} + +static int get_boolean(struct ctf_visitor_generate_ir *ctx, struct ctf_node *unary_expr) +{ + int ret = 0; + + if (unary_expr->type != NODE_UNARY_EXPRESSION) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(unary_expr, "Expecting unary expression: node-type=%d", + unary_expr->type); + ret = -EINVAL; + goto end; + } + + switch (unary_expr->u.unary_expression.type) { + case UNARY_UNSIGNED_CONSTANT: + ret = (unary_expr->u.unary_expression.u.unsigned_constant != 0); + break; + case UNARY_SIGNED_CONSTANT: + ret = (unary_expr->u.unary_expression.u.signed_constant != 0); + break; + case UNARY_STRING: + { + const char *str = unary_expr->u.unary_expression.u.string; + + if (strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0) { + ret = TRUE; + } else if (strcmp(str, "false") == 0 || strcmp(str, "FALSE") == 0) { + ret = FALSE; + } else { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(unary_expr, "Unexpected boolean value: value=\"%s\"", + str); + ret = -EINVAL; + goto end; + } + break; + } + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(unary_expr, + "Unexpected unary expression type: node-type=%d", + unary_expr->u.unary_expression.type); + ret = -EINVAL; + goto end; + } + +end: + return ret; +} + +static enum ctf_byte_order byte_order_from_unary_expr(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *unary_expr) +{ + const char *str; + enum ctf_byte_order bo = CTF_BYTE_ORDER_UNKNOWN; + + if (unary_expr->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + unary_expr, "\"byte_order\" attribute: expecting `be`, `le`, `network`, or `native`."); + goto end; + } + + str = unary_expr->u.unary_expression.u.string; + + if (strcmp(str, "be") == 0 || strcmp(str, "network") == 0) { + bo = CTF_BYTE_ORDER_BIG; + } else if (strcmp(str, "le") == 0) { + bo = CTF_BYTE_ORDER_LITTLE; + } else if (strcmp(str, "native") == 0) { + bo = CTF_BYTE_ORDER_DEFAULT; + } else { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + unary_expr, + "Unexpected \"byte_order\" attribute value: " + "expecting `be`, `le`, `network`, or `native`: value=\"%s\"", + str); + goto end; + } + +end: + return bo; +} + +static enum ctf_byte_order get_real_byte_order(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *uexpr) +{ + enum ctf_byte_order bo = byte_order_from_unary_expr(ctx, uexpr); + + if (bo == CTF_BYTE_ORDER_DEFAULT) { + bo = ctx->ctf_tc->default_byte_order; + } + + return bo; +} + +static int is_align_valid(uint64_t align) +{ + return (align != 0) && !(align & (align - UINT64_C(1))); +} + +static int get_class_specifier_name(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *cls_specifier, GString *str) +{ + int ret = 0; + + if (cls_specifier->type != NODE_TYPE_SPECIFIER) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier, "Unexpected node type: node-type=%d", + cls_specifier->type); + ret = -EINVAL; + goto end; + } + + switch (cls_specifier->u.field_class_specifier.type) { + case TYPESPEC_VOID: + g_string_append(str, "void"); + break; + case TYPESPEC_CHAR: + g_string_append(str, "char"); + break; + case TYPESPEC_SHORT: + g_string_append(str, "short"); + break; + case TYPESPEC_INT: + g_string_append(str, "int"); + break; + case TYPESPEC_LONG: + g_string_append(str, "long"); + break; + case TYPESPEC_FLOAT: + g_string_append(str, "float"); + break; + case TYPESPEC_DOUBLE: + g_string_append(str, "double"); + break; + case TYPESPEC_SIGNED: + g_string_append(str, "signed"); + break; + case TYPESPEC_UNSIGNED: + g_string_append(str, "unsigned"); + break; + case TYPESPEC_BOOL: + g_string_append(str, "bool"); + break; + case TYPESPEC_COMPLEX: + g_string_append(str, "_Complex"); + break; + case TYPESPEC_IMAGINARY: + g_string_append(str, "_Imaginary"); + break; + case TYPESPEC_CONST: + g_string_append(str, "const"); + break; + case TYPESPEC_ID_TYPE: + if (cls_specifier->u.field_class_specifier.id_type) { + g_string_append(str, cls_specifier->u.field_class_specifier.id_type); + } + break; + case TYPESPEC_STRUCT: + { + struct ctf_node *node = cls_specifier->u.field_class_specifier.node; + + if (!node->u._struct.name) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unexpected empty structure field class name."); + ret = -EINVAL; + goto end; + } + + g_string_append(str, "struct "); + g_string_append(str, node->u._struct.name); + break; + } + case TYPESPEC_VARIANT: + { + struct ctf_node *node = cls_specifier->u.field_class_specifier.node; + + if (!node->u.variant.name) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unexpected empty variant field class name."); + ret = -EINVAL; + goto end; + } + + g_string_append(str, "variant "); + g_string_append(str, node->u.variant.name); + break; + } + case TYPESPEC_ENUM: + { + struct ctf_node *node = cls_specifier->u.field_class_specifier.node; + + if (!node->u._enum.enum_id) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Unexpected empty enumeration field class (`enum`) name."); + ret = -EINVAL; + goto end; + } + + g_string_append(str, "enum "); + g_string_append(str, node->u._enum.enum_id); + break; + } + case TYPESPEC_FLOATING_POINT: + case TYPESPEC_INTEGER: + case TYPESPEC_STRING: + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier->u.field_class_specifier.node, + "Unexpected field class specifier type: %d", + cls_specifier->u.field_class_specifier.type); + ret = -EINVAL; + goto end; + } + +end: + return ret; +} + +static int get_class_specifier_list_name(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *cls_specifier_list, GString *str) +{ + int ret = 0; + struct ctf_node *iter; + int alias_item_nr = 0; + struct bt_list_head *head = &cls_specifier_list->u.field_class_specifier_list.head; + + bt_list_for_each_entry (iter, head, siblings) { + if (alias_item_nr != 0) { + g_string_append(str, " "); + } + + alias_item_nr++; + ret = get_class_specifier_name(ctx, iter, str); + if (ret) { + goto end; + } + } + +end: + return ret; +} + +static GQuark create_class_alias_identifier(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *cls_specifier_list, + struct ctf_node *node_field_class_declarator) +{ + int ret; + char *str_c; + GString *str; + GQuark qalias = 0; + struct ctf_node *iter; + struct bt_list_head *pointers = &node_field_class_declarator->u.field_class_declarator.pointers; + + str = g_string_new(""); + ret = get_class_specifier_list_name(ctx, cls_specifier_list, str); + if (ret) { + g_string_free(str, TRUE); + goto end; + } + + bt_list_for_each_entry (iter, pointers, siblings) { + g_string_append(str, " *"); + + if (iter->u.pointer.const_qualifier) { + g_string_append(str, " const"); + } + } + + str_c = g_string_free(str, FALSE); + qalias = g_quark_from_string(str_c); + g_free(str_c); + +end: + return qalias; +} + +static int visit_field_class_declarator(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *cls_specifier_list, GQuark *field_name, + struct ctf_node *node_field_class_declarator, + struct ctf_field_class **field_decl, + struct ctf_field_class *nested_decl) +{ + /* + * During this whole function, nested_decl is always OURS, + * whereas field_decl is an output which we create, but + * belongs to the caller (it is moved). + */ + int ret = 0; + *field_decl = NULL; + + /* Validate field class declarator node */ + if (node_field_class_declarator) { + if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_UNKNOWN) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node_field_class_declarator, "Unexpected field class declarator type: type=%d", + node_field_class_declarator->u.field_class_declarator.type); + ret = -EINVAL; + goto error; + } + + /* TODO: GCC bitfields not supported yet */ + if (node_field_class_declarator->u.field_class_declarator.bitfield_len != NULL) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, + "GCC bitfields are not supported as of this version."); + ret = -EPERM; + goto error; + } + } + + /* Find the right nested declaration if not provided */ + if (!nested_decl) { + if (node_field_class_declarator && + !bt_list_empty(&node_field_class_declarator->u.field_class_declarator.pointers)) { + GQuark qalias; + + /* + * If we have a pointer declarator, it HAS to + * be present in the field class aliases (else + * fail). + */ + qalias = + create_class_alias_identifier(ctx, cls_specifier_list, node_field_class_declarator); + nested_decl = ctx_decl_scope_lookup_alias(ctx->current_scope, g_quark_to_string(qalias), + -1, true); + if (!nested_decl) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, + "Cannot find class alias: name=\"%s\"", + g_quark_to_string(qalias)); + ret = -EINVAL; + goto error; + } + + if (nested_decl->type == CTF_FIELD_CLASS_TYPE_INT) { + /* Pointer: force integer's base to 16 */ + struct ctf_field_class_int *int_fc = ctf_field_class_as_int(nested_decl); + + int_fc->disp_base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL; + } + } else { + ret = visit_field_class_specifier_list(ctx, cls_specifier_list, &nested_decl); + if (ret) { + BT_ASSERT(!nested_decl); + goto error; + } + } + } + + BT_ASSERT(nested_decl); + + if (!node_field_class_declarator) { + *field_decl = nested_decl; + nested_decl = NULL; + goto end; + } + + if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_ID) { + if (node_field_class_declarator->u.field_class_declarator.u.id) { + const char *id = node_field_class_declarator->u.field_class_declarator.u.id; + + *field_name = g_quark_from_string(id); + } else { + *field_name = 0; + } + + *field_decl = nested_decl; + nested_decl = NULL; + goto end; + } else { + struct ctf_node *first; + struct ctf_field_class *decl = NULL; + struct ctf_field_class *outer_field_decl = NULL; + struct bt_list_head *length = + &node_field_class_declarator->u.field_class_declarator.u.nested.length; + + /* Create array/sequence, pass nested_decl as child */ + if (bt_list_empty(length)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, + "Expecting length field reference or value."); + ret = -EINVAL; + goto error; + } + + first = _BT_LIST_FIRST_ENTRY(length, struct ctf_node, siblings); + if (first->type != NODE_UNARY_EXPRESSION) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type=%d", + first->type); + ret = -EINVAL; + goto error; + } + + switch (first->u.unary_expression.type) { + case UNARY_UNSIGNED_CONSTANT: + { + struct ctf_field_class_array *array_decl = NULL; + + array_decl = ctf_field_class_array_create(); + BT_ASSERT(array_decl); + array_decl->length = first->u.unary_expression.u.unsigned_constant; + array_decl->base.elem_fc = nested_decl; + nested_decl = NULL; + decl = &array_decl->base.base; + break; + } + case UNARY_STRING: + { + /* Lookup unsigned integer definition, create seq. */ + struct ctf_field_class_sequence *seq_decl = NULL; + char *length_name = ctf_ast_concatenate_unary_strings(length); + + if (!length_name) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, + "Cannot concatenate unary strings."); + ret = -EINVAL; + goto error; + } + + if (strncmp(length_name, "env.", 4) == 0) { + /* This is, in fact, an array */ + const char *env_entry_name = &length_name[4]; + struct ctf_trace_class_env_entry *env_entry = + ctf_trace_class_borrow_env_entry_by_name(ctx->ctf_tc, env_entry_name); + struct ctf_field_class_array *array_decl; + + if (!env_entry) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, + "Cannot find environment entry: " + "name=\"%s\"", + env_entry_name); + ret = -EINVAL; + goto error; + } + + if (env_entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, + "Wrong environment entry type " + "(expecting integer): " + "name=\"%s\"", + env_entry_name); + ret = -EINVAL; + goto error; + } + + if (env_entry->value.i < 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node_field_class_declarator, + "Invalid, negative array length: " + "env-entry-name=\"%s\", " + "value=%" PRId64, + env_entry_name, env_entry->value.i); + ret = -EINVAL; + goto error; + } + + array_decl = ctf_field_class_array_create(); + BT_ASSERT(array_decl); + array_decl->length = (uint64_t) env_entry->value.i; + array_decl->base.elem_fc = nested_decl; + nested_decl = NULL; + decl = &array_decl->base.base; + } else { + seq_decl = ctf_field_class_sequence_create(); + BT_ASSERT(seq_decl); + seq_decl->base.elem_fc = nested_decl; + nested_decl = NULL; + g_string_assign(seq_decl->length_ref, length_name); + decl = &seq_decl->base.base; + } + + g_free(length_name); + break; + } + default: + ret = -EINVAL; + goto error; + } + + BT_ASSERT(!nested_decl); + BT_ASSERT(decl); + BT_ASSERT(!*field_decl); + + /* + * At this point, we found the next nested declaration. + * We currently own this (and lost the ownership of + * nested_decl in the meantime). Pass this next + * nested declaration as the content of the outer + * container, MOVING its ownership. + */ + ret = visit_field_class_declarator( + ctx, cls_specifier_list, field_name, + node_field_class_declarator->u.field_class_declarator.u.nested.field_class_declarator, + &outer_field_decl, decl); + decl = NULL; + if (ret) { + BT_ASSERT(!outer_field_decl); + ret = -EINVAL; + goto error; + } + + BT_ASSERT(outer_field_decl); + *field_decl = outer_field_decl; + outer_field_decl = NULL; + } + + BT_ASSERT(*field_decl); + goto end; + +error: + ctf_field_class_destroy(*field_decl); + *field_decl = NULL; + + if (ret >= 0) { + ret = -1; + } + +end: + ctf_field_class_destroy(nested_decl); + nested_decl = NULL; + return ret; +} + +static int visit_struct_decl_field(struct ctf_visitor_generate_ir *ctx, + struct ctf_field_class_struct *struct_decl, + struct ctf_node *cls_specifier_list, + struct bt_list_head *field_class_declarators) +{ + int ret = 0; + struct ctf_node *iter; + struct ctf_field_class *field_decl = NULL; + + bt_list_for_each_entry (iter, field_class_declarators, siblings) { + field_decl = NULL; + GQuark qfield_name; + const char *field_name; + + ret = visit_field_class_declarator(ctx, cls_specifier_list, &qfield_name, iter, &field_decl, + NULL); + if (ret) { + BT_ASSERT(!field_decl); + _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, + "Cannot visit field class declarator: ret=%d", ret); + goto error; + } + + BT_ASSERT(field_decl); + field_name = g_quark_to_string(qfield_name); + + /* Check if field with same name already exists */ + if (ctf_field_class_struct_borrow_member_by_name(struct_decl, field_name)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, + "Duplicate field in structure field class: " + "field-name=\"%s\"", + field_name); + ret = -EINVAL; + goto error; + } + + /* Add field to structure */ + ctf_field_class_struct_append_member(struct_decl, field_name, field_decl); + field_decl = NULL; + } + + return 0; + +error: + ctf_field_class_destroy(field_decl); + field_decl = NULL; + return ret; +} + +static int visit_variant_decl_field(struct ctf_visitor_generate_ir *ctx, + struct ctf_field_class_variant *variant_decl, + struct ctf_node *cls_specifier_list, + struct bt_list_head *field_class_declarators) +{ + int ret = 0; + struct ctf_node *iter; + struct ctf_field_class *field_decl = NULL; + + bt_list_for_each_entry (iter, field_class_declarators, siblings) { + field_decl = NULL; + GQuark qfield_name; + const char *field_name; + + ret = visit_field_class_declarator(ctx, cls_specifier_list, &qfield_name, iter, &field_decl, + NULL); + if (ret) { + BT_ASSERT(!field_decl); + _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, + "Cannot visit field class declarator: ret=%d", ret); + goto error; + } + + BT_ASSERT(field_decl); + field_name = g_quark_to_string(qfield_name); + + /* Check if field with same name already exists */ + if (ctf_field_class_variant_borrow_option_by_name(variant_decl, field_name)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, + "Duplicate field in variant field class: " + "field-name=\"%s\"", + field_name); + ret = -EINVAL; + goto error; + } + + /* Add field to structure */ + ctf_field_class_variant_append_option(variant_decl, field_name, field_decl); + field_decl = NULL; + } + + return 0; + +error: + ctf_field_class_destroy(field_decl); + field_decl = NULL; + return ret; +} + +static int visit_field_class_def(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *cls_specifier_list, + struct bt_list_head *field_class_declarators) +{ + int ret = 0; + GQuark qidentifier; + struct ctf_node *iter; + struct ctf_field_class *class_decl = NULL; + + bt_list_for_each_entry (iter, field_class_declarators, siblings) { + ret = visit_field_class_declarator(ctx, cls_specifier_list, &qidentifier, iter, &class_decl, + NULL); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit field class declarator: ret=%d", + ret); + ret = -EINVAL; + goto end; + } + + /* Do not allow field class def and alias of untagged variants */ + if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(class_decl); + + if (var_fc->tag_path.path->len == 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + iter, "Type definition of untagged variant field class is not allowed."); + ret = -EPERM; + goto end; + } + } + + ret = ctx_decl_scope_register_alias(ctx->current_scope, g_quark_to_string(qidentifier), + class_decl); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot register field class alias: name=\"%s\"", + g_quark_to_string(qidentifier)); + goto end; + } + } + +end: + ctf_field_class_destroy(class_decl); + class_decl = NULL; + return ret; +} + +static int visit_field_class_alias(struct ctf_visitor_generate_ir *ctx, struct ctf_node *target, + struct ctf_node *alias) +{ + int ret = 0; + GQuark qalias; + struct ctf_node *node; + GQuark qdummy_field_name; + struct ctf_field_class *class_decl = NULL; + + /* Create target field class */ + if (bt_list_empty(&target->u.field_class_alias_target.field_class_declarators)) { + node = NULL; + } else { + node = _BT_LIST_FIRST_ENTRY(&target->u.field_class_alias_target.field_class_declarators, + struct ctf_node, siblings); + } + + ret = visit_field_class_declarator( + ctx, target->u.field_class_alias_target.field_class_specifier_list, &qdummy_field_name, + node, &class_decl, NULL); + if (ret) { + BT_ASSERT(!class_decl); + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot visit field class declarator: ret=%d", ret); + goto end; + } + + /* Do not allow field class def and alias of untagged variants */ + if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) { + struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(class_decl); + + if (var_fc->tag_path.path->len == 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + target, "Type definition of untagged variant field class is not allowed."); + ret = -EPERM; + goto end; + } + } + + /* + * The semantic validator does not check whether the target is + * abstract or not (if it has an identifier). Check it here. + */ + if (qdummy_field_name != 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(target, "Expecting empty identifier: id=\"%s\"", + g_quark_to_string(qdummy_field_name)); + ret = -EINVAL; + goto end; + } + + /* Create alias identifier */ + node = _BT_LIST_FIRST_ENTRY(&alias->u.field_class_alias_name.field_class_declarators, + struct ctf_node, siblings); + qalias = create_class_alias_identifier( + ctx, alias->u.field_class_alias_name.field_class_specifier_list, node); + ret = ctx_decl_scope_register_alias(ctx->current_scope, g_quark_to_string(qalias), class_decl); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot register class alias: name=\"%s\"", + g_quark_to_string(qalias)); + goto end; + } + +end: + ctf_field_class_destroy(class_decl); + class_decl = NULL; + return ret; +} + +static int visit_struct_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *entry_node, + struct ctf_field_class_struct *struct_decl) +{ + int ret = 0; + + switch (entry_node->type) { + case NODE_TYPEDEF: + ret = visit_field_class_def(ctx, entry_node->u.field_class_def.field_class_specifier_list, + &entry_node->u.field_class_def.field_class_declarators); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Cannot add field class found in structure field class: ret=%d", ret); + goto end; + } + break; + case NODE_TYPEALIAS: + ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target, + entry_node->u.field_class_alias.alias); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Cannot add field class alias found in structure field class: ret=%d", + ret); + goto end; + } + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + /* Field */ + ret = visit_struct_decl_field( + ctx, struct_decl, + entry_node->u.struct_or_variant_declaration.field_class_specifier_list, + &entry_node->u.struct_or_variant_declaration.field_class_declarators); + if (ret) { + goto end; + } + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type=%d", + entry_node->type); + ret = -EINVAL; + goto end; + } + +end: + return ret; +} + +static int visit_variant_decl_entry(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *entry_node, + struct ctf_field_class_variant *variant_decl) +{ + int ret = 0; + + switch (entry_node->type) { + case NODE_TYPEDEF: + ret = visit_field_class_def(ctx, entry_node->u.field_class_def.field_class_specifier_list, + &entry_node->u.field_class_def.field_class_declarators); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Cannot add field class found in variant field class: ret=%d", ret); + goto end; + } + break; + case NODE_TYPEALIAS: + ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target, + entry_node->u.field_class_alias.alias); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Cannot add field class alias found in variant field class: ret=%d", + ret); + goto end; + } + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + /* Field */ + ret = visit_variant_decl_field( + ctx, variant_decl, + entry_node->u.struct_or_variant_declaration.field_class_specifier_list, + &entry_node->u.struct_or_variant_declaration.field_class_declarators); + if (ret) { + goto end; + } + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type=%d", + entry_node->type); + ret = -EINVAL; + goto end; + } + +end: + return ret; +} + +static int visit_struct_decl(struct ctf_visitor_generate_ir *ctx, const char *name, + struct bt_list_head *decl_list, int has_body, + struct bt_list_head *min_align, + struct ctf_field_class_struct **struct_decl) +{ + int ret = 0; + + BT_ASSERT(struct_decl); + *struct_decl = NULL; + + /* For named struct (without body), lookup in declaration scope */ + if (!has_body) { + if (!name) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Bodyless structure field class: missing name."); + ret = -EPERM; + goto error; + } + + *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope, name, -1, true); + if (!*struct_decl) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot find structure field class: name=\"struct %s\"", name); + ret = -EINVAL; + goto error; + } + } else { + struct ctf_node *entry_node; + uint64_t min_align_value = 0; + + if (name) { + if (ctx_decl_scope_lookup_struct(ctx->current_scope, name, 1, false)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Structure field class already declared in local scope: " + "name=\"struct %s\"", + name); + ret = -EINVAL; + goto error; + } + } + + if (!bt_list_empty(min_align)) { + ret = get_unary_unsigned(ctx, min_align, &min_align_value); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Unexpected unary expression for structure field class's `align` attribute: " + "ret=%d", + ret); + goto error; + } + } + + *struct_decl = ctf_field_class_struct_create(); + BT_ASSERT(*struct_decl); + + if (min_align_value != 0) { + (*struct_decl)->base.alignment = min_align_value; + } + + _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); + + bt_list_for_each_entry (entry_node, decl_list, siblings) { + ret = visit_struct_decl_entry(ctx, entry_node, *struct_decl); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, + "Cannot visit structure field class entry: " + "ret=%d", + ret); + ctx_pop_scope(ctx); + goto error; + } + } + + ctx_pop_scope(ctx); + + if (name) { + ret = ctx_decl_scope_register_struct(ctx->current_scope, name, *struct_decl); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot register structure field class in declaration scope: " + "name=\"struct %s\", ret=%d", + name, ret); + goto error; + } + } + } + + return 0; + +error: + ctf_field_class_destroy(&(*struct_decl)->base); + *struct_decl = NULL; + return ret; +} + +static int visit_variant_decl(struct ctf_visitor_generate_ir *ctx, const char *name, + const char *tag, struct bt_list_head *decl_list, int has_body, + struct ctf_field_class_variant **variant_decl) +{ + int ret = 0; + struct ctf_field_class_variant *untagged_variant_decl = NULL; + + BT_ASSERT(variant_decl); + *variant_decl = NULL; + + /* For named variant (without body), lookup in declaration scope */ + if (!has_body) { + if (!name) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Bodyless variant field class: missing name."); + ret = -EPERM; + goto error; + } + + untagged_variant_decl = ctx_decl_scope_lookup_variant(ctx->current_scope, name, -1, true); + if (!untagged_variant_decl) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot find variant field class: name=\"variant %s\"", name); + ret = -EINVAL; + goto error; + } + } else { + struct ctf_node *entry_node; + + if (name) { + if (ctx_decl_scope_lookup_variant(ctx->current_scope, name, 1, false)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Variant field class already declared in local scope: " + "name=\"variant %s\"", + name); + ret = -EINVAL; + goto error; + } + } + + untagged_variant_decl = ctf_field_class_variant_create(); + BT_ASSERT(untagged_variant_decl); + _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); + + bt_list_for_each_entry (entry_node, decl_list, siblings) { + ret = visit_variant_decl_entry(ctx, entry_node, untagged_variant_decl); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, + "Cannot visit variant field class entry: " + "ret=%d", + ret); + ctx_pop_scope(ctx); + goto error; + } + } + + ctx_pop_scope(ctx); + + if (name) { + ret = ctx_decl_scope_register_variant(ctx->current_scope, name, untagged_variant_decl); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot register variant field class in declaration scope: " + "name=\"variant %s\", ret=%d", + name, ret); + goto error; + } + } + } + + /* + * If tagged, create tagged variant and return; otherwise + * return untagged variant. + */ + if (!tag) { + *variant_decl = untagged_variant_decl; + untagged_variant_decl = NULL; + } else { + /* + * At this point, we have a fresh untagged variant; nobody + * else owns it. Set its tag now. + */ + g_string_assign(untagged_variant_decl->tag_ref, tag); + *variant_decl = untagged_variant_decl; + untagged_variant_decl = NULL; + } + + BT_ASSERT(!untagged_variant_decl); + BT_ASSERT(*variant_decl); + return 0; + +error: + ctf_field_class_destroy(&untagged_variant_decl->base); + untagged_variant_decl = NULL; + ctf_field_class_destroy(&(*variant_decl)->base); + *variant_decl = NULL; + return ret; +} + +struct uori +{ + bool is_signed; + union + { + uint64_t u; + uint64_t i; + } value; +}; + +static int visit_enum_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *enumerator, + struct ctf_field_class_enum *enum_decl, struct uori *last) +{ + int ret = 0; + int nr_vals = 0; + struct ctf_node *iter; + struct uori start = { + .is_signed = false, + .value = + { + .u = 0, + }, + }; + struct uori end = { + .is_signed = false, + .value = + { + .u = 0, + }, + }; + const char *label = enumerator->u.enumerator.id; + struct bt_list_head *values = &enumerator->u.enumerator.values; + + bt_list_for_each_entry (iter, values, siblings) { + struct uori *target; + + if (iter->type != NODE_UNARY_EXPRESSION) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, + "Wrong expression for enumeration field class label: " + "node-type=%d, label=\"%s\"", + iter->type, label); + ret = -EINVAL; + goto error; + } + + if (nr_vals == 0) { + target = &start; + } else { + target = &end; + } + + switch (iter->u.unary_expression.type) { + case UNARY_SIGNED_CONSTANT: + target->is_signed = true; + target->value.i = iter->u.unary_expression.u.signed_constant; + break; + case UNARY_UNSIGNED_CONSTANT: + target->is_signed = false; + target->value.u = iter->u.unary_expression.u.unsigned_constant; + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, + "Invalid enumeration field class entry: " + "expecting constant signed or unsigned integer: " + "node-type=%d, label=\"%s\"", + iter->u.unary_expression.type, label); + ret = -EINVAL; + goto error; + } + + if (nr_vals > 1) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + iter, "Invalid enumeration field class entry: label=\"%s\"", label); + ret = -EINVAL; + goto error; + } + + nr_vals++; + } + + if (nr_vals == 0) { + start = *last; + } + + if (nr_vals <= 1) { + end = start; + } + + if (end.is_signed) { + last->value.i = end.value.i + 1; + } else { + last->value.u = end.value.u + 1; + } + + ctf_field_class_enum_map_range(enum_decl, label, start.value.u, end.value.u); + return 0; + +error: + return ret; +} + +static int visit_enum_decl(struct ctf_visitor_generate_ir *ctx, const char *name, + struct ctf_node *container_cls, struct bt_list_head *enumerator_list, + int has_body, struct ctf_field_class_enum **enum_decl) +{ + int ret = 0; + GQuark qdummy_id; + struct ctf_field_class_int *integer_decl = NULL; + + BT_ASSERT(enum_decl); + *enum_decl = NULL; + + /* For named enum (without body), lookup in declaration scope */ + if (!has_body) { + if (!name) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Bodyless enumeration field class: missing name."); + ret = -EPERM; + goto error; + } + + *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope, name, -1, true); + if (!*enum_decl) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot find enumeration field class: " + "name=\"enum %s\"", + name); + ret = -EINVAL; + goto error; + } + } else { + struct ctf_node *iter; + struct uori last_value = { + .is_signed = false, + .value = + { + .u = 0, + }, + }; + + if (name) { + if (ctx_decl_scope_lookup_enum(ctx->current_scope, name, 1, false)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Enumeration field class already declared in local scope: " + "name=\"enum %s\"", + name); + ret = -EINVAL; + goto error; + } + } + + if (!container_cls) { + integer_decl = ctf_field_class_as_int( + ctx_decl_scope_lookup_alias(ctx->current_scope, "int", -1, true)); + if (!integer_decl) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot find implicit `int` field class alias for enumeration field class."); + ret = -EINVAL; + goto error; + } + } else { + ctf_field_class *decl; + + ret = visit_field_class_declarator(ctx, container_cls, &qdummy_id, NULL, &decl, NULL); + if (ret) { + BT_ASSERT(!decl); + ret = -EINVAL; + goto error; + } + + integer_decl = ctf_field_class_as_int(decl); + } + + BT_ASSERT(integer_decl); + + if (integer_decl->base.base.type != CTF_FIELD_CLASS_TYPE_INT) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Container field class for enumeration field class is not an integer field class: " + "fc-type=%d", + integer_decl->base.base.type); + ret = -EINVAL; + goto error; + } + + *enum_decl = ctf_field_class_enum_create(); + BT_ASSERT(*enum_decl); + (*enum_decl)->base.base.base.alignment = integer_decl->base.base.alignment; + ctf_field_class_int_copy_content(&(*enum_decl)->base, integer_decl); + last_value.is_signed = (*enum_decl)->base.is_signed; + + bt_list_for_each_entry (iter, enumerator_list, siblings) { + ret = visit_enum_decl_entry(ctx, iter, *enum_decl, &last_value); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, + "Cannot visit enumeration field class entry: " + "ret=%d", + ret); + goto error; + } + } + + if (name) { + ret = ctx_decl_scope_register_enum(ctx->current_scope, name, *enum_decl); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot register enumeration field class in declaration scope: " + "ret=%d", + ret); + goto error; + } + } + } + + goto end; + +error: + ctf_field_class_destroy(&(*enum_decl)->base.base.base); + *enum_decl = NULL; + +end: + ctf_field_class_destroy(&integer_decl->base.base); + integer_decl = NULL; + return ret; +} + +static int visit_field_class_specifier(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *cls_specifier_list, + struct ctf_field_class **decl) +{ + int ret = 0; + GString *str = NULL; + + *decl = NULL; + str = g_string_new(""); + ret = get_class_specifier_list_name(ctx, cls_specifier_list, str); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + cls_specifier_list, "Cannot get field class specifier list's name: ret=%d", ret); + goto error; + } + + *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1, true); + if (!*decl) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(cls_specifier_list, + "Cannot find field class alias: name=\"%s\"", str->str); + ret = -EINVAL; + goto error; + } + + goto end; + +error: + ctf_field_class_destroy(*decl); + *decl = NULL; + +end: + if (str) { + g_string_free(str, TRUE); + } + + return ret; +} + +static int visit_integer_decl(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *expressions, + struct ctf_field_class_int **integer_decl) +{ + int set = 0; + int ret = 0; + int signedness = 0; + struct ctf_node *expression; + uint64_t alignment = 0, size = 0; + struct ctf_clock_class *mapped_clock_class = NULL; + enum ctf_encoding encoding = CTF_ENCODING_NONE; + bt_field_class_integer_preferred_display_base base = + BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL; + enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order; + + *integer_decl = NULL; + + bt_list_for_each_entry (expression, expressions, siblings) { + struct ctf_node *left, *right; + + left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings); + right = + _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings); + + if (left->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type=%d", + left->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + if (strcmp(left->u.unary_expression.u.string, "signed") == 0) { + if (_IS_SET(&set, _INTEGER_SIGNED_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "signed", "integer field class"); + ret = -EPERM; + goto error; + } + + signedness = get_boolean(ctx, right); + if (signedness < 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid boolean value for integer field class's `signed` attribute: " + "ret=%d", + ret); + ret = -EINVAL; + goto error; + } + + _SET(&set, _INTEGER_SIGNED_SET); + } else if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) { + if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order", "integer field class"); + ret = -EPERM; + goto error; + } + + byte_order = get_real_byte_order(ctx, right); + if (byte_order == CTF_BYTE_ORDER_UNKNOWN) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `byte_order` attribute in integer field class: " + "ret=%d", + ret); + ret = -EINVAL; + goto error; + } + + _SET(&set, _INTEGER_BYTE_ORDER_SET); + } else if (strcmp(left->u.unary_expression.u.string, "size") == 0) { + if (_IS_SET(&set, _INTEGER_SIZE_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "size", "integer field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, + "Invalid `size` attribute in integer field class: " + "expecting unsigned constant integer: " + "node-type=%d", + right->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + size = right->u.unary_expression.u.unsigned_constant; + if (size == 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, + "Invalid `size` attribute in integer field class: " + "expecting positive constant integer: " + "size=%" PRIu64, + size); + ret = -EINVAL; + goto error; + } else if (size > 64) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `size` attribute in integer field class: " + "integer fields over 64 bits are not supported as of this version: " + "size=%" PRIu64, + size); + ret = -EINVAL; + goto error; + } + + _SET(&set, _INTEGER_SIZE_SET); + } else if (strcmp(left->u.unary_expression.u.string, "align") == 0) { + if (_IS_SET(&set, _INTEGER_ALIGN_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "align", "integer field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, + "Invalid `align` attribute in integer field class: " + "expecting unsigned constant integer: " + "node-type=%d", + right->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + alignment = right->u.unary_expression.u.unsigned_constant; + if (!is_align_valid(alignment)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, + "Invalid `align` attribute in integer field class: " + "expecting power of two: " + "align=%" PRIu64, + alignment); + ret = -EINVAL; + goto error; + } + + _SET(&set, _INTEGER_ALIGN_SET); + } else if (strcmp(left->u.unary_expression.u.string, "base") == 0) { + if (_IS_SET(&set, _INTEGER_BASE_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "base", "integer field class"); + ret = -EPERM; + goto error; + } + + switch (right->u.unary_expression.type) { + case UNARY_UNSIGNED_CONSTANT: + { + uint64_t constant = right->u.unary_expression.u.unsigned_constant; + + switch (constant) { + case 2: + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY; + break; + case 8: + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL; + break; + case 10: + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL; + break; + case 16: + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL; + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `base` attribute in integer field class: " + "base=%" PRIu64, + right->u.unary_expression.u.unsigned_constant); + ret = -EINVAL; + goto error; + } + break; + } + case UNARY_STRING: + { + char *s_right = + ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); + if (!s_right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Unexpected unary expression for integer field class's `base` attribute."); + ret = -EINVAL; + goto error; + } + + if (strcmp(s_right, "decimal") == 0 || strcmp(s_right, "dec") == 0 || + strcmp(s_right, "d") == 0 || strcmp(s_right, "i") == 0 || + strcmp(s_right, "u") == 0) { + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL; + } else if (strcmp(s_right, "hexadecimal") == 0 || strcmp(s_right, "hex") == 0 || + strcmp(s_right, "x") == 0 || strcmp(s_right, "X") == 0 || + strcmp(s_right, "p") == 0) { + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL; + } else if (strcmp(s_right, "octal") == 0 || strcmp(s_right, "oct") == 0 || + strcmp(s_right, "o") == 0) { + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL; + } else if (strcmp(s_right, "binary") == 0 || strcmp(s_right, "b") == 0) { + base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY; + } else { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Unexpected unary expression for integer field class's `base` attribute: " + "base=\"%s\"", + s_right); + g_free(s_right); + ret = -EINVAL; + goto error; + } + + g_free(s_right); + break; + } + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, "Invalid `base` attribute in integer field class: " + "expecting unsigned constant integer or unary string."); + ret = -EINVAL; + goto error; + } + + _SET(&set, _INTEGER_BASE_SET); + } else if (strcmp(left->u.unary_expression.u.string, "encoding") == 0) { + char *s_right; + + if (_IS_SET(&set, _INTEGER_ENCODING_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "integer field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, "Invalid `encoding` attribute in integer field class: " + "expecting unary string."); + ret = -EINVAL; + goto error; + } + + s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); + if (!s_right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Unexpected unary expression for integer field class's `encoding` attribute."); + ret = -EINVAL; + goto error; + } + + if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 || + strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 || + strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) { + encoding = CTF_ENCODING_UTF8; + } else if (strcmp(s_right, "none") == 0) { + encoding = CTF_ENCODING_NONE; + } else { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `encoding` attribute in integer field class: " + "unknown encoding: encoding=\"%s\"", + s_right); + g_free(s_right); + ret = -EINVAL; + goto error; + } + + g_free(s_right); + _SET(&set, _INTEGER_ENCODING_SET); + } else if (strcmp(left->u.unary_expression.u.string, "map") == 0) { + const char *clock_name; + + if (_IS_SET(&set, _INTEGER_MAP_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "map", "integer field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(right, + "Invalid `map` attribute in integer field class: " + "expecting unary string."); + ret = -EINVAL; + goto error; + } + + clock_name = get_map_clock_name_value(&expression->u.ctf_expression.right); + if (!clock_name) { + char *s_right = + ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); + + if (!s_right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Unexpected unary expression for integer field class's `map` attribute."); + ret = -EINVAL; + goto error; + } + + _BT_COMP_LOGE_NODE(right, + "Invalid `map` attribute in integer field class: " + "cannot find clock class at this point: name=\"%s\"", + s_right); + _SET(&set, _INTEGER_MAP_SET); + g_free(s_right); + continue; + } + + mapped_clock_class = + ctf_trace_class_borrow_clock_class_by_name(ctx->ctf_tc, clock_name); + if (!mapped_clock_class) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `map` attribute in integer field class: " + "cannot find clock class at this point: name=\"%s\"", + clock_name); + ret = -EINVAL; + goto error; + } + + _SET(&set, _INTEGER_MAP_SET); + } else { + _BT_COMP_LOGW_NODE(left, + "Unknown attribute in integer field class: " + "attr-name=\"%s\"", + left->u.unary_expression.u.string); + } + } + + if (!_IS_SET(&set, _INTEGER_SIZE_SET)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Missing `size` attribute in integer field class."); + ret = -EPERM; + goto error; + } + + if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) { + if (size % CHAR_BIT) { + /* Bit-packed alignment */ + alignment = 1; + } else { + /* Byte-packed alignment */ + alignment = CHAR_BIT; + } + } + + *integer_decl = ctf_field_class_int_create(); + BT_ASSERT(*integer_decl); + (*integer_decl)->base.base.alignment = alignment; + (*integer_decl)->base.byte_order = byte_order; + (*integer_decl)->base.size = size; + (*integer_decl)->is_signed = (signedness > 0); + (*integer_decl)->disp_base = base; + (*integer_decl)->encoding = encoding; + (*integer_decl)->mapped_clock_class = mapped_clock_class; + return 0; + +error: + ctf_field_class_destroy(&(*integer_decl)->base.base); + *integer_decl = NULL; + return ret; +} + +static int visit_floating_point_number_decl(struct ctf_visitor_generate_ir *ctx, + struct bt_list_head *expressions, + struct ctf_field_class_float **float_decl) +{ + int set = 0; + int ret = 0; + struct ctf_node *expression; + uint64_t alignment = 1, exp_dig = 0, mant_dig = 0; + enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order; + + *float_decl = NULL; + + bt_list_for_each_entry (expression, expressions, siblings) { + struct ctf_node *left, *right; + + left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings); + right = + _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings); + + if (left->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type=%d", + left->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) { + if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order", + "floating point number field class"); + ret = -EPERM; + goto error; + } + + byte_order = get_real_byte_order(ctx, right); + if (byte_order == CTF_BYTE_ORDER_UNKNOWN) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `byte_order` attribute in floating point number field class: " + "ret=%d", + ret); + ret = -EINVAL; + goto error; + } + + _SET(&set, _FLOAT_BYTE_ORDER_SET); + } else if (strcmp(left->u.unary_expression.u.string, "exp_dig") == 0) { + if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "exp_dig", + "floating point number field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `exp_dig` attribute in floating point number field class: " + "expecting unsigned constant integer: " + "node-type=%d", + right->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + exp_dig = right->u.unary_expression.u.unsigned_constant; + _SET(&set, _FLOAT_EXP_DIG_SET); + } else if (strcmp(left->u.unary_expression.u.string, "mant_dig") == 0) { + if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "mant_dig", + "floating point number field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `mant_dig` attribute in floating point number field class: " + "expecting unsigned constant integer: " + "node-type=%d", + right->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + mant_dig = right->u.unary_expression.u.unsigned_constant; + _SET(&set, _FLOAT_MANT_DIG_SET); + } else if (strcmp(left->u.unary_expression.u.string, "align") == 0) { + if (_IS_SET(&set, _FLOAT_ALIGN_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "align", + "floating point number field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `align` attribute in floating point number field class: " + "expecting unsigned constant integer: " + "node-type=%d", + right->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + alignment = right->u.unary_expression.u.unsigned_constant; + + if (!is_align_valid(alignment)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `align` attribute in floating point number field class: " + "expecting power of two: " + "align=%" PRIu64, + alignment); + ret = -EINVAL; + goto error; + } + + _SET(&set, _FLOAT_ALIGN_SET); + } else { + _BT_COMP_LOGW_NODE(left, + "Unknown attribute in floating point number field class: " + "attr-name=\"%s\"", + left->u.unary_expression.u.string); + } + } + + if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Missing `mant_dig` attribute in floating point number field class."); + ret = -EPERM; + goto error; + } + + if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Missing `exp_dig` attribute in floating point number field class."); + ret = -EPERM; + goto error; + } + + if (mant_dig != 24 && mant_dig != 53) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("`mant_dig` attribute: expecting 24 or 53."); + ret = -EPERM; + goto error; + } + + if (mant_dig == 24 && exp_dig != 8) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "`exp_dig` attribute: expecting 8 because `mant_dig` is 24."); + ret = -EPERM; + goto error; + } + + if (mant_dig == 53 && exp_dig != 11) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "`exp_dig` attribute: expecting 11 because `mant_dig` is 53."); + ret = -EPERM; + goto error; + } + + if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) { + if ((mant_dig + exp_dig) % CHAR_BIT) { + /* Bit-packed alignment */ + alignment = 1; + } else { + /* Byte-packed alignment */ + alignment = CHAR_BIT; + } + } + + *float_decl = ctf_field_class_float_create(); + BT_ASSERT(*float_decl); + (*float_decl)->base.base.alignment = alignment; + (*float_decl)->base.byte_order = byte_order; + (*float_decl)->base.size = mant_dig + exp_dig; + return 0; + +error: + ctf_field_class_destroy(&(*float_decl)->base.base); + *float_decl = NULL; + return ret; +} + +static int visit_string_decl(struct ctf_visitor_generate_ir *ctx, struct bt_list_head *expressions, + struct ctf_field_class_string **string_decl) +{ + int set = 0; + int ret = 0; + struct ctf_node *expression; + enum ctf_encoding encoding = CTF_ENCODING_UTF8; + + *string_decl = NULL; + + bt_list_for_each_entry (expression, expressions, siblings) { + struct ctf_node *left, *right; + + left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left, struct ctf_node, siblings); + right = + _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.right, struct ctf_node, siblings); + + if (left->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type=%d", + left->u.unary_expression.type); + ret = -EINVAL; + goto error; + } + + if (strcmp(left->u.unary_expression.u.string, "encoding") == 0) { + char *s_right; + + if (_IS_SET(&set, _STRING_ENCODING_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "string field class"); + ret = -EPERM; + goto error; + } + + if (right->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, "Invalid `encoding` attribute in string field class: " + "expecting unary string."); + ret = -EINVAL; + goto error; + } + + s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right); + if (!s_right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Unexpected unary expression for string field class's `encoding` attribute."); + ret = -EINVAL; + goto error; + } + + if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 || + strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 || + strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) { + encoding = CTF_ENCODING_UTF8; + } else if (strcmp(s_right, "none") == 0) { + encoding = CTF_ENCODING_NONE; + } else { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + right, + "Invalid `encoding` attribute in string field class: " + "unknown encoding: encoding=\"%s\"", + s_right); + g_free(s_right); + ret = -EINVAL; + goto error; + } + + g_free(s_right); + _SET(&set, _STRING_ENCODING_SET); + } else { + _BT_COMP_LOGW_NODE(left, + "Unknown attribute in string field class: " + "attr-name=\"%s\"", + left->u.unary_expression.u.string); + } + } + + *string_decl = ctf_field_class_string_create(); + BT_ASSERT(*string_decl); + (*string_decl)->encoding = encoding; + return 0; + +error: + ctf_field_class_destroy(&(*string_decl)->base); + *string_decl = NULL; + return ret; +} + +static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *ctx, + struct ctf_node *ts_list, struct ctf_field_class **decl) +{ + int ret = 0; + struct ctf_node *first, *node; + + *decl = NULL; + + if (ts_list->type != NODE_TYPE_SPECIFIER_LIST) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(ts_list, "Unexpected node type: node-type=%d", + ts_list->type); + ret = -EINVAL; + goto error; + } + + first = _BT_LIST_FIRST_ENTRY(&ts_list->u.field_class_specifier_list.head, struct ctf_node, + siblings); + if (first->type != NODE_TYPE_SPECIFIER) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type=%d", first->type); + ret = -EINVAL; + goto error; + } + + node = first->u.field_class_specifier.node; + + switch (first->u.field_class_specifier.type) { + case TYPESPEC_INTEGER: + { + ctf_field_class_int *int_decl; + + ret = visit_integer_decl(ctx, &node->u.integer.expressions, &int_decl); + if (ret) { + BT_ASSERT(!int_decl); + goto error; + } + + *decl = &int_decl->base.base; + break; + } + case TYPESPEC_FLOATING_POINT: + { + ctf_field_class_float *float_decl; + + ret = + visit_floating_point_number_decl(ctx, &node->u.floating_point.expressions, &float_decl); + if (ret) { + BT_ASSERT(!float_decl); + goto error; + } + + *decl = &float_decl->base.base; + break; + } + case TYPESPEC_STRING: + { + ctf_field_class_string *string_decl; + + ret = visit_string_decl(ctx, &node->u.string.expressions, &string_decl); + if (ret) { + BT_ASSERT(!string_decl); + goto error; + } + + *decl = &string_decl->base; + break; + } + case TYPESPEC_STRUCT: + { + ctf_field_class_struct *struct_decl; + + ret = visit_struct_decl(ctx, node->u._struct.name, &node->u._struct.declaration_list, + node->u._struct.has_body, &node->u._struct.min_align, &struct_decl); + if (ret) { + BT_ASSERT(!struct_decl); + goto error; + } + + *decl = &struct_decl->base; + break; + } + case TYPESPEC_VARIANT: + { + ctf_field_class_variant *variant_decl; + + ret = visit_variant_decl(ctx, node->u.variant.name, node->u.variant.choice, + &node->u.variant.declaration_list, node->u.variant.has_body, + &variant_decl); + if (ret) { + BT_ASSERT(!variant_decl); + goto error; + } + + *decl = &variant_decl->base; + break; + } + case TYPESPEC_ENUM: + { + ctf_field_class_enum *enum_decl; + + ret = visit_enum_decl(ctx, node->u._enum.enum_id, node->u._enum.container_field_class, + &node->u._enum.enumerator_list, node->u._enum.has_body, &enum_decl); + if (ret) { + BT_ASSERT(!enum_decl); + goto error; + } + + *decl = &enum_decl->base.base.base; + break; + } + case TYPESPEC_VOID: + case TYPESPEC_CHAR: + case TYPESPEC_SHORT: + case TYPESPEC_INT: + case TYPESPEC_LONG: + case TYPESPEC_FLOAT: + case TYPESPEC_DOUBLE: + case TYPESPEC_SIGNED: + case TYPESPEC_UNSIGNED: + case TYPESPEC_BOOL: + case TYPESPEC_COMPLEX: + case TYPESPEC_IMAGINARY: + case TYPESPEC_CONST: + case TYPESPEC_ID_TYPE: + ret = visit_field_class_specifier(ctx, ts_list, decl); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, "Cannot visit field class specifier: ret=%d", + ret); + BT_ASSERT(!*decl); + goto error; + } + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(first, + "Unexpected field class specifier type: node-type=%d", + first->u.field_class_specifier.type); + ret = -EINVAL; + goto error; + } + + BT_ASSERT(*decl); + return 0; + +error: + ctf_field_class_destroy(*decl); + *decl = NULL; + return ret; +} + +static int visit_event_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node, + struct ctf_event_class *event_class, uint64_t *stream_id, + int *set) +{ + int ret = 0; + char *left = NULL; + + switch (node->type) { + case NODE_TYPEDEF: + ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list, + &node->u.field_class_def.field_class_declarators); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot add field class found in event class."); + goto error; + } + break; + case NODE_TYPEALIAS: + ret = visit_field_class_alias(ctx, node->u.field_class_alias.target, + node->u.field_class_alias.alias); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Cannot add field class alias found in event class."); + goto error; + } + break; + case NODE_CTF_EXPRESSION: + { + left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); + if (!left) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); + ret = -EINVAL; + goto error; + } + + if (strcmp(left, "name") == 0) { + /* This is already known at this stage */ + if (_IS_SET(set, _EVENT_NAME_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "name", "event class"); + ret = -EPERM; + goto error; + } + + _SET(set, _EVENT_NAME_SET); + } else if (strcmp(left, "id") == 0) { + int64_t id = -1; + + if (_IS_SET(set, _EVENT_ID_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "event class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id); + /* Only read "id" if get_unary_unsigned() succeeded. */ + if (ret || (!ret && id < 0)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Unexpected unary expression for event class's `id` attribute."); + ret = -EINVAL; + goto error; + } + + event_class->id = id; + _SET(set, _EVENT_ID_SET); + } else if (strcmp(left, "stream_id") == 0) { + if (_IS_SET(set, _EVENT_STREAM_ID_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "stream_id", "event class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, stream_id); + + /* + * Only read "stream_id" if get_unary_unsigned() + * succeeded. + */ + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Unexpected unary expression for event class's `stream_id` attribute."); + ret = -EINVAL; + goto error; + } + + _SET(set, _EVENT_STREAM_ID_SET); + } else if (strcmp(left, "context") == 0) { + if (_IS_SET(set, _EVENT_CONTEXT_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate `context` entry in event class."); + ret = -EPERM; + goto error; + } + + ret = visit_field_class_specifier_list( + ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), + &event_class->spec_context_fc); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Cannot create event class's context field class."); + goto error; + } + + BT_ASSERT(event_class->spec_context_fc); + _SET(set, _EVENT_CONTEXT_SET); + } else if (strcmp(left, "fields") == 0) { + if (_IS_SET(set, _EVENT_FIELDS_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate `fields` entry in event class."); + ret = -EPERM; + goto error; + } + + ret = visit_field_class_specifier_list( + ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), + &event_class->payload_fc); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Cannot create event class's payload field class."); + goto error; + } + + BT_ASSERT(event_class->payload_fc); + _SET(set, _EVENT_FIELDS_SET); + } else if (strcmp(left, "loglevel") == 0) { + uint64_t loglevel_value; + bool is_log_level_known = true; + bt_event_class_log_level log_level; + + if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "loglevel", "event class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &loglevel_value); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Unexpected unary expression for event class's `loglevel` attribute."); + ret = -EINVAL; + goto error; + } + + switch (loglevel_value) { + case 0: + log_level = BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY; + break; + case 1: + log_level = BT_EVENT_CLASS_LOG_LEVEL_ALERT; + break; + case 2: + log_level = BT_EVENT_CLASS_LOG_LEVEL_CRITICAL; + break; + case 3: + log_level = BT_EVENT_CLASS_LOG_LEVEL_ERROR; + break; + case 4: + log_level = BT_EVENT_CLASS_LOG_LEVEL_WARNING; + break; + case 5: + log_level = BT_EVENT_CLASS_LOG_LEVEL_NOTICE; + break; + case 6: + log_level = BT_EVENT_CLASS_LOG_LEVEL_INFO; + break; + case 7: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM; + break; + case 8: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM; + break; + case 9: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS; + break; + case 10: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE; + break; + case 11: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT; + break; + case 12: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION; + break; + case 13: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE; + break; + case 14: + log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG; + break; + default: + is_log_level_known = false; + _BT_COMP_LOGW_NODE( + node, + "Not setting event class's log level because its value is unknown: " + "log-level=%" PRIu64, + loglevel_value); + } + + if (is_log_level_known) { + ctf_event_class_set_log_level(event_class, log_level); + } + + _SET(set, _EVENT_LOG_LEVEL_SET); + } else if (strcmp(left, "model.emf.uri") == 0) { + char *right; + + if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "model.emf.uri", "event class"); + ret = -EPERM; + goto error; + } + + right = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.right); + if (!right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, + "Unexpected unary expression for event class's `model.emf.uri` attribute."); + ret = -EINVAL; + goto error; + } + + if (strlen(right) == 0) { + _BT_COMP_LOGW_NODE(node, "Not setting event class's EMF URI because it's empty."); + } else { + g_string_assign(event_class->emf_uri, right); + } + + g_free(right); + _SET(set, _EVENT_MODEL_EMF_URI_SET); + } else { + _BT_COMP_LOGW_NODE(node, + "Unknown attribute in event class: " + "attr-name=\"%s\"", + left); + } + + g_free(left); + left = NULL; + break; + } + default: + ret = -EPERM; + goto error; + } + + goto end; + +error: + g_free(left); + +end: + return ret; +} + +static char *get_event_decl_name(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) +{ + char *left = NULL; + char *name = NULL; + struct ctf_node *iter; + struct bt_list_head *decl_list = &node->u.event.declaration_list; + + bt_list_for_each_entry (iter, decl_list, siblings) { + if (iter->type != NODE_CTF_EXPRESSION) { + continue; + } + + left = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.left); + if (!left) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot concatenate unary strings."); + goto error; + } + + if (strcmp(left, "name") == 0) { + name = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.right); + if (!name) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + iter, "Unexpected unary expression for event class's `name` attribute."); + goto error; + } + } + + g_free(left); + left = NULL; + + if (name) { + break; + } + } + + return name; + +error: + g_free(left); + return NULL; +} + +static int visit_event_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) +{ + int ret = 0; + int set = 0; + struct ctf_node *iter; + uint64_t stream_id = 0; + char *event_name = NULL; + struct ctf_event_class *event_class = NULL; + struct 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; + } + + node->visited = TRUE; + event_name = get_event_decl_name(ctx, node); + if (!event_name) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Missing `name` attribute in event class."); + ret = -EPERM; + goto error; + } + + event_class = ctf_event_class_create(); + BT_ASSERT(event_class); + g_string_assign(event_class->name, event_name); + _TRY_PUSH_SCOPE_OR_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 (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, + "Cannot visit event class's entry: " + "ret=%d", + ret); + goto error; + } + } + + if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) { + /* + * Allow missing stream_id if there is only a single + * stream class. + */ + switch (ctx->ctf_tc->stream_classes->len) { + case 0: + /* Create implicit stream class if there's none */ + stream_id = 0; + stream_class = ctf_stream_class_create(); + BT_ASSERT(stream_class); + stream_class->id = stream_id; + g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class); + break; + case 1: + /* Single stream class: get its ID */ + stream_class = (ctf_stream_class *) ctx->ctf_tc->stream_classes->pdata[0]; + stream_id = stream_class->id; + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Missing `stream_id` attribute in event class."); + ret = -EPERM; + goto error; + } + } + + /* We have the stream ID now; get the stream class if found */ + if (!stream_class) { + stream_class = ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, stream_id); + if (!stream_class) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Cannot find stream class at this point: " + "id=%" PRId64, + stream_id); + ret = -EINVAL; + goto error; + } + } + + BT_ASSERT(stream_class); + + if (!_IS_SET(&set, _EVENT_ID_SET)) { + /* Allow only one event without ID per stream */ + if (stream_class->event_classes->len != 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Missing `id` attribute in event class."); + ret = -EPERM; + goto error; + } + + /* Automatic ID */ + event_class->id = 0; + } + + if (ctf_stream_class_borrow_event_class_by_id(stream_class, event_class->id)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Duplicate event class (same ID) in the same stream class: " + "id=%" PRId64, + event_class->id); + ret = -EEXIST; + goto error; + } + + ctf_stream_class_append_event_class(stream_class, event_class); + event_class = NULL; + goto end; + +error: + ctf_event_class_destroy(event_class); + event_class = NULL; + + if (ret >= 0) { + ret = -1; + } + +end: + if (pop_scope) { + ctx_pop_scope(ctx); + } + + g_free(event_name); + + return ret; +} + +static int auto_map_field_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx, + struct ctf_field_class *fc) +{ + struct ctf_clock_class *clock_class_to_map_to = NULL; + uint64_t clock_class_count; + + if (!fc) { + return 0; + } + + if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + return 0; + } + + ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + + if (int_fc->mapped_clock_class) { + /* Already mapped */ + return 0; + } + + clock_class_count = ctx->ctf_tc->clock_classes->len; + + switch (clock_class_count) { + case 0: + /* + * No clock class exists in the trace at this point. Create an + * implicit one at 1 GHz, named `default`, and use this clock + * class. + */ + clock_class_to_map_to = ctf_clock_class_create(); + BT_ASSERT(clock_class_to_map_to); + clock_class_to_map_to->frequency = UINT64_C(1000000000); + g_string_assign(clock_class_to_map_to->name, "default"); + g_ptr_array_add(ctx->ctf_tc->clock_classes, clock_class_to_map_to); + break; + case 1: + /* + * Only one clock class exists in the trace at this point: use + * this one. + */ + clock_class_to_map_to = (ctf_clock_class *) ctx->ctf_tc->clock_classes->pdata[0]; + break; + default: + /* + * Timestamp field not mapped to a clock class and there's more + * than one clock class in the trace: this is an error. + */ + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Timestamp field found with no mapped clock class, " + "but there's more than one clock class in the trace at this point."); + return -1; + } + + BT_ASSERT(clock_class_to_map_to); + int_fc->mapped_clock_class = clock_class_to_map_to; + + return 0; +} + +static int auto_map_fields_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx, + struct ctf_field_class *root_fc, + const char *field_name) +{ + int ret = 0; + uint64_t i, count; + struct ctf_field_class_struct *struct_fc = (ctf_field_class_struct *) root_fc; + struct ctf_field_class_variant *var_fc = (ctf_field_class_variant *) root_fc; + + if (!root_fc) { + goto end; + } + + if (root_fc->type != CTF_FIELD_CLASS_TYPE_STRUCT && + root_fc->type != CTF_FIELD_CLASS_TYPE_VARIANT) { + goto end; + } + + if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) { + count = struct_fc->members->len; + } else { + count = var_fc->options->len; + } + + for (i = 0; i < count; i++) { + struct ctf_named_field_class *named_fc = NULL; + + if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) { + named_fc = ctf_field_class_struct_borrow_member_by_index(struct_fc, i); + } else if (root_fc->type == CTF_FIELD_CLASS_TYPE_VARIANT) { + named_fc = ctf_field_class_variant_borrow_option_by_index(var_fc, i); + } else { + bt_common_abort(); + } + + if (strcmp(named_fc->name->str, field_name) == 0) { + ret = auto_map_field_to_trace_clock_class(ctx, named_fc->fc); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot automatically map field to trace's clock class: " + "field-name=\"%s\"", + field_name); + goto end; + } + } + + ret = auto_map_fields_to_trace_clock_class(ctx, named_fc->fc, field_name); + if (ret) { + _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE( + "Cannot automatically map structure or variant field class's fields to trace's clock class: " + "field-name=\"%s\", root-field-name=\"%s\"", + field_name, named_fc->name->str); + goto end; + } + } + +end: + return ret; +} + +static int visit_stream_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node, + struct ctf_stream_class *stream_class, int *set) +{ + int ret = 0; + char *left = NULL; + + switch (node->type) { + case NODE_TYPEDEF: + ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list, + &node->u.field_class_def.field_class_declarators); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot add field class found in stream class."); + goto error; + } + break; + case NODE_TYPEALIAS: + ret = visit_field_class_alias(ctx, node->u.field_class_alias.target, + node->u.field_class_alias.alias); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Cannot add field class alias found in stream class."); + goto error; + } + break; + case NODE_CTF_EXPRESSION: + { + left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); + if (!left) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); + ret = -EINVAL; + goto error; + } + + if (strcmp(left, "id") == 0) { + int64_t id; + + if (_IS_SET(set, _STREAM_ID_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "stream declaration"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id); + + /* Only read "id" if get_unary_unsigned() succeeded. */ + if (ret || (!ret && id < 0)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Unexpected unary expression for stream class's `id` attribute."); + ret = -EINVAL; + goto error; + } + + if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, id)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Duplicate stream class (same ID): id=%" PRId64, id); + ret = -EEXIST; + goto error; + } + + stream_class->id = id; + _SET(set, _STREAM_ID_SET); + } else if (strcmp(left, "event.header") == 0) { + if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Duplicate `event.header` entry in stream class."); + ret = -EPERM; + goto error; + } + + ret = visit_field_class_specifier_list( + ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), + &stream_class->event_header_fc); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Cannot create stream class's event header field class."); + goto error; + } + + BT_ASSERT(stream_class->event_header_fc); + ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->event_header_fc, + "timestamp"); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, + "Cannot automatically map specific event header field class fields named `timestamp` to trace's clock class."); + goto error; + } + + _SET(set, _STREAM_EVENT_HEADER_SET); + } else if (strcmp(left, "event.context") == 0) { + if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Duplicate `event.context` entry in stream class."); + ret = -EPERM; + goto error; + } + + ret = visit_field_class_specifier_list( + ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), + &stream_class->event_common_context_fc); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Cannot create stream class's event context field class."); + goto error; + } + + BT_ASSERT(stream_class->event_common_context_fc); + _SET(set, _STREAM_EVENT_CONTEXT_SET); + } else if (strcmp(left, "packet.context") == 0) { + if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Duplicate `packet.context` entry in stream class."); + ret = -EPERM; + goto error; + } + + ret = visit_field_class_specifier_list( + ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), + &stream_class->packet_context_fc); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Cannot create stream class's packet context field class."); + goto error; + } + + BT_ASSERT(stream_class->packet_context_fc); + ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->packet_context_fc, + "timestamp_begin"); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, + "Cannot automatically map specific packet context field class fields named `timestamp_begin` to trace's clock class."); + goto error; + } + + ret = auto_map_fields_to_trace_clock_class(ctx, stream_class->packet_context_fc, + "timestamp_end"); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, + "Cannot automatically map specific packet context field class fields named `timestamp_end` to trace's clock class."); + goto error; + } + + _SET(set, _STREAM_PACKET_CONTEXT_SET); + } else { + _BT_COMP_LOGW_NODE(node, + "Unknown attribute in stream class: " + "attr-name=\"%s\"", + left); + } + + g_free(left); + left = NULL; + break; + } + + default: + ret = -EPERM; + goto error; + } + + return 0; + +error: + g_free(left); + return ret; +} + +static int visit_stream_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) +{ + int set = 0; + int ret = 0; + struct ctf_node *iter; + struct ctf_stream_class *stream_class = NULL; + struct bt_list_head *decl_list = &node->u.stream.declaration_list; + + if (node->visited) { + goto end; + } + + node->visited = TRUE; + stream_class = ctf_stream_class_create(); + BT_ASSERT(stream_class); + _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); + + bt_list_for_each_entry (iter, decl_list, siblings) { + ret = visit_stream_decl_entry(ctx, iter, stream_class, &set); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, + "Cannot visit stream class's entry: " + "ret=%d", + ret); + ctx_pop_scope(ctx); + goto error; + } + } + + ctx_pop_scope(ctx); + + if (_IS_SET(&set, _STREAM_ID_SET)) { + /* Check that packet header has `stream_id` field */ + struct ctf_named_field_class *named_fc = NULL; + + if (!ctx->ctf_tc->packet_header_fc) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Stream class has a `id` attribute, " + "but trace has no packet header field class."); + ret = -EINVAL; + goto error; + } + + named_fc = ctf_field_class_struct_borrow_member_by_name( + ctf_field_class_as_struct(ctx->ctf_tc->packet_header_fc), "stream_id"); + if (!named_fc) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Stream class has a `id` attribute, " + "but trace's packet header field class has no `stream_id` field."); + ret = -EINVAL; + goto error; + } + + if (named_fc->fc->type != CTF_FIELD_CLASS_TYPE_INT && + named_fc->fc->type != CTF_FIELD_CLASS_TYPE_ENUM) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, + "Stream class has a `id` attribute, " + "but trace's packet header field class's `stream_id` field is not an integer field class."); + ret = -EINVAL; + goto error; + } + } else { + /* Allow only _one_ ID-less stream */ + if (ctx->ctf_tc->stream_classes->len != 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, + "Missing `id` attribute in stream class as there's more than one stream class in the trace."); + ret = -EPERM; + goto error; + } + + /* Automatic ID: 0 */ + stream_class->id = 0; + } + + /* + * Make sure that this stream class's ID is currently unique in + * the trace. + */ + if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc, stream_class->id)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate stream class (same ID): id=%" PRId64, + stream_class->id); + ret = -EINVAL; + goto error; + } + + g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class); + stream_class = NULL; + goto end; + +error: + ctf_stream_class_destroy(stream_class); + stream_class = NULL; + +end: + return ret; +} + +static int visit_trace_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node, + int *set) +{ + int ret = 0; + char *left = NULL; + uint64_t val; + + switch (node->type) { + case NODE_TYPEDEF: + ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list, + &node->u.field_class_def.field_class_declarators); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Cannot add field class found in trace (`trace` block)."); + goto error; + } + break; + case NODE_TYPEALIAS: + ret = visit_field_class_alias(ctx, node->u.field_class_alias.target, + node->u.field_class_alias.alias); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Cannot add field class alias found in trace (`trace` block)."); + goto error; + } + break; + case NODE_CTF_EXPRESSION: + { + left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); + if (!left) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); + ret = -EINVAL; + goto error; + } + + if (strcmp(left, "major") == 0) { + if (_IS_SET(set, _TRACE_MAJOR_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "major", "trace"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Unexpected unary expression for trace's `major` attribute."); + ret = -EINVAL; + goto error; + } + + if (val != 1) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Invalid trace's `minor` attribute: expecting 1."); + ret = -EINVAL; + goto error; + } + + ctx->ctf_tc->major = val; + _SET(set, _TRACE_MAJOR_SET); + } else if (strcmp(left, "minor") == 0) { + if (_IS_SET(set, _TRACE_MINOR_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "minor", "trace"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Unexpected unary expression for trace's `minor` attribute."); + ret = -EINVAL; + goto error; + } + + if (val != 8) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Invalid trace's `minor` attribute: expecting 8."); + ret = -EINVAL; + goto error; + } + + ctx->ctf_tc->minor = val; + _SET(set, _TRACE_MINOR_SET); + } else if (strcmp(left, "uuid") == 0) { + if (_IS_SET(set, _TRACE_UUID_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "uuid", "trace"); + ret = -EPERM; + goto error; + } + + ret = get_unary_uuid(ctx, &node->u.ctf_expression.right, ctx->ctf_tc->uuid); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Invalid trace's `uuid` attribute."); + goto error; + } + + ctx->ctf_tc->is_uuid_set = true; + _SET(set, _TRACE_UUID_SET); + } else if (strcmp(left, "byte_order") == 0) { + /* Default byte order is already known at this stage */ + if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace"); + ret = -EPERM; + goto error; + } + + BT_ASSERT(ctx->ctf_tc->default_byte_order != CTF_BYTE_ORDER_UNKNOWN); + _SET(set, _TRACE_BYTE_ORDER_SET); + } else if (strcmp(left, "packet.header") == 0) { + if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate `packet.header` entry in trace."); + ret = -EPERM; + goto error; + } + + ret = visit_field_class_specifier_list( + ctx, _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings), + &ctx->ctf_tc->packet_header_fc); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Cannot create trace's packet header field class."); + goto error; + } + + BT_ASSERT(ctx->ctf_tc->packet_header_fc); + _SET(set, _TRACE_PACKET_HEADER_SET); + } else { + _BT_COMP_LOGW_NODE(node, + "Unknown attribute in stream class: " + "attr-name=\"%s\"", + left); + } + + g_free(left); + left = NULL; + break; + } + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unknown expression in trace."); + ret = -EINVAL; + goto error; + } + + return 0; + +error: + g_free(left); + return ret; +} + +static int visit_trace_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) +{ + int ret = 0; + int set = 0; + struct ctf_node *iter; + struct bt_list_head *decl_list = &node->u.trace.declaration_list; + + if (node->visited) { + goto end; + } + + node->visited = TRUE; + + if (ctx->is_trace_visited) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block)."); + ret = -EEXIST; + goto error; + } + + _TRY_PUSH_SCOPE_OR_GOTO_ERROR(); + + bt_list_for_each_entry (iter, decl_list, siblings) { + ret = visit_trace_decl_entry(ctx, iter, &set); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, + "Cannot visit trace's entry (`trace` block): " + "ret=%d", + ret); + ctx_pop_scope(ctx); + goto error; + } + } + + ctx_pop_scope(ctx); + + if (!_IS_SET(&set, _TRACE_MAJOR_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Missing `major` attribute in trace (`trace` block)."); + ret = -EPERM; + goto error; + } + + if (!_IS_SET(&set, _TRACE_MINOR_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Missing `minor` attribute in trace (`trace` block)."); + ret = -EPERM; + goto error; + } + + if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Missing `byte_order` attribute in trace (`trace` block)."); + ret = -EPERM; + goto error; + } + + ctx->is_trace_visited = true; + +end: + return 0; + +error: + return ret; +} + +static int visit_env(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) +{ + int ret = 0; + char *left = NULL; + struct ctf_node *entry_node; + struct bt_list_head *decl_list = &node->u.env.declaration_list; + + if (node->visited) { + goto end; + } + + node->visited = TRUE; + + bt_list_for_each_entry (entry_node, decl_list, siblings) { + struct bt_list_head *right_head = &entry_node->u.ctf_expression.right; + + if (entry_node->type != NODE_CTF_EXPRESSION) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, + "Wrong expression in environment entry: " + "node-type=%d", + entry_node->type); + ret = -EPERM; + goto error; + } + + left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left); + if (!left) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot get environment entry's name."); + ret = -EINVAL; + goto error; + } + + if (is_unary_string(right_head)) { + char *right = ctf_ast_concatenate_unary_strings(right_head); + + if (!right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, + "Unexpected unary expression for environment entry's value: " + "name=\"%s\"", + left); + ret = -EINVAL; + goto error; + } + + if (strcmp(left, "tracer_name") == 0) { + if (strncmp(right, "lttng", 5) == 0) { + BT_COMP_LOGI("Detected LTTng trace from `%s` environment value: " + "tracer-name=\"%s\"", + left, right); + ctx->is_lttng = true; + } + } + + ctf_trace_class_append_env_entry(ctx->ctf_tc, left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR, + right, 0); + g_free(right); + } else if (is_unary_unsigned(right_head) || is_unary_signed(right_head)) { + int64_t v; + + if (is_unary_unsigned(right_head)) { + ret = get_unary_unsigned(ctx, right_head, (uint64_t *) &v); + } else { + ret = get_unary_signed(right_head, &v); + } + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, + "Unexpected unary expression for environment entry's value: " + "name=\"%s\"", + left); + ret = -EINVAL; + goto error; + } + + ctf_trace_class_append_env_entry(ctx->ctf_tc, left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT, + NULL, v); + } else { + _BT_COMP_LOGW_NODE(entry_node, + "Environment entry has unknown type: " + "name=\"%s\"", + left); + } + + g_free(left); + left = NULL; + } + +end: + return 0; + +error: + g_free(left); + return ret; +} + +static int set_trace_byte_order(struct ctf_visitor_generate_ir *ctx, struct ctf_node *trace_node) +{ + int ret = 0; + int set = 0; + char *left = NULL; + struct ctf_node *node; + struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list; + + bt_list_for_each_entry (node, decl_list, siblings) { + if (node->type == NODE_CTF_EXPRESSION) { + struct ctf_node *right_node; + + left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left); + if (!left) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings."); + ret = -EINVAL; + goto error; + } + + if (strcmp(left, "byte_order") == 0) { + enum ctf_byte_order bo; + + if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace"); + ret = -EPERM; + goto error; + } + + _SET(&set, _TRACE_BYTE_ORDER_SET); + right_node = + _BT_LIST_FIRST_ENTRY(&node->u.ctf_expression.right, struct ctf_node, siblings); + bo = byte_order_from_unary_expr(ctx, right_node); + if (bo == CTF_BYTE_ORDER_UNKNOWN) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Invalid `byte_order` attribute in trace (`trace` block): " + "expecting `le`, `be`, or `network`."); + ret = -EINVAL; + goto error; + } else if (bo == CTF_BYTE_ORDER_DEFAULT) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + node, "Invalid `byte_order` attribute in trace (`trace` block): " + "cannot be set to `native` here."); + ret = -EPERM; + goto error; + } + + ctx->ctf_tc->default_byte_order = bo; + } + + g_free(left); + left = NULL; + } + } + + if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(trace_node, + "Missing `byte_order` attribute in trace (`trace` block)."); + ret = -EINVAL; + goto error; + } + + return 0; + +error: + g_free(left); + return ret; +} + +static int visit_clock_decl_entry(struct ctf_visitor_generate_ir *ctx, struct ctf_node *entry_node, + struct ctf_clock_class *clock, int *set, int64_t *offset_seconds, + uint64_t *offset_cycles) +{ + int ret = 0; + char *left = NULL; + + if (entry_node->type != NODE_CTF_EXPRESSION) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type=%d", + entry_node->type); + ret = -EPERM; + goto error; + } + + left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left); + if (!left) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot concatenate unary strings."); + ret = -EINVAL; + goto error; + } + + if (strcmp(left, "name") == 0) { + char *right; + + if (_IS_SET(set, _CLOCK_NAME_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "name", "clock class"); + ret = -EPERM; + goto error; + } + + right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right); + if (!right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Unexpected unary expression for clock class's `name` attribute."); + ret = -EINVAL; + goto error; + } + + g_string_assign(clock->name, right); + g_free(right); + _SET(set, _CLOCK_NAME_SET); + } else if (strcmp(left, "uuid") == 0) { + bt_uuid_t uuid; + + if (_IS_SET(set, _CLOCK_UUID_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "uuid", "clock class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_uuid(ctx, &entry_node->u.ctf_expression.right, uuid); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Invalid clock class's `uuid` attribute."); + goto error; + } + + clock->has_uuid = true; + bt_uuid_copy(clock->uuid, uuid); + _SET(set, _CLOCK_UUID_SET); + } else if (strcmp(left, "description") == 0) { + char *right; + + if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "description", "clock class"); + ret = -EPERM; + goto error; + } + + right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right); + if (!right) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, + "Unexpected unary expression for clock class's `description` attribute."); + ret = -EINVAL; + goto error; + } + + g_string_assign(clock->description, right); + g_free(right); + _SET(set, _CLOCK_DESCRIPTION_SET); + } else if (strcmp(left, "freq") == 0) { + uint64_t freq = UINT64_C(-1); + + if (_IS_SET(set, _CLOCK_FREQ_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "freq", "clock class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &freq); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Unexpected unary expression for clock class's `freq` attribute."); + ret = -EINVAL; + goto error; + } + + if (freq == UINT64_C(-1) || freq == 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, + "Invalid clock class frequency: freq=%" PRIu64, freq); + ret = -EINVAL; + goto error; + } + + clock->frequency = freq; + _SET(set, _CLOCK_FREQ_SET); + } else if (strcmp(left, "precision") == 0) { + uint64_t precision; + + if (_IS_SET(set, _CLOCK_PRECISION_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "precision", "clock class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &precision); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Unexpected unary expression for clock class's `precision` attribute."); + ret = -EINVAL; + goto error; + } + + clock->precision = precision; + _SET(set, _CLOCK_PRECISION_SET); + } else if (strcmp(left, "offset_s") == 0) { + if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset_s", "clock class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_signed(&entry_node->u.ctf_expression.right, offset_seconds); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Unexpected unary expression for clock class's `offset_s` attribute."); + ret = -EINVAL; + goto error; + } + + _SET(set, _CLOCK_OFFSET_S_SET); + } else if (strcmp(left, "offset") == 0) { + if (_IS_SET(set, _CLOCK_OFFSET_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset", "clock class"); + ret = -EPERM; + goto error; + } + + ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, offset_cycles); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Unexpected unary expression for clock class's `offset` attribute."); + ret = -EINVAL; + goto error; + } + + _SET(set, _CLOCK_OFFSET_SET); + } else if (strcmp(left, "absolute") == 0) { + struct ctf_node *right; + + if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "absolute", "clock class"); + ret = -EPERM; + goto error; + } + + right = + _BT_LIST_FIRST_ENTRY(&entry_node->u.ctf_expression.right, struct ctf_node, siblings); + ret = get_boolean(ctx, right); + if (ret < 0) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + entry_node, "Unexpected unary expression for clock class's `absolute` attribute."); + ret = -EINVAL; + goto error; + } + + clock->is_absolute = ret; + _SET(set, _CLOCK_ABSOLUTE_SET); + } else { + _BT_COMP_LOGW_NODE(entry_node, "Unknown attribute in clock class: attr-name=\"%s\"", left); + } + + g_free(left); + left = NULL; + return 0; + +error: + g_free(left); + return ret; +} + +static inline uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns) +{ + uint64_t cycles; + + /* 1GHz */ + if (frequency == UINT64_C(1000000000)) { + cycles = ns; + } else { + cycles = (uint64_t) (((double) ns * (double) frequency) / 1e9); + } + + return cycles; +} + +static void calibrate_clock_class_offsets(int64_t *offset_seconds, uint64_t *offset_cycles, + uint64_t freq) +{ + if (*offset_cycles >= freq) { + const uint64_t s_in_offset_cycles = *offset_cycles / freq; + + *offset_seconds += (int64_t) s_in_offset_cycles; + *offset_cycles -= (s_in_offset_cycles * freq); + } +} + +static void apply_clock_class_is_absolute(struct ctf_visitor_generate_ir *ctx, + struct ctf_clock_class *clock) +{ + if (ctx->decoder_config.force_clock_class_origin_unix_epoch) { + clock->is_absolute = true; + } + + return; +} + +static void apply_clock_class_offset(struct ctf_visitor_generate_ir *ctx, + struct ctf_clock_class *clock) +{ + uint64_t freq; + int64_t offset_s_to_apply = ctx->decoder_config.clock_class_offset_s; + uint64_t offset_ns_to_apply; + int64_t cur_offset_s; + uint64_t cur_offset_cycles; + + if (ctx->decoder_config.clock_class_offset_s == 0 && + ctx->decoder_config.clock_class_offset_ns == 0) { + goto end; + } + + /* Transfer nanoseconds to seconds as much as possible */ + if (ctx->decoder_config.clock_class_offset_ns < 0) { + const int64_t abs_ns = -ctx->decoder_config.clock_class_offset_ns; + const int64_t abs_extra_s = abs_ns / INT64_C(1000000000) + 1; + const int64_t extra_s = -abs_extra_s; + const int64_t offset_ns = + ctx->decoder_config.clock_class_offset_ns - (extra_s * INT64_C(1000000000)); + + BT_ASSERT(offset_ns > 0); + offset_ns_to_apply = (uint64_t) offset_ns; + offset_s_to_apply += extra_s; + } else { + const int64_t extra_s = ctx->decoder_config.clock_class_offset_ns / INT64_C(1000000000); + const int64_t offset_ns = + ctx->decoder_config.clock_class_offset_ns - (extra_s * INT64_C(1000000000)); + + BT_ASSERT(offset_ns >= 0); + offset_ns_to_apply = (uint64_t) offset_ns; + offset_s_to_apply += extra_s; + } + + freq = clock->frequency; + cur_offset_s = clock->offset_seconds; + cur_offset_cycles = clock->offset_cycles; + + /* Apply offsets */ + cur_offset_s += offset_s_to_apply; + cur_offset_cycles += cycles_from_ns(freq, offset_ns_to_apply); + + /* + * Recalibrate offsets because the part in cycles can be greater + * than the frequency at this point. + */ + calibrate_clock_class_offsets(&cur_offset_s, &cur_offset_cycles, freq); + + /* Set final offsets */ + clock->offset_seconds = cur_offset_s; + clock->offset_cycles = cur_offset_cycles; + +end: + return; +} + +static int visit_clock_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *clock_node) +{ + int ret = 0; + int set = 0; + struct ctf_clock_class *clock; + struct ctf_node *entry_node; + struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list; + const char *clock_class_name; + int64_t offset_seconds = 0; + uint64_t offset_cycles = 0; + uint64_t freq; + + if (clock_node->visited) { + return 0; + } + + clock_node->visited = TRUE; + + /* CTF 1.8's default frequency for a clock class is 1 GHz */ + clock = ctf_clock_class_create(); + if (!clock) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(clock_node, "Cannot create default clock class."); + ret = -ENOMEM; + goto end; + } + + bt_list_for_each_entry (entry_node, decl_list, siblings) { + ret = visit_clock_decl_entry(ctx, entry_node, clock, &set, &offset_seconds, &offset_cycles); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot visit clock class's entry: ret=%d", + ret); + goto end; + } + } + + if (!_IS_SET(&set, _CLOCK_NAME_SET)) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(clock_node, "Missing `name` attribute in clock class."); + ret = -EPERM; + goto end; + } + + clock_class_name = clock->name->str; + BT_ASSERT(clock_class_name); + if (ctx->is_lttng && strcmp(clock_class_name, "monotonic") == 0) { + /* + * Old versions of LTTng forgot to set its clock class + * as absolute, even if it is. This is important because + * it's a condition to be able to sort messages + * from different sources. + */ + clock->is_absolute = true; + } + + /* + * Adjust offsets so that the part in cycles is less than the + * frequency (move to the part in seconds). + */ + freq = clock->frequency; + calibrate_clock_class_offsets(&offset_seconds, &offset_cycles, freq); + BT_ASSERT(offset_cycles < clock->frequency); + clock->offset_seconds = offset_seconds; + clock->offset_cycles = offset_cycles; + apply_clock_class_offset(ctx, clock); + apply_clock_class_is_absolute(ctx, clock); + g_ptr_array_add(ctx->ctf_tc->clock_classes, clock); + clock = NULL; + +end: + if (clock) { + ctf_clock_class_destroy(clock); + } + + return ret; +} + +static int visit_root_decl(struct ctf_visitor_generate_ir *ctx, struct ctf_node *root_decl_node) +{ + int ret = 0; + + if (root_decl_node->visited) { + goto end; + } + + root_decl_node->visited = TRUE; + + switch (root_decl_node->type) { + case NODE_TYPEDEF: + ret = + visit_field_class_def(ctx, root_decl_node->u.field_class_def.field_class_specifier_list, + &root_decl_node->u.field_class_def.field_class_declarators); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, + "Cannot add field class found in root scope."); + goto end; + } + break; + case NODE_TYPEALIAS: + ret = visit_field_class_alias(ctx, root_decl_node->u.field_class_alias.target, + root_decl_node->u.field_class_alias.alias); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, + "Cannot add field class alias found in root scope."); + goto end; + } + break; + case NODE_TYPE_SPECIFIER_LIST: + { + struct ctf_field_class *decl = NULL; + + /* + * Just add the field class specifier to the root + * declaration scope. Put local reference. + */ + ret = visit_field_class_specifier_list(ctx, root_decl_node, &decl); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, + "Cannot visit root scope's field class: " + "ret=%d", + ret); + BT_ASSERT(!decl); + goto end; + } + + ctf_field_class_destroy(decl); + decl = NULL; + break; + } + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, "Unexpected node type: node-type=%d", + root_decl_node->type); + ret = -EPERM; + goto end; + } + +end: + return ret; +} + +struct ctf_visitor_generate_ir * +ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *decoder_config) +{ + struct ctf_visitor_generate_ir *ctx = NULL; + + /* Create visitor's context */ + ctx = ctx_create(decoder_config); + if (!ctx) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, decoder_config->log_level, decoder_config->self_comp, + "Cannot create visitor's context."); + goto error; + } + + goto end; + +error: + ctx_destroy(ctx); + ctx = NULL; + +end: + return ctx; +} + +void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor) +{ + ctx_destroy(visitor); +} + +bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *ctx) +{ + BT_ASSERT_DBG(ctx); + + if (ctx->trace_class) { + bt_trace_class_get_ref(ctx->trace_class); + } + + return ctx->trace_class; +} + +struct ctf_trace_class * +ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *ctx) +{ + BT_ASSERT_DBG(ctx); + BT_ASSERT_DBG(ctx->ctf_tc); + return ctx->ctf_tc; +} + +int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node) +{ + int ret = 0; + + BT_COMP_LOGI_STR("Visiting metadata's AST to generate CTF IR objects."); + + switch (node->type) { + case NODE_ROOT: + { + struct ctf_node *iter; + bool got_trace_decl = false; + + /* + * The first thing we need is the native byte order of + * the trace block, because early class 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. + */ + if (ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_UNKNOWN) { + bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { + if (got_trace_decl) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block)."); + ret = -1; + goto end; + } + + ret = set_trace_byte_order(ctx, iter); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, + "Cannot set trace's native byte order: " + "ret=%d", + ret); + goto end; + } + + got_trace_decl = true; + } + + if (!got_trace_decl) { + BT_COMP_LOGD_STR("Incomplete AST: need trace (`trace` block)."); + ret = -EINCOMPLETE; + goto end; + } + } + + BT_ASSERT(ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_LITTLE || + ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_BIG); + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + + /* Environment */ + bt_list_for_each_entry (iter, &node->u.root.env, siblings) { + ret = visit_env(ctx, iter); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE( + iter, + "Cannot visit trace's environment (`env` block) entry: " + "ret=%d", + ret); + goto end; + } + } + + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + + /* + * Visit clock blocks. + */ + bt_list_for_each_entry (iter, &node->u.root.clock, siblings) { + ret = visit_clock_decl(ctx, iter); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit clock class: ret=%d", ret); + goto end; + } + } + + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + + /* + * Visit root declarations next, as they can be used by any + * following entity. + */ + bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) { + ret = visit_root_decl(ctx, iter); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit root entry: ret=%d", ret); + goto end; + } + } + + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + + /* Callsite blocks are not supported */ + bt_list_for_each_entry (iter, &node->u.root.callsite, siblings) { + _BT_COMP_LOGW_NODE(iter, "\"callsite\" blocks are not supported as of this version."); + } + + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + + /* Trace */ + bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { + ret = visit_trace_decl(ctx, iter); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, + "Cannot visit trace (`trace` block): " + "ret=%d", + ret); + goto end; + } + } + + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + + /* Streams */ + bt_list_for_each_entry (iter, &node->u.root.stream, siblings) { + ret = visit_stream_decl(ctx, iter); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit stream class: ret=%d", ret); + goto end; + } + } + + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + + /* Events */ + bt_list_for_each_entry (iter, &node->u.root.event, siblings) { + ret = visit_event_decl(ctx, iter); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit event class: ret=%d", ret); + goto end; + } + } + + BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope); + break; + } + default: + _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unexpected node type: node-type=%d", node->type); + ret = -EINVAL; + goto end; + } + + /* Update default clock classes */ + ret = ctf_trace_class_update_default_clock_classes(ctx->ctf_tc, &ctx->log_cfg); + if (ret) { + ret = -EINVAL; + goto end; + } + + /* Update trace class meanings */ + ret = ctf_trace_class_update_meanings(ctx->ctf_tc); + if (ret) { + ret = -EINVAL; + goto end; + } + + /* Update stream class configuration */ + ret = ctf_trace_class_update_stream_class_config(ctx->ctf_tc); + if (ret) { + ret = -EINVAL; + goto end; + } + + /* Update text arrays and sequences */ + ret = ctf_trace_class_update_text_array_sequence(ctx->ctf_tc); + if (ret) { + ret = -EINVAL; + goto end; + } + + /* Update structure/array/sequence alignments */ + ret = ctf_trace_class_update_alignments(ctx->ctf_tc); + if (ret) { + ret = -EINVAL; + goto end; + } + + /* Resolve sequence lengths and variant tags */ + ret = ctf_trace_class_resolve_field_classes(ctx->ctf_tc, &ctx->log_cfg); + if (ret) { + ret = -EINVAL; + goto end; + } + + if (ctx->trace_class) { + /* + * Update "in IR" for field classes. + * + * If we have no IR trace class, then we'll have no way + * to create IR fields anyway, so we leave all the + * `in_ir` members false. + */ + ret = ctf_trace_class_update_in_ir(ctx->ctf_tc); + if (ret) { + ret = -EINVAL; + goto end; + } + } + + /* Update saved value indexes */ + ret = ctf_trace_class_update_value_storing_indexes(ctx->ctf_tc); + if (ret) { + ret = -EINVAL; + goto end; + } + + /* Validate what we have so far */ + ret = ctf_trace_class_validate(ctx->ctf_tc, &ctx->log_cfg); + if (ret) { + ret = -EINVAL; + goto end; + } + + /* + * If there are fields which are not related to the CTF format + * itself in the packet header and in event header field + * classes, warn about it because they are never translated. + */ + ctf_trace_class_warn_meaningless_header_fields(ctx->ctf_tc, &ctx->log_cfg); + + if (ctx->trace_class) { + /* Copy new CTF metadata -> new IR metadata */ + ret = ctf_trace_class_translate(ctx->log_cfg.self_comp, ctx->trace_class, ctx->ctf_tc); + if (ret) { + ret = -EINVAL; + goto end; + } + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp b/src/plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp new file mode 100644 index 00000000..84c504f9 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp @@ -0,0 +1,441 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * + * Common Trace Format Metadata Parent Link Creator. + */ + +#include + +#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) +#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/PARENT-LINKS-VISITOR" +#include "logging.hpp" + +#include "common/list.h" + +#include "ast.hpp" + +static int ctf_visitor_unary_expression(int depth, struct ctf_node *node, + struct meta_log_config *log_cfg) +{ + int ret = 0; + + switch (node->u.unary_expression.link) { + case UNARY_LINK_UNKNOWN: + case UNARY_DOTLINK: + case UNARY_ARROWLINK: + case UNARY_DOTDOTDOT: + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown expression link type: type=%d\n", + node->u.unary_expression.link); + return -EINVAL; + } + + switch (node->u.unary_expression.type) { + case UNARY_STRING: + case UNARY_SIGNED_CONSTANT: + case UNARY_UNSIGNED_CONSTANT: + break; + case UNARY_SBRAC: + node->u.unary_expression.u.sbrac_exp->parent = node; + ret = + ctf_visitor_unary_expression(depth + 1, node->u.unary_expression.u.sbrac_exp, log_cfg); + if (ret) + return ret; + break; + + case UNARY_UNKNOWN: + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown expression link type: type=%d\n", + node->u.unary_expression.link); + return -EINVAL; + } + return 0; +} + +static int ctf_visitor_type_specifier(int depth, struct ctf_node *node, + struct meta_log_config *log_cfg) +{ + int ret; + + switch (node->u.field_class_specifier.type) { + case TYPESPEC_VOID: + case TYPESPEC_CHAR: + case TYPESPEC_SHORT: + case TYPESPEC_INT: + case TYPESPEC_LONG: + case TYPESPEC_FLOAT: + case TYPESPEC_DOUBLE: + case TYPESPEC_SIGNED: + case TYPESPEC_UNSIGNED: + case TYPESPEC_BOOL: + case TYPESPEC_COMPLEX: + case TYPESPEC_IMAGINARY: + case TYPESPEC_CONST: + case TYPESPEC_ID_TYPE: + break; + case TYPESPEC_FLOATING_POINT: + case TYPESPEC_INTEGER: + case TYPESPEC_STRING: + case TYPESPEC_STRUCT: + case TYPESPEC_VARIANT: + case TYPESPEC_ENUM: + node->u.field_class_specifier.node->parent = node; + ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_specifier.node, log_cfg); + if (ret) + return ret; + break; + + case TYPESPEC_UNKNOWN: + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown type specifier: type=%d\n", + node->u.field_class_specifier.type); + return -EINVAL; + } + return 0; +} + +static int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node, + struct meta_log_config *log_cfg) +{ + int ret = 0; + struct ctf_node *iter; + + depth++; + + bt_list_for_each_entry (iter, &node->u.field_class_declarator.pointers, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + + switch (node->u.field_class_declarator.type) { + case TYPEDEC_ID: + break; + case TYPEDEC_NESTED: + if (node->u.field_class_declarator.u.nested.field_class_declarator) { + node->u.field_class_declarator.u.nested.field_class_declarator->parent = node; + ret = ctf_visitor_parent_links( + depth + 1, node->u.field_class_declarator.u.nested.field_class_declarator, log_cfg); + if (ret) + return ret; + } + if (!node->u.field_class_declarator.u.nested.abstract_array) { + bt_list_for_each_entry (iter, &node->u.field_class_declarator.u.nested.length, + siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + } + if (node->u.field_class_declarator.bitfield_len) { + node->u.field_class_declarator.bitfield_len = node; + ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_declarator.bitfield_len, + log_cfg); + if (ret) + return ret; + } + break; + case TYPEDEC_UNKNOWN: + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown type declarator: type=%d\n", + node->u.field_class_declarator.type); + return -EINVAL; + } + depth--; + return 0; +} + +int ctf_visitor_parent_links(int depth, struct ctf_node *node, struct meta_log_config *log_cfg) +{ + int ret = 0; + struct ctf_node *iter; + + if (node->visited) + return 0; + + switch (node->type) { + case NODE_ROOT: + bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.stream, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.event, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.clock, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.callsite, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_EVENT: + bt_list_for_each_entry (iter, &node->u.event.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_STREAM: + bt_list_for_each_entry (iter, &node->u.stream.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_ENV: + bt_list_for_each_entry (iter, &node->u.env.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_TRACE: + bt_list_for_each_entry (iter, &node->u.trace.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_CLOCK: + bt_list_for_each_entry (iter, &node->u.clock.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_CALLSITE: + bt_list_for_each_entry (iter, &node->u.callsite.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_CTF_EXPRESSION: + depth++; + bt_list_for_each_entry (iter, &node->u.ctf_expression.left, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.ctf_expression.right, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_UNARY_EXPRESSION: + return ctf_visitor_unary_expression(depth, node, log_cfg); + + case NODE_TYPEDEF: + depth++; + node->u.field_class_def.field_class_specifier_list->parent = node; + ret = ctf_visitor_parent_links(depth + 1, + node->u.field_class_def.field_class_specifier_list, log_cfg); + if (ret) + return ret; + bt_list_for_each_entry (iter, &node->u.field_class_def.field_class_declarators, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS_TARGET: + depth++; + node->u.field_class_alias_target.field_class_specifier_list->parent = node; + ret = ctf_visitor_parent_links( + depth + 1, node->u.field_class_alias_target.field_class_specifier_list, log_cfg); + if (ret) + return ret; + bt_list_for_each_entry (iter, &node->u.field_class_alias_target.field_class_declarators, + siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS_ALIAS: + depth++; + node->u.field_class_alias_name.field_class_specifier_list->parent = node; + ret = ctf_visitor_parent_links( + depth + 1, node->u.field_class_alias_name.field_class_specifier_list, log_cfg); + if (ret) + return ret; + bt_list_for_each_entry (iter, &node->u.field_class_alias_name.field_class_declarators, + siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS: + node->u.field_class_alias.target->parent = node; + ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.target, log_cfg); + if (ret) + return ret; + node->u.field_class_alias.alias->parent = node; + ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.alias, log_cfg); + if (ret) + return ret; + break; + + case NODE_TYPE_SPECIFIER_LIST: + bt_list_for_each_entry (iter, &node->u.field_class_specifier_list.head, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_TYPE_SPECIFIER: + ret = ctf_visitor_type_specifier(depth, node, log_cfg); + if (ret) + return ret; + break; + case NODE_POINTER: + break; + case NODE_TYPE_DECLARATOR: + ret = ctf_visitor_field_class_declarator(depth, node, log_cfg); + if (ret) + return ret; + break; + + case NODE_FLOATING_POINT: + bt_list_for_each_entry (iter, &node->u.floating_point.expressions, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_INTEGER: + bt_list_for_each_entry (iter, &node->u.integer.expressions, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_STRING: + bt_list_for_each_entry (iter, &node->u.string.expressions, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_ENUMERATOR: + bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_ENUM: + depth++; + if (node->u._enum.container_field_class) { + ret = ctf_visitor_parent_links(depth + 1, node->u._enum.container_field_class, log_cfg); + if (ret) + return ret; + } + + bt_list_for_each_entry (iter, &node->u._enum.enumerator_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + node->u.struct_or_variant_declaration.field_class_specifier_list->parent = node; + ret = ctf_visitor_parent_links( + depth + 1, node->u.struct_or_variant_declaration.field_class_specifier_list, log_cfg); + if (ret) + return ret; + bt_list_for_each_entry ( + iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_VARIANT: + bt_list_for_each_entry (iter, &node->u.variant.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_STRUCT: + bt_list_for_each_entry (iter, &node->u._struct.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u._struct.min_align, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_UNKNOWN: + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown node type: type=%d\n", node->type); + return -EINVAL; + } + return ret; +} diff --git a/src/plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp b/src/plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp new file mode 100644 index 00000000..4fad1360 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp @@ -0,0 +1,996 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * + * Common Trace Format Metadata Semantic Validator. + */ + +#include + +#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp) +#define BT_LOG_OUTPUT_LEVEL (log_cfg->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/META/SEMANTIC-VALIDATOR-VISITOR" +#include "logging.hpp" + +#include "common/list.h" + +#include "ast.hpp" + +#define _bt_list_first_entry(ptr, type, member) bt_list_entry((ptr)->next, type, member) + +static int _ctf_visitor_semantic_check(int depth, struct ctf_node *node, + struct meta_log_config *log_cfg); + +static int ctf_visitor_unary_expression(int, struct ctf_node *node, struct meta_log_config *log_cfg) +{ + struct ctf_node *iter; + int is_ctf_exp = 0, is_ctf_exp_left = 0; + + switch (node->parent->type) { + case NODE_CTF_EXPRESSION: + is_ctf_exp = 1; + bt_list_for_each_entry (iter, &node->parent->u.ctf_expression.left, siblings) { + if (iter == node) { + is_ctf_exp_left = 1; + /* + * We are a left child of a ctf expression. + * We are only allowed to be a string. + */ + if (node->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Left child of a CTF expression is only allowed to be a string."); + goto errperm; + } + break; + } + } + /* Right child of a ctf expression can be any type of unary exp. */ + break; /* OK */ + case NODE_TYPE_DECLARATOR: + /* + * We are the length of a type declarator. + */ + switch (node->u.unary_expression.type) { + case UNARY_UNSIGNED_CONSTANT: + case UNARY_STRING: + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Children of field class declarator and `enum` can only be unsigned numeric constants or references to fields (e.g., `a.b.c`)."); + goto errperm; + } + break; /* OK */ + + case NODE_STRUCT: + /* + * We are the size of a struct align attribute. + */ + switch (node->u.unary_expression.type) { + case UNARY_UNSIGNED_CONSTANT: + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Structure alignment attribute can only be an unsigned numeric constant."); + goto errperm; + } + break; + + case NODE_ENUMERATOR: + /* The enumerator's parent has validated its validity already. */ + break; /* OK */ + + case NODE_UNARY_EXPRESSION: + /* + * We disallow nested unary expressions and "sbrac" unary + * expressions. + */ + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, + "Nested unary expressions not allowed (`()` and `[]`)."); + goto errperm; + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_VARIANT: + default: + goto errinval; + } + + switch (node->u.unary_expression.link) { + case UNARY_LINK_UNKNOWN: + /* We don't allow empty link except on the first node of the list */ + if (is_ctf_exp && + _bt_list_first_entry(is_ctf_exp_left ? &node->parent->u.ctf_expression.left : + &node->parent->u.ctf_expression.right, + struct ctf_node, siblings) != node) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Empty link is not allowed except on first node of unary expression (need to separate nodes with `.` or `->`)."); + goto errperm; + } + break; /* OK */ + case UNARY_DOTLINK: + case UNARY_ARROWLINK: + /* We only allow -> and . links between children of ctf_expression. */ + if (node->parent->type != NODE_CTF_EXPRESSION) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, "Links `.` and `->` are only allowed as children of CTF expression."); + goto errperm; + } + /* + * Only strings can be separated linked by . or ->. + * This includes "", '' and non-quoted identifiers. + */ + if (node->u.unary_expression.type != UNARY_STRING) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Links `.` and `->` are only allowed to separate strings and identifiers."); + goto errperm; + } + /* We don't allow link on the first node of the list */ + if (is_ctf_exp && + _bt_list_first_entry(is_ctf_exp_left ? &node->parent->u.ctf_expression.left : + &node->parent->u.ctf_expression.right, + struct ctf_node, siblings) == node) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Links `.` and `->` are not allowed before first node of the unary expression list."); + goto errperm; + } + break; + case UNARY_DOTDOTDOT: + /* We only allow ... link between children of enumerator. */ + if (node->parent->type != NODE_ENUMERATOR) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, + "Link `...` is only allowed within enumerator."); + goto errperm; + } + /* We don't allow link on the first node of the list */ + if (_bt_list_first_entry(&node->parent->u.enumerator.values, struct ctf_node, siblings) == + node) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Link `...` is not allowed on the first node of the unary expression list."); + goto errperm; + } + break; + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown expression link type: type=%d", + node->u.unary_expression.link); + return -EINVAL; + } + return 0; + +errinval: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EINVAL; /* Incoherent structure */ + +errperm: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, + "Semantic error: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EPERM; /* Structure not allowed */ +} + +static int ctf_visitor_field_class_specifier_list(int, struct ctf_node *node, + struct meta_log_config *log_cfg) +{ + switch (node->parent->type) { + case NODE_CTF_EXPRESSION: + case NODE_TYPE_DECLARATOR: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_ROOT: + break; /* OK */ + + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + return 0; +errinval: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EINVAL; /* Incoherent structure */ +} + +static int ctf_visitor_field_class_specifier(int, struct ctf_node *node, + struct meta_log_config *log_cfg) +{ + switch (node->parent->type) { + case NODE_TYPE_SPECIFIER_LIST: + break; /* OK */ + + case NODE_CTF_EXPRESSION: + case NODE_TYPE_DECLARATOR: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + return 0; +errinval: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EINVAL; /* Incoherent structure */ +} + +static int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node, + struct meta_log_config *log_cfg) +{ + int ret = 0; + struct ctf_node *iter; + + depth++; + + switch (node->parent->type) { + case NODE_TYPE_DECLARATOR: + /* + * A nested field class declarator is not allowed to + * contain pointers. + */ + if (!bt_list_empty(&node->u.field_class_declarator.pointers)) + goto errperm; + break; /* OK */ + case NODE_TYPEALIAS_TARGET: + break; /* OK */ + case NODE_TYPEALIAS_ALIAS: + /* + * Only accept alias name containing: + * - identifier + * - identifier * (any number of pointers) + * NOT accepting alias names containing [] (would otherwise + * cause semantic clash for later declarations of + * arrays/sequences of elements, where elements could be + * arrays/sequences themselves (if allowed in field class alias). + * NOT accepting alias with identifier. The declarator should + * be either empty or contain pointer(s). + */ + if (node->u.field_class_declarator.type == TYPEDEC_NESTED) + goto errperm; + bt_list_for_each_entry (iter, + &node->parent->u.field_class_alias_name.field_class_specifier_list + ->u.field_class_specifier_list.head, + siblings) { + switch (iter->u.field_class_specifier.type) { + case TYPESPEC_FLOATING_POINT: + case TYPESPEC_INTEGER: + case TYPESPEC_STRING: + case TYPESPEC_STRUCT: + case TYPESPEC_VARIANT: + case TYPESPEC_ENUM: + if (bt_list_empty(&node->u.field_class_declarator.pointers)) + goto errperm; + break; + default: + break; + } + } + if (node->u.field_class_declarator.type == TYPEDEC_ID && + node->u.field_class_declarator.u.id) + goto errperm; + break; /* OK */ + case NODE_TYPEDEF: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.field_class_declarator.pointers, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + + switch (node->u.field_class_declarator.type) { + case TYPEDEC_ID: + break; + case TYPEDEC_NESTED: + { + if (node->u.field_class_declarator.u.nested.field_class_declarator) { + ret = _ctf_visitor_semantic_check( + depth + 1, node->u.field_class_declarator.u.nested.field_class_declarator, log_cfg); + if (ret) + return ret; + } + if (!node->u.field_class_declarator.u.nested.abstract_array) { + bt_list_for_each_entry (iter, &node->u.field_class_declarator.u.nested.length, + siblings) { + if (iter->type != NODE_UNARY_EXPRESSION) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, "Expecting unary expression as length: node-type=%s", + node_type(iter)); + return -EINVAL; + } + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + } else { + if (node->parent->type == NODE_TYPEALIAS_TARGET) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Abstract array declarator not permitted as target of field class alias."); + return -EINVAL; + } + } + if (node->u.field_class_declarator.bitfield_len) { + ret = _ctf_visitor_semantic_check(depth + 1, + node->u.field_class_declarator.bitfield_len, log_cfg); + if (ret) + return ret; + } + break; + } + case TYPEDEC_UNKNOWN: + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown field class declarator: type=%d", + node->u.field_class_declarator.type); + return -EINVAL; + } + depth--; + return 0; + +errinval: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EINVAL; /* Incoherent structure */ + +errperm: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, + "Semantic error: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EPERM; /* Structure not allowed */ +} + +static int _ctf_visitor_semantic_check(int depth, struct ctf_node *node, + struct meta_log_config *log_cfg) +{ + int ret = 0; + struct ctf_node *iter; + + if (node->visited) + return 0; + + switch (node->type) { + case NODE_ROOT: + bt_list_for_each_entry (iter, &node->u.root.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.trace, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.stream, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.root.event, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_EVENT: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.event.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_STREAM: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.stream.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_ENV: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.env.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_TRACE: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.trace.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_CLOCK: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.clock.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_CALLSITE: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.callsite.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_CTF_EXPRESSION: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + break; /* OK */ + + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + + depth++; + bt_list_for_each_entry (iter, &node->u.ctf_expression.left, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + bt_list_for_each_entry (iter, &node->u.ctf_expression.right, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_UNARY_EXPRESSION: + return ctf_visitor_unary_expression(depth, node, log_cfg); + + case NODE_TYPEDEF: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_VARIANT: + case NODE_STRUCT: + break; /* OK */ + + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_ENV: + default: + goto errinval; + } + + depth++; + ret = _ctf_visitor_semantic_check( + depth + 1, node->u.field_class_def.field_class_specifier_list, log_cfg); + if (ret) + return ret; + bt_list_for_each_entry (iter, &node->u.field_class_def.field_class_declarators, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS_TARGET: + { + int nr_declarators; + + switch (node->parent->type) { + case NODE_TYPEALIAS: + break; /* OK */ + default: + goto errinval; + } + + depth++; + ret = _ctf_visitor_semantic_check( + depth + 1, node->u.field_class_alias_target.field_class_specifier_list, log_cfg); + if (ret) + return ret; + nr_declarators = 0; + bt_list_for_each_entry (iter, &node->u.field_class_alias_target.field_class_declarators, + siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + nr_declarators++; + } + if (nr_declarators > 1) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Too many declarators in field class alias's name (maximum is 1): count=%d", + nr_declarators); + return -EINVAL; + } + depth--; + break; + } + case NODE_TYPEALIAS_ALIAS: + { + int nr_declarators; + + switch (node->parent->type) { + case NODE_TYPEALIAS: + break; /* OK */ + default: + goto errinval; + } + + depth++; + ret = _ctf_visitor_semantic_check( + depth + 1, node->u.field_class_alias_name.field_class_specifier_list, log_cfg); + if (ret) + return ret; + nr_declarators = 0; + bt_list_for_each_entry (iter, &node->u.field_class_alias_name.field_class_declarators, + siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + nr_declarators++; + } + if (nr_declarators > 1) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, + "Too many declarators in field class alias's name (maximum is 1): count=%d", + nr_declarators); + return -EINVAL; + } + depth--; + break; + } + case NODE_TYPEALIAS: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_VARIANT: + case NODE_STRUCT: + break; /* OK */ + + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_ENV: + default: + goto errinval; + } + + ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.target, log_cfg); + if (ret) + return ret; + ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.alias, log_cfg); + if (ret) + return ret; + break; + + case NODE_TYPE_SPECIFIER_LIST: + ret = ctf_visitor_field_class_specifier_list(depth, node, log_cfg); + if (ret) + return ret; + break; + case NODE_TYPE_SPECIFIER: + ret = ctf_visitor_field_class_specifier(depth, node, log_cfg); + if (ret) + return ret; + break; + case NODE_POINTER: + switch (node->parent->type) { + case NODE_TYPE_DECLARATOR: + break; /* OK */ + default: + goto errinval; + } + break; + case NODE_TYPE_DECLARATOR: + ret = ctf_visitor_field_class_declarator(depth, node, log_cfg); + if (ret) + return ret; + break; + + case NODE_FLOATING_POINT: + switch (node->parent->type) { + case NODE_TYPE_SPECIFIER: + break; /* OK */ + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + bt_list_for_each_entry (iter, &node->u.floating_point.expressions, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_INTEGER: + switch (node->parent->type) { + case NODE_TYPE_SPECIFIER: + break; /* OK */ + default: + goto errinval; + } + + bt_list_for_each_entry (iter, &node->u.integer.expressions, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_STRING: + switch (node->parent->type) { + case NODE_TYPE_SPECIFIER: + break; /* OK */ + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + + bt_list_for_each_entry (iter, &node->u.string.expressions, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_ENUMERATOR: + switch (node->parent->type) { + case NODE_ENUM: + break; + default: + goto errinval; + } + /* + * Enumerators are only allows to contain: + * numeric unary expression + * or num. unary exp. ... num. unary exp + */ + { + int count = 0; + + bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { + switch (count++) { + case 0: + if (iter->type != NODE_UNARY_EXPRESSION || + (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT && + iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) || + iter->u.unary_expression.link != UNARY_LINK_UNKNOWN) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + iter->lineno, "First unary expression of enumerator is unexpected."); + goto errperm; + } + break; + case 1: + if (iter->type != NODE_UNARY_EXPRESSION || + (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT && + iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) || + iter->u.unary_expression.link != UNARY_DOTDOTDOT) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + iter->lineno, "Second unary expression of enumerator is unexpected."); + goto errperm; + } + break; + default: + goto errperm; + } + } + } + + bt_list_for_each_entry (iter, &node->u.enumerator.values, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_ENUM: + switch (node->parent->type) { + case NODE_TYPE_SPECIFIER: + break; /* OK */ + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + + depth++; + ret = _ctf_visitor_semantic_check(depth + 1, node->u._enum.container_field_class, log_cfg); + if (ret) + return ret; + + bt_list_for_each_entry (iter, &node->u._enum.enumerator_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + depth--; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + switch (node->parent->type) { + case NODE_STRUCT: + case NODE_VARIANT: + break; + default: + goto errinval; + } + ret = _ctf_visitor_semantic_check( + depth + 1, node->u.struct_or_variant_declaration.field_class_specifier_list, log_cfg); + if (ret) + return ret; + bt_list_for_each_entry ( + iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + case NODE_VARIANT: + switch (node->parent->type) { + case NODE_TYPE_SPECIFIER: + break; /* OK */ + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + bt_list_for_each_entry (iter, &node->u.variant.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_STRUCT: + switch (node->parent->type) { + case NODE_TYPE_SPECIFIER: + break; /* OK */ + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + bt_list_for_each_entry (iter, &node->u._struct.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg); + if (ret) + return ret; + } + break; + + case NODE_UNKNOWN: + default: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown node type: type=%d", node->type); + return -EINVAL; + } + return ret; + +errinval: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO( + node->lineno, "Incoherent parent node's type: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EINVAL; /* Incoherent structure */ + +errperm: + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, + "Semantic error: node-type=%s, parent-node-type=%s", + node_type(node), node_type(node->parent)); + return -EPERM; /* Structure not allowed */ +} + +int ctf_visitor_semantic_check(int depth, struct ctf_node *node, struct meta_log_config *log_cfg) +{ + int ret = 0; + + /* + * First make sure we create the parent links for all children. Let's + * take the safe route and recreate them at each validation, just in + * case the structure has changed. + */ + ret = ctf_visitor_parent_links(depth, node, log_cfg); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, + "Cannot create parent links in metadata's AST: " + "ret=%d", + ret); + goto end; + } + + ret = _ctf_visitor_semantic_check(depth, node, log_cfg); + if (ret) { + _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, + "Cannot check metadata's AST semantics: " + "ret=%d", + ret); + goto end; + } + +end: + return ret; +} diff --git a/src/plugins/ctf/common/src/msg-iter/msg-iter.cpp b/src/plugins/ctf/common/src/msg-iter/msg-iter.cpp new file mode 100644 index 00000000..37e88c17 --- /dev/null +++ b/src/plugins/ctf/common/src/msg-iter/msg-iter.cpp @@ -0,0 +1,3007 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2018 Philippe Proulx + * + * Babeltrace - CTF message iterator + */ + +#include +#include +#include +#include +#include + +#include + +#define BT_COMP_LOG_SELF_COMP (msg_it->self_comp) +#define BT_LOG_OUTPUT_LEVEL (msg_it->log_level) +#define BT_LOG_TAG "PLUGIN/CTF/MSG-ITER" +#include "logging/comp-logging.h" + +#include "common/assert.h" +#include "common/common.h" + +#include "../bfcr/bfcr.hpp" +#include "msg-iter.hpp" + +/* A visit stack entry */ +struct stack_entry +{ + /* + * Current base field, one of: + * + * * string + * * structure + * * array + * * sequence + * * variant + * + * Field is borrowed. + */ + bt_field *base; + + /* Index of next field to set */ + size_t index; +}; + +/* Visit stack */ +struct stack +{ + struct ctf_msg_iter *msg_it; + + /* Entries (struct stack_entry) */ + GArray *entries; + + /* Number of active entries */ + size_t size; +}; + +/* State */ +enum state +{ + STATE_INIT, + STATE_SWITCH_PACKET, + STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN, + STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, + STATE_AFTER_TRACE_PACKET_HEADER, + STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN, + STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE, + STATE_AFTER_STREAM_PACKET_CONTEXT, + STATE_EMIT_MSG_STREAM_BEGINNING, + STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS, + STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS, + STATE_EMIT_MSG_DISCARDED_EVENTS, + STATE_EMIT_MSG_DISCARDED_PACKETS, + STATE_EMIT_MSG_PACKET_BEGINNING, + STATE_DSCOPE_EVENT_HEADER_BEGIN, + STATE_DSCOPE_EVENT_HEADER_CONTINUE, + STATE_AFTER_EVENT_HEADER, + STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN, + STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, + STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN, + STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, + STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, + STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, + STATE_EMIT_MSG_EVENT, + STATE_EMIT_QUEUED_MSG_EVENT, + STATE_SKIP_PACKET_PADDING, + STATE_EMIT_MSG_PACKET_END_MULTI, + STATE_EMIT_MSG_PACKET_END_SINGLE, + STATE_EMIT_QUEUED_MSG_PACKET_END, + STATE_CHECK_EMIT_MSG_STREAM_END, + STATE_EMIT_MSG_STREAM_END, + STATE_DONE, +}; + +struct end_of_packet_snapshots +{ + uint64_t discarded_events; + uint64_t packets; + uint64_t beginning_clock; + uint64_t end_clock; +}; + +/* CTF message iterator */ +struct ctf_msg_iter +{ + /* Visit stack */ + struct stack *stack; + + /* Current message iterator to create messages (weak) */ + bt_self_message_iterator *self_msg_iter; + + /* + * True if library objects are unavailable during the decoding and + * should not be created/used. + */ + bool dry_run; + + /* + * Current dynamic scope field pointer. + * + * This is set by read_dscope_begin_state() and contains the + * value of one of the pointers in `dscopes` below. + */ + bt_field *cur_dscope_field; + + /* + * True if we're done filling a string field from a text + * array/sequence payload. + */ + bool done_filling_string; + + /* Trace and classes */ + /* True to set IR fields */ + bool set_ir_fields; + + struct + { + struct ctf_trace_class *tc; + struct ctf_stream_class *sc; + struct ctf_event_class *ec; + } meta; + + /* Current packet (NULL if not created yet) */ + bt_packet *packet; + + /* Current stream (NULL if not set yet) */ + bt_stream *stream; + + /* Current event (NULL if not created yet) */ + bt_event *event; + + /* Current event message (NULL if not created yet) */ + bt_message *event_msg; + + /* + * True if we need to emit a packet beginning message before we emit + * the next event message or the packet end message. + */ + bool emit_delayed_packet_beginning_msg; + + /* + * True if this is the first packet we are reading, and therefore if we + * should emit a stream beginning message. + */ + bool emit_stream_beginning_message; + + /* + * True if we need to emit a stream end message at the end of the + * current stream. A live stream may never receive any data and thus + * never send a stream beginning message which removes the need to emit + * a stream end message. + */ + bool emit_stream_end_message; + + /* Database of current dynamic scopes */ + struct + { + bt_field *stream_packet_context; + bt_field *event_common_context; + bt_field *event_spec_context; + bt_field *event_payload; + } dscopes; + + /* Current state */ + enum state state; + + /* Current medium buffer data */ + struct + { + /* Last address provided by medium */ + const uint8_t *addr; + + /* Buffer size provided by medium (bytes) */ + size_t sz; + + /* Offset within whole packet of addr (bits) */ + size_t packet_offset; + + /* Current position from addr (bits) */ + size_t at; + + /* Position of the last event header from addr (bits) */ + size_t last_eh_at; + } buf; + + /* Binary type reader */ + struct bt_bfcr *bfcr; + + /* Current medium data */ + struct + { + struct ctf_msg_iter_medium_ops medops; + size_t max_request_sz; + void *data; + } medium; + + /* Current packet size (bits) (-1 if unknown) */ + int64_t cur_exp_packet_total_size; + + /* Current content size (bits) (-1 if unknown) */ + int64_t cur_exp_packet_content_size; + + /* Current stream class ID */ + int64_t cur_stream_class_id; + + /* Current event class ID */ + int64_t cur_event_class_id; + + /* Current data stream ID */ + int64_t cur_data_stream_id; + + /* + * Offset, in the underlying media, of the current packet's + * start (-1 if unknown). + */ + off_t cur_packet_offset; + + /* Default clock's current value */ + uint64_t default_clock_snapshot; + + /* End of current packet snapshots */ + struct end_of_packet_snapshots snapshots; + + /* End of previous packet snapshots */ + struct end_of_packet_snapshots prev_packet_snapshots; + + /* Stored values (for sequence lengths, variant tags) */ + GArray *stored_values; + + /* Iterator's current log level */ + bt_logging_level log_level; + + /* Iterator's owning self component, or `NULL` if none (query) */ + bt_self_component *self_comp; +}; + +static inline const char *state_string(enum state state) +{ + switch (state) { + case STATE_INIT: + return "INIT"; + case STATE_SWITCH_PACKET: + return "SWITCH_PACKET"; + case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN: + return "DSCOPE_TRACE_PACKET_HEADER_BEGIN"; + case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE: + return "DSCOPE_TRACE_PACKET_HEADER_CONTINUE"; + case STATE_AFTER_TRACE_PACKET_HEADER: + return "AFTER_TRACE_PACKET_HEADER"; + case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN: + return "DSCOPE_STREAM_PACKET_CONTEXT_BEGIN"; + case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE: + return "DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE"; + case STATE_AFTER_STREAM_PACKET_CONTEXT: + return "AFTER_STREAM_PACKET_CONTEXT"; + case STATE_EMIT_MSG_STREAM_BEGINNING: + return "EMIT_MSG_STREAM_BEGINNING"; + case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS: + return "CHECK_EMIT_MSG_DISCARDED_EVENTS"; + case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS: + return "CHECK_EMIT_MSG_DISCARDED_PACKETS"; + case STATE_EMIT_MSG_PACKET_BEGINNING: + return "EMIT_MSG_PACKET_BEGINNING"; + case STATE_EMIT_MSG_DISCARDED_EVENTS: + return "EMIT_MSG_DISCARDED_EVENTS"; + case STATE_EMIT_MSG_DISCARDED_PACKETS: + return "EMIT_MSG_DISCARDED_PACKETS"; + case STATE_DSCOPE_EVENT_HEADER_BEGIN: + return "DSCOPE_EVENT_HEADER_BEGIN"; + case STATE_DSCOPE_EVENT_HEADER_CONTINUE: + return "DSCOPE_EVENT_HEADER_CONTINUE"; + case STATE_AFTER_EVENT_HEADER: + return "AFTER_EVENT_HEADER"; + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: + return "DSCOPE_EVENT_COMMON_CONTEXT_BEGIN"; + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: + return "DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE"; + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: + return "DSCOPE_EVENT_SPEC_CONTEXT_BEGIN"; + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: + return "DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE"; + case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: + return "DSCOPE_EVENT_PAYLOAD_BEGIN"; + case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: + return "DSCOPE_EVENT_PAYLOAD_CONTINUE"; + case STATE_EMIT_MSG_EVENT: + return "EMIT_MSG_EVENT"; + case STATE_EMIT_QUEUED_MSG_EVENT: + return "EMIT_QUEUED_MSG_EVENT"; + case STATE_SKIP_PACKET_PADDING: + return "SKIP_PACKET_PADDING"; + case STATE_EMIT_MSG_PACKET_END_MULTI: + return "EMIT_MSG_PACKET_END_MULTI"; + case STATE_EMIT_MSG_PACKET_END_SINGLE: + return "EMIT_MSG_PACKET_END_SINGLE"; + case STATE_EMIT_QUEUED_MSG_PACKET_END: + return "EMIT_QUEUED_MSG_PACKET_END"; + case STATE_CHECK_EMIT_MSG_STREAM_END: + return "CHECK_EMIT_MSG_STREAM_END"; + case STATE_EMIT_MSG_STREAM_END: + return "EMIT_MSG_STREAM_END"; + case STATE_DONE: + return "DONE"; + } + + bt_common_abort(); +} + +static struct stack *stack_new(struct ctf_msg_iter *msg_it) +{ + bt_self_component *self_comp = msg_it->self_comp; + struct stack *stack = NULL; + + stack = g_new0(struct stack, 1); + if (!stack) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate one stack."); + goto error; + } + + stack->msg_it = msg_it; + stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry)); + if (!stack->entries) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate a GArray."); + goto error; + } + + BT_COMP_LOGD("Created stack: msg-it-addr=%p, stack-addr=%p", msg_it, stack); + goto end; + +error: + g_free(stack); + stack = NULL; + +end: + return stack; +} + +static void stack_destroy(struct stack *stack) +{ + struct ctf_msg_iter *msg_it; + + BT_ASSERT_DBG(stack); + msg_it = stack->msg_it; + BT_COMP_LOGD("Destroying stack: addr=%p", stack); + + if (stack->entries) { + g_array_free(stack->entries, TRUE); + } + + g_free(stack); +} + +static void stack_push(struct stack *stack, bt_field *base) +{ + struct stack_entry *entry; + struct ctf_msg_iter *msg_it; + + BT_ASSERT_DBG(stack); + msg_it = stack->msg_it; + BT_ASSERT_DBG(base); + BT_COMP_LOGT("Pushing base field on stack: stack-addr=%p, " + "stack-size-before=%zu, stack-size-after=%zu", + stack, stack->size, stack->size + 1); + + if (stack->entries->len == stack->size) { + g_array_set_size(stack->entries, stack->size + 1); + } + + entry = &bt_g_array_index(stack->entries, struct stack_entry, stack->size); + entry->base = base; + entry->index = 0; + stack->size++; +} + +static inline unsigned int stack_size(struct stack *stack) +{ + BT_ASSERT_DBG(stack); + return stack->size; +} + +static void stack_pop(struct stack *stack) +{ + struct ctf_msg_iter *msg_it; + + BT_ASSERT_DBG(stack); + BT_ASSERT_DBG(stack_size(stack)); + msg_it = stack->msg_it; + BT_COMP_LOGT("Popping from stack: " + "stack-addr=%p, stack-size-before=%zu, stack-size-after=%zu", + stack, stack->size, stack->size - 1); + stack->size--; +} + +static inline struct stack_entry *stack_top(struct stack *stack) +{ + BT_ASSERT_DBG(stack); + BT_ASSERT_DBG(stack_size(stack)); + return &bt_g_array_index(stack->entries, struct stack_entry, stack->size - 1); +} + +static inline bool stack_empty(struct stack *stack) +{ + return stack_size(stack) == 0; +} + +static void stack_clear(struct stack *stack) +{ + BT_ASSERT_DBG(stack); + stack->size = 0; +} + +static inline enum ctf_msg_iter_status +msg_iter_status_from_m_status(enum ctf_msg_iter_medium_status m_status) +{ + /* They are the same */ + return (ctf_msg_iter_status) m_status; +} + +static inline size_t buf_size_bits(struct ctf_msg_iter *msg_it) +{ + return msg_it->buf.sz * 8; +} + +static inline size_t buf_available_bits(struct ctf_msg_iter *msg_it) +{ + return buf_size_bits(msg_it) - msg_it->buf.at; +} + +static inline size_t packet_at(struct ctf_msg_iter *msg_it) +{ + return msg_it->buf.packet_offset + msg_it->buf.at; +} + +static inline void buf_consume_bits(struct ctf_msg_iter *msg_it, size_t incr) +{ + BT_COMP_LOGT("Advancing cursor: msg-it-addr=%p, cur-before=%zu, cur-after=%zu", msg_it, + msg_it->buf.at, msg_it->buf.at + incr); + msg_it->buf.at += incr; +} + +static enum ctf_msg_iter_status request_medium_bytes(struct ctf_msg_iter *msg_it) +{ + bt_self_component *self_comp = msg_it->self_comp; + uint8_t *buffer_addr = NULL; + size_t buffer_sz = 0; + enum ctf_msg_iter_medium_status m_status; + + BT_COMP_LOGD("Calling user function (request bytes): msg-it-addr=%p, " + "request-size=%zu", + msg_it, msg_it->medium.max_request_sz); + m_status = msg_it->medium.medops.request_bytes(msg_it->medium.max_request_sz, &buffer_addr, + &buffer_sz, msg_it->medium.data); + BT_COMP_LOGD("User function returned: status=%s, buf-addr=%p, buf-size=%zu", + ctf_msg_iter_medium_status_string(m_status), buffer_addr, buffer_sz); + if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_OK) { + BT_ASSERT(buffer_sz != 0); + + /* New packet offset is old one + old size (in bits) */ + msg_it->buf.packet_offset += buf_size_bits(msg_it); + + /* Restart at the beginning of the new medium buffer */ + msg_it->buf.at = 0; + msg_it->buf.last_eh_at = SIZE_MAX; + + /* New medium buffer size */ + msg_it->buf.sz = buffer_sz; + + /* New medium buffer address */ + msg_it->buf.addr = buffer_addr; + + BT_COMP_LOGD("User function returned new bytes: " + "packet-offset=%zu, cur=%zu, size=%zu, addr=%p", + msg_it->buf.packet_offset, msg_it->buf.at, msg_it->buf.sz, msg_it->buf.addr); + BT_COMP_LOGT_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:", buffer_addr); + } else if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) { + /* + * User returned end of stream: validate that we're not + * in the middle of a packet header, packet context, or + * event. + */ + if (msg_it->cur_exp_packet_total_size >= 0) { + if (packet_at(msg_it) == msg_it->cur_exp_packet_total_size) { + goto end; + } + } else { + if (packet_at(msg_it) == 0) { + goto end; + } + + if (msg_it->buf.last_eh_at != SIZE_MAX && msg_it->buf.at == msg_it->buf.last_eh_at) { + goto end; + } + } + + /* All other states are invalid */ + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "User function returned %s, but message iterator is in an unexpected state: " + "state=%s, cur-packet-size=%" PRId64 ", cur=%zu, " + "packet-cur=%zu, last-eh-at=%zu", + ctf_msg_iter_medium_status_string(m_status), state_string(msg_it->state), + msg_it->cur_exp_packet_total_size, msg_it->buf.at, packet_at(msg_it), + msg_it->buf.last_eh_at); + m_status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR; + } else if (m_status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "User function failed: " + "status=%s", + ctf_msg_iter_medium_status_string(m_status)); + } + +end: + return msg_iter_status_from_m_status(m_status); +} + +static inline enum ctf_msg_iter_status buf_ensure_available_bits(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + + if (G_UNLIKELY(buf_available_bits(msg_it) == 0)) { + /* + * This _cannot_ return CTF_MSG_ITER_STATUS_OK + * _and_ no bits. + */ + status = request_medium_bytes(msg_it); + } + + return status; +} + +static enum ctf_msg_iter_status +read_dscope_begin_state(struct ctf_msg_iter *msg_it, struct ctf_field_class *dscope_fc, + enum state done_state, enum state continue_state, bt_field *dscope_field) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + enum bt_bfcr_status bfcr_status; + size_t consumed_bits; + + msg_it->cur_dscope_field = dscope_field; + BT_COMP_LOGT("Starting BFCR: msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p", msg_it, msg_it->bfcr, + dscope_fc); + consumed_bits = bt_bfcr_start(msg_it->bfcr, dscope_fc, msg_it->buf.addr, msg_it->buf.at, + packet_at(msg_it), msg_it->buf.sz, &bfcr_status); + BT_COMP_LOGT("BFCR consumed bits: size=%zu", consumed_bits); + + switch (bfcr_status) { + case BT_BFCR_STATUS_OK: + /* Field class was read completely */ + BT_COMP_LOGT_STR("Field was completely decoded."); + msg_it->state = done_state; + break; + case BT_BFCR_STATUS_EOF: + BT_COMP_LOGT_STR("BFCR needs more data to decode field completely."); + msg_it->state = continue_state; + break; + default: + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "BFCR failed to start: msg-it-addr=%p, bfcr-addr=%p, " + "status=%s", + msg_it, msg_it->bfcr, bt_bfcr_status_string(bfcr_status)); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + /* Consume bits now since we know we're not in an error state */ + buf_consume_bits(msg_it, consumed_bits); + +end: + return status; +} + +static enum ctf_msg_iter_status read_dscope_continue_state(struct ctf_msg_iter *msg_it, + enum state done_state) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + enum bt_bfcr_status bfcr_status; + size_t consumed_bits; + + BT_COMP_LOGT("Continuing BFCR: msg-it-addr=%p, bfcr-addr=%p", msg_it, msg_it->bfcr); + + status = buf_ensure_available_bits(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + if (status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot ensure that buffer has at least one byte: " + "msg-addr=%p, status=%s", + msg_it, ctf_msg_iter_status_string(status)); + } else { + BT_COMP_LOGT("Cannot ensure that buffer has at least one byte: " + "msg-addr=%p, status=%s", + msg_it, ctf_msg_iter_status_string(status)); + } + + goto end; + } + + consumed_bits = bt_bfcr_continue(msg_it->bfcr, msg_it->buf.addr, msg_it->buf.sz, &bfcr_status); + BT_COMP_LOGT("BFCR consumed bits: size=%zu", consumed_bits); + + switch (bfcr_status) { + case BT_BFCR_STATUS_OK: + /* Type was read completely. */ + BT_COMP_LOGT_STR("Field was completely decoded."); + msg_it->state = done_state; + break; + case BT_BFCR_STATUS_EOF: + /* Stay in this continue state. */ + BT_COMP_LOGT_STR("BFCR needs more data to decode field completely."); + break; + default: + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "BFCR failed to continue: msg-it-addr=%p, bfcr-addr=%p, " + "status=%s", + msg_it, msg_it->bfcr, bt_bfcr_status_string(bfcr_status)); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + /* Consume bits now since we know we're not in an error state. */ + buf_consume_bits(msg_it, consumed_bits); +end: + return status; +} + +static void release_event_dscopes(struct ctf_msg_iter *msg_it) +{ + msg_it->dscopes.event_common_context = NULL; + msg_it->dscopes.event_spec_context = NULL; + msg_it->dscopes.event_payload = NULL; +} + +static void release_all_dscopes(struct ctf_msg_iter *msg_it) +{ + msg_it->dscopes.stream_packet_context = NULL; + + release_event_dscopes(msg_it); +} + +static enum ctf_msg_iter_status switch_packet_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status; + bt_self_component *self_comp = msg_it->self_comp; + + /* + * We don't put the stream class here because we need to make + * sure that all the packets processed by the same message + * iterator refer to the same stream class (the first one). + */ + BT_ASSERT(msg_it); + + if (msg_it->cur_exp_packet_total_size != -1) { + msg_it->cur_packet_offset += msg_it->cur_exp_packet_total_size; + } + + BT_COMP_LOGD("Switching packet: msg-it-addr=%p, cur=%zu, " + "packet-offset=%" PRId64, + msg_it, msg_it->buf.at, msg_it->cur_packet_offset); + stack_clear(msg_it->stack); + msg_it->meta.ec = NULL; + BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); + BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg); + release_all_dscopes(msg_it); + msg_it->cur_dscope_field = NULL; + + if (msg_it->medium.medops.switch_packet) { + enum ctf_msg_iter_medium_status medium_status; + + medium_status = msg_it->medium.medops.switch_packet(msg_it->medium.data); + if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) { + /* No more packets. */ + msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END; + status = CTF_MSG_ITER_STATUS_OK; + goto end; + } else if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) { + status = msg_iter_status_from_m_status(medium_status); + goto end; + } + + /* + * After the packet switch, the medium might want to give us a + * different buffer for the new packet. + */ + status = request_medium_bytes(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + } + + /* + * Adjust current buffer so that addr points to the beginning of the new + * packet. + */ + if (msg_it->buf.addr) { + size_t consumed_bytes = (size_t) (msg_it->buf.at / CHAR_BIT); + + /* Packets are assumed to start on a byte frontier. */ + if (msg_it->buf.at % CHAR_BIT) { + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "Cannot switch packet: current position is not a multiple of 8: " + "msg-it-addr=%p, cur=%zu", + msg_it, msg_it->buf.at); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + msg_it->buf.addr += consumed_bytes; + msg_it->buf.sz -= consumed_bytes; + msg_it->buf.at = 0; + msg_it->buf.packet_offset = 0; + BT_COMP_LOGD("Adjusted buffer: addr=%p, size=%zu", msg_it->buf.addr, msg_it->buf.sz); + } + + msg_it->cur_exp_packet_content_size = -1; + msg_it->cur_exp_packet_total_size = -1; + msg_it->cur_stream_class_id = -1; + msg_it->cur_event_class_id = -1; + msg_it->cur_data_stream_id = -1; + msg_it->prev_packet_snapshots = msg_it->snapshots; + msg_it->snapshots.discarded_events = UINT64_C(-1); + msg_it->snapshots.packets = UINT64_C(-1); + msg_it->snapshots.beginning_clock = UINT64_C(-1); + msg_it->snapshots.end_clock = UINT64_C(-1); + msg_it->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN; + + status = CTF_MSG_ITER_STATUS_OK; +end: + return status; +} + +static enum ctf_msg_iter_status read_packet_header_begin_state(struct ctf_msg_iter *msg_it) +{ + struct ctf_field_class *packet_header_fc = NULL; + bt_self_component *self_comp = msg_it->self_comp; + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + + /* + * Make sure at least one bit is available for this packet. An + * empty packet is impossible. If we reach the end of the medium + * at this point, then it's considered the end of the stream. + */ + status = buf_ensure_available_bits(msg_it); + switch (status) { + case CTF_MSG_ITER_STATUS_OK: + break; + case CTF_MSG_ITER_STATUS_EOF: + status = CTF_MSG_ITER_STATUS_OK; + msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END; + goto end; + default: + goto end; + } + + /* Packet header class is common to the whole trace class. */ + packet_header_fc = msg_it->meta.tc->packet_header_fc; + if (!packet_header_fc) { + msg_it->state = STATE_AFTER_TRACE_PACKET_HEADER; + goto end; + } + + msg_it->cur_stream_class_id = -1; + msg_it->cur_event_class_id = -1; + msg_it->cur_data_stream_id = -1; + BT_COMP_LOGD("Decoding packet header field: " + "msg-it-addr=%p, trace-class-addr=%p, fc-addr=%p", + msg_it, msg_it->meta.tc, packet_header_fc); + status = read_dscope_begin_state(msg_it, packet_header_fc, STATE_AFTER_TRACE_PACKET_HEADER, + STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, NULL); + if (status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot decode packet header field: " + "msg-it-addr=%p, trace-class-addr=%p, " + "fc-addr=%p", + msg_it, msg_it->meta.tc, packet_header_fc); + } + +end: + return status; +} + +static enum ctf_msg_iter_status read_packet_header_continue_state(struct ctf_msg_iter *msg_it) +{ + return read_dscope_continue_state(msg_it, STATE_AFTER_TRACE_PACKET_HEADER); +} + +static inline enum ctf_msg_iter_status set_current_stream_class(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_stream_class *new_stream_class = NULL; + + if (msg_it->cur_stream_class_id == -1) { + /* + * No current stream class ID field, therefore only one + * stream class. + */ + if (msg_it->meta.tc->stream_classes->len != 1) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Need exactly one stream class since there's " + "no stream class ID field: " + "msg-it-addr=%p", + msg_it); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + new_stream_class = (ctf_stream_class *) msg_it->meta.tc->stream_classes->pdata[0]; + msg_it->cur_stream_class_id = new_stream_class->id; + } + + new_stream_class = + ctf_trace_class_borrow_stream_class_by_id(msg_it->meta.tc, msg_it->cur_stream_class_id); + if (!new_stream_class) { + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "No stream class with ID of stream class ID to use in trace class: " + "msg-it-addr=%p, stream-class-id=%" PRIu64 ", " + "trace-class-addr=%p", + msg_it, msg_it->cur_stream_class_id, msg_it->meta.tc); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + if (msg_it->meta.sc) { + if (new_stream_class != msg_it->meta.sc) { + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "Two packets refer to two different stream classes within the same packet sequence: " + "msg-it-addr=%p, prev-stream-class-addr=%p, " + "prev-stream-class-id=%" PRId64 ", " + "next-stream-class-addr=%p, " + "next-stream-class-id=%" PRId64 ", " + "trace-addr=%p", + msg_it, msg_it->meta.sc, msg_it->meta.sc->id, new_stream_class, + new_stream_class->id, msg_it->meta.tc); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + } else { + msg_it->meta.sc = new_stream_class; + } + + BT_COMP_LOGD("Set current stream class: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64, + msg_it, msg_it->meta.sc, msg_it->meta.sc->id); + +end: + return status; +} + +static inline enum ctf_msg_iter_status set_current_stream(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + bt_stream *stream = NULL; + + BT_COMP_LOGD("Calling user function (get stream): msg-it-addr=%p, " + "stream-class-addr=%p, stream-class-id=%" PRId64, + msg_it, msg_it->meta.sc, msg_it->meta.sc->id); + stream = msg_it->medium.medops.borrow_stream(msg_it->meta.sc->ir_sc, msg_it->cur_data_stream_id, + msg_it->medium.data); + bt_stream_get_ref(stream); + BT_COMP_LOGD("User function returned: stream-addr=%p", stream); + if (!stream) { + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "User function failed to return a stream object for the given stream class."); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + if (msg_it->stream && stream != msg_it->stream) { + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "User function returned a different stream than the previous one for the same sequence of packets."); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + BT_STREAM_MOVE_REF(msg_it->stream, stream); + +end: + bt_stream_put_ref(stream); + return status; +} + +static inline enum ctf_msg_iter_status set_current_packet(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + bt_packet *packet = NULL; + + BT_COMP_LOGD("Creating packet from stream: " + "msg-it-addr=%p, stream-addr=%p, " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64, + msg_it, msg_it->stream, msg_it->meta.sc, msg_it->meta.sc->id); + + /* Create packet */ + BT_ASSERT(msg_it->stream); + packet = bt_packet_create(msg_it->stream); + if (!packet) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create packet from stream: " + "msg-it-addr=%p, stream-addr=%p, " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64, + msg_it, msg_it->stream, msg_it->meta.sc, msg_it->meta.sc->id); + goto error; + } + + goto end; + +error: + BT_PACKET_PUT_REF_AND_RESET(packet); + status = CTF_MSG_ITER_STATUS_ERROR; + +end: + BT_PACKET_MOVE_REF(msg_it->packet, packet); + return status; +} + +static enum ctf_msg_iter_status after_packet_header_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status; + + status = set_current_stream_class(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + if (!msg_it->dry_run) { + status = set_current_stream(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + status = set_current_packet(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + } + + msg_it->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN; + + status = CTF_MSG_ITER_STATUS_OK; + +end: + return status; +} + +static enum ctf_msg_iter_status read_packet_context_begin_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_field_class *packet_context_fc; + + BT_ASSERT(msg_it->meta.sc); + packet_context_fc = msg_it->meta.sc->packet_context_fc; + if (!packet_context_fc) { + BT_COMP_LOGD("No packet packet context field class in stream class: continuing: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64, + msg_it, msg_it->meta.sc, msg_it->meta.sc->id); + msg_it->state = STATE_AFTER_STREAM_PACKET_CONTEXT; + goto end; + } + + if (packet_context_fc->in_ir && !msg_it->dry_run) { + BT_ASSERT(!msg_it->dscopes.stream_packet_context); + BT_ASSERT(msg_it->packet); + msg_it->dscopes.stream_packet_context = bt_packet_borrow_context_field(msg_it->packet); + BT_ASSERT(msg_it->dscopes.stream_packet_context); + } + + BT_COMP_LOGD("Decoding packet context field: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", fc-addr=%p", + msg_it, msg_it->meta.sc, msg_it->meta.sc->id, packet_context_fc); + status = read_dscope_begin_state(msg_it, packet_context_fc, STATE_AFTER_STREAM_PACKET_CONTEXT, + STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE, + msg_it->dscopes.stream_packet_context); + if (status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot decode packet context field: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", fc-addr=%p", + msg_it, msg_it->meta.sc, msg_it->meta.sc->id, packet_context_fc); + } + +end: + return status; +} + +static enum ctf_msg_iter_status read_packet_context_continue_state(struct ctf_msg_iter *msg_it) +{ + return read_dscope_continue_state(msg_it, STATE_AFTER_STREAM_PACKET_CONTEXT); +} + +static enum ctf_msg_iter_status set_current_packet_content_sizes(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + + if (msg_it->cur_exp_packet_total_size == -1) { + if (msg_it->cur_exp_packet_content_size != -1) { + msg_it->cur_exp_packet_total_size = msg_it->cur_exp_packet_content_size; + } + } else { + if (msg_it->cur_exp_packet_content_size == -1) { + msg_it->cur_exp_packet_content_size = msg_it->cur_exp_packet_total_size; + } + } + + BT_ASSERT( + (msg_it->cur_exp_packet_total_size >= 0 && msg_it->cur_exp_packet_content_size >= 0) || + (msg_it->cur_exp_packet_total_size < 0 && msg_it->cur_exp_packet_content_size < 0)); + + if (msg_it->cur_exp_packet_content_size > msg_it->cur_exp_packet_total_size) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Invalid packet or content size: " + "content size is greater than packet size: " + "msg-it-addr=%p, packet-context-field-addr=%p, " + "packet-size=%" PRId64 ", content-size=%" PRId64, + msg_it, msg_it->dscopes.stream_packet_context, + msg_it->cur_exp_packet_total_size, + msg_it->cur_exp_packet_content_size); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + BT_COMP_LOGD("Set current packet and content sizes: " + "msg-it-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64, + msg_it, msg_it->cur_exp_packet_total_size, msg_it->cur_exp_packet_content_size); + +end: + return status; +} + +static enum ctf_msg_iter_status after_packet_context_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status; + + status = set_current_packet_content_sizes(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + if (msg_it->emit_stream_beginning_message) { + msg_it->state = STATE_EMIT_MSG_STREAM_BEGINNING; + } else { + msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS; + } + +end: + return status; +} + +static enum ctf_msg_iter_status read_event_header_begin_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_field_class *event_header_fc = NULL; + + /* Reset the position of the last event header */ + msg_it->buf.last_eh_at = msg_it->buf.at; + msg_it->cur_event_class_id = -1; + + /* Check if we have some content left */ + if (msg_it->cur_exp_packet_content_size >= 0) { + if (G_UNLIKELY(packet_at(msg_it) == msg_it->cur_exp_packet_content_size)) { + /* No more events! */ + BT_COMP_LOGD("Reached end of packet: msg-it-addr=%p, " + "cur=%zu", + msg_it, packet_at(msg_it)); + msg_it->state = STATE_EMIT_MSG_PACKET_END_MULTI; + goto end; + } else if (G_UNLIKELY(packet_at(msg_it) > msg_it->cur_exp_packet_content_size)) { + /* That's not supposed to happen */ + BT_COMP_LOGD( + "Before decoding event header field: cursor is passed the packet's content: " + "msg-it-addr=%p, content-size=%" PRId64 ", " + "cur=%zu", + msg_it, msg_it->cur_exp_packet_content_size, packet_at(msg_it)); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + } else { + /* + * "Infinite" content: we're done when the medium has + * nothing else for us. + */ + status = buf_ensure_available_bits(msg_it); + switch (status) { + case CTF_MSG_ITER_STATUS_OK: + break; + case CTF_MSG_ITER_STATUS_EOF: + status = CTF_MSG_ITER_STATUS_OK; + msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE; + goto end; + default: + goto end; + } + } + + release_event_dscopes(msg_it); + BT_ASSERT(msg_it->meta.sc); + event_header_fc = msg_it->meta.sc->event_header_fc; + if (!event_header_fc) { + msg_it->state = STATE_AFTER_EVENT_HEADER; + goto end; + } + + BT_COMP_LOGD("Decoding event header field: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", " + "fc-addr=%p", + msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_header_fc); + status = read_dscope_begin_state(msg_it, event_header_fc, STATE_AFTER_EVENT_HEADER, + STATE_DSCOPE_EVENT_HEADER_CONTINUE, NULL); + if (status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot decode event header field: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", fc-addr=%p", + msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_header_fc); + } + +end: + return status; +} + +static enum ctf_msg_iter_status read_event_header_continue_state(struct ctf_msg_iter *msg_it) +{ + return read_dscope_continue_state(msg_it, STATE_AFTER_EVENT_HEADER); +} + +static inline enum ctf_msg_iter_status set_current_event_class(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + + struct ctf_event_class *new_event_class = NULL; + + if (msg_it->cur_event_class_id == -1) { + /* + * No current event class ID field, therefore only one + * event class. + */ + if (msg_it->meta.sc->event_classes->len != 1) { + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "Need exactly one event class since there's no event class ID field: " + "msg-it-addr=%p", + msg_it); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + new_event_class = (ctf_event_class *) msg_it->meta.sc->event_classes->pdata[0]; + msg_it->cur_event_class_id = new_event_class->id; + } + + new_event_class = + ctf_stream_class_borrow_event_class_by_id(msg_it->meta.sc, msg_it->cur_event_class_id); + if (!new_event_class) { + BT_COMP_LOGE_APPEND_CAUSE( + self_comp, + "No event class with ID of event class ID to use in stream class: " + "msg-it-addr=%p, stream-class-id=%" PRIu64 ", " + "event-class-id=%" PRIu64 ", " + "trace-class-addr=%p", + msg_it, msg_it->meta.sc->id, msg_it->cur_event_class_id, msg_it->meta.tc); + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + + msg_it->meta.ec = new_event_class; + BT_COMP_LOGD("Set current event class: " + "msg-it-addr=%p, event-class-addr=%p, " + "event-class-id=%" PRId64 ", " + "event-class-name=\"%s\"", + msg_it, msg_it->meta.ec, msg_it->meta.ec->id, msg_it->meta.ec->name->str); + +end: + return status; +} + +static inline enum ctf_msg_iter_status set_current_event_message(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + bt_message *msg = NULL; + + BT_ASSERT_DBG(msg_it->meta.ec); + BT_ASSERT_DBG(msg_it->packet); + BT_COMP_LOGD("Creating event message from event class and packet: " + "msg-it-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p", + msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->packet); + BT_ASSERT_DBG(msg_it->self_msg_iter); + BT_ASSERT_DBG(msg_it->meta.sc); + + if (bt_stream_class_borrow_default_clock_class(msg_it->meta.sc->ir_sc)) { + msg = bt_message_event_create_with_packet_and_default_clock_snapshot( + msg_it->self_msg_iter, msg_it->meta.ec->ir_ec, msg_it->packet, + msg_it->default_clock_snapshot); + } else { + msg = bt_message_event_create_with_packet(msg_it->self_msg_iter, msg_it->meta.ec->ir_ec, + msg_it->packet); + } + + if (!msg) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create event message: " + "msg-it-addr=%p, ec-addr=%p, ec-name=\"%s\", " + "packet-addr=%p", + msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, + msg_it->packet); + goto error; + } + + goto end; + +error: + BT_MESSAGE_PUT_REF_AND_RESET(msg); + status = CTF_MSG_ITER_STATUS_ERROR; + +end: + BT_MESSAGE_MOVE_REF(msg_it->event_msg, msg); + return status; +} + +static enum ctf_msg_iter_status after_event_header_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status; + + status = set_current_event_class(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + if (G_UNLIKELY(msg_it->dry_run)) { + goto next_state; + } + + status = set_current_event_message(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + msg_it->event = bt_message_event_borrow_event(msg_it->event_msg); + BT_ASSERT_DBG(msg_it->event); + +next_state: + msg_it->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN; + +end: + return status; +} + +static enum ctf_msg_iter_status read_event_common_context_begin_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_field_class *event_common_context_fc; + + event_common_context_fc = msg_it->meta.sc->event_common_context_fc; + if (!event_common_context_fc) { + msg_it->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN; + goto end; + } + + if (event_common_context_fc->in_ir && !msg_it->dry_run) { + BT_ASSERT_DBG(!msg_it->dscopes.event_common_context); + msg_it->dscopes.event_common_context = bt_event_borrow_common_context_field(msg_it->event); + BT_ASSERT_DBG(msg_it->dscopes.event_common_context); + } + + BT_COMP_LOGT("Decoding event common context field: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", " + "fc-addr=%p", + msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_common_context_fc); + status = read_dscope_begin_state( + msg_it, event_common_context_fc, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN, + STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, msg_it->dscopes.event_common_context); + if (status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot decode event common context field: " + "msg-it-addr=%p, stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", fc-addr=%p", + msg_it, msg_it->meta.sc, msg_it->meta.sc->id, + event_common_context_fc); + } + +end: + return status; +} + +static enum ctf_msg_iter_status +read_event_common_context_continue_state(struct ctf_msg_iter *msg_it) +{ + return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN); +} + +static enum ctf_msg_iter_status read_event_spec_context_begin_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_field_class *event_spec_context_fc; + + event_spec_context_fc = msg_it->meta.ec->spec_context_fc; + if (!event_spec_context_fc) { + msg_it->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN; + goto end; + } + + if (event_spec_context_fc->in_ir && !msg_it->dry_run) { + BT_ASSERT_DBG(!msg_it->dscopes.event_spec_context); + msg_it->dscopes.event_spec_context = bt_event_borrow_specific_context_field(msg_it->event); + BT_ASSERT_DBG(msg_it->dscopes.event_spec_context); + } + + BT_COMP_LOGT("Decoding event specific context field: " + "msg-it-addr=%p, event-class-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64 ", " + "fc-addr=%p", + msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->meta.ec->id, + event_spec_context_fc); + status = read_dscope_begin_state( + msg_it, event_spec_context_fc, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN, + STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, msg_it->dscopes.event_spec_context); + if (status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot decode event specific context field: " + "msg-it-addr=%p, event-class-addr=%p, " + "event-class-name=\"%s\", " + "event-class-id=%" PRId64 ", fc-addr=%p", + msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, + msg_it->meta.ec->id, event_spec_context_fc); + } + +end: + return status; +} + +static enum ctf_msg_iter_status read_event_spec_context_continue_state(struct ctf_msg_iter *msg_it) +{ + return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN); +} + +static enum ctf_msg_iter_status read_event_payload_begin_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_field_class *event_payload_fc; + + event_payload_fc = msg_it->meta.ec->payload_fc; + if (!event_payload_fc) { + msg_it->state = STATE_EMIT_MSG_EVENT; + goto end; + } + + if (event_payload_fc->in_ir && !msg_it->dry_run) { + BT_ASSERT_DBG(!msg_it->dscopes.event_payload); + msg_it->dscopes.event_payload = bt_event_borrow_payload_field(msg_it->event); + BT_ASSERT_DBG(msg_it->dscopes.event_payload); + } + + BT_COMP_LOGT("Decoding event payload field: " + "msg-it-addr=%p, event-class-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64 ", " + "fc-addr=%p", + msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->meta.ec->id, + event_payload_fc); + status = + read_dscope_begin_state(msg_it, event_payload_fc, STATE_EMIT_MSG_EVENT, + STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, msg_it->dscopes.event_payload); + if (status < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot decode event payload field: " + "msg-it-addr=%p, event-class-addr=%p, " + "event-class-name=\"%s\", " + "event-class-id=%" PRId64 ", fc-addr=%p", + msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, + msg_it->meta.ec->id, event_payload_fc); + } + +end: + return status; +} + +static enum ctf_msg_iter_status read_event_payload_continue_state(struct ctf_msg_iter *msg_it) +{ + return read_dscope_continue_state(msg_it, STATE_EMIT_MSG_EVENT); +} + +static enum ctf_msg_iter_status skip_packet_padding_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + size_t bits_to_skip; + const enum state next_state = STATE_SWITCH_PACKET; + + BT_ASSERT(msg_it->cur_exp_packet_total_size > 0); + bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it); + if (bits_to_skip == 0) { + msg_it->state = next_state; + goto end; + } else { + size_t bits_to_consume; + + BT_COMP_LOGD("Trying to skip %zu bits of padding: msg-it-addr=%p, size=%zu", bits_to_skip, + msg_it, bits_to_skip); + status = buf_ensure_available_bits(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + bits_to_consume = MIN(buf_available_bits(msg_it), bits_to_skip); + BT_COMP_LOGD("Skipping %zu bits of padding: msg-it-addr=%p, size=%zu", bits_to_consume, + msg_it, bits_to_consume); + buf_consume_bits(msg_it, bits_to_consume); + bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it); + if (bits_to_skip == 0) { + msg_it->state = next_state; + goto end; + } + } + +end: + return status; +} + +static enum ctf_msg_iter_status check_emit_msg_discarded_events(struct ctf_msg_iter *msg_it) +{ + msg_it->state = STATE_EMIT_MSG_DISCARDED_EVENTS; + + if (!msg_it->meta.sc->has_discarded_events) { + msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; + goto end; + } + + if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) { + if (msg_it->snapshots.discarded_events == 0 || + msg_it->snapshots.discarded_events == UINT64_C(-1)) { + /* + * Stream's first packet with no discarded + * events or no information about discarded + * events: do not emit. + */ + msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; + } + } else { + /* + * If the previous packet has a value for this counter, + * then this counter is defined for the whole stream. + */ + BT_ASSERT(msg_it->snapshots.discarded_events != UINT64_C(-1)); + + if (msg_it->snapshots.discarded_events - msg_it->prev_packet_snapshots.discarded_events == + 0) { + /* + * No discarded events since previous packet: do + * not emit. + */ + msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; + } + } + +end: + return CTF_MSG_ITER_STATUS_OK; +} + +static enum ctf_msg_iter_status check_emit_msg_discarded_packets(struct ctf_msg_iter *msg_it) +{ + msg_it->state = STATE_EMIT_MSG_DISCARDED_PACKETS; + + if (!msg_it->meta.sc->has_discarded_packets) { + msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; + goto end; + } + + if (msg_it->prev_packet_snapshots.packets == UINT64_C(-1)) { + /* + * Stream's first packet or no information about + * discarded packets: do not emit. In other words, if + * this is the first packet and its sequence number is + * not 0, do not consider that packets were previously + * lost: we might be reading a partial stream (LTTng + * snapshot for example). + */ + msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; + } else { + /* + * If the previous packet has a value for this counter, + * then this counter is defined for the whole stream. + */ + BT_ASSERT(msg_it->snapshots.packets != UINT64_C(-1)); + + if (msg_it->snapshots.packets - msg_it->prev_packet_snapshots.packets <= 1) { + /* + * No discarded packets since previous packet: + * do not emit. + */ + msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; + } + } + +end: + return CTF_MSG_ITER_STATUS_OK; +} + +static inline enum state check_emit_msg_stream_end(struct ctf_msg_iter *msg_it) +{ + enum state next_state; + + if (msg_it->emit_stream_end_message) { + next_state = STATE_EMIT_MSG_STREAM_END; + } else { + next_state = STATE_DONE; + } + + return next_state; +} + +static inline enum ctf_msg_iter_status handle_state(struct ctf_msg_iter *msg_it) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + const enum state state = msg_it->state; + + BT_COMP_LOGT("Handling state: msg-it-addr=%p, state=%s", msg_it, state_string(state)); + + // TODO: optimalize! + switch (state) { + case STATE_INIT: + msg_it->state = STATE_SWITCH_PACKET; + break; + case STATE_SWITCH_PACKET: + status = switch_packet_state(msg_it); + break; + case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN: + status = read_packet_header_begin_state(msg_it); + break; + case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE: + status = read_packet_header_continue_state(msg_it); + break; + case STATE_AFTER_TRACE_PACKET_HEADER: + status = after_packet_header_state(msg_it); + break; + case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN: + status = read_packet_context_begin_state(msg_it); + break; + case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE: + status = read_packet_context_continue_state(msg_it); + break; + case STATE_AFTER_STREAM_PACKET_CONTEXT: + status = after_packet_context_state(msg_it); + break; + case STATE_EMIT_MSG_STREAM_BEGINNING: + msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS; + break; + case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS: + status = check_emit_msg_discarded_events(msg_it); + break; + case STATE_EMIT_MSG_DISCARDED_EVENTS: + msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS; + break; + case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS: + status = check_emit_msg_discarded_packets(msg_it); + break; + case STATE_EMIT_MSG_DISCARDED_PACKETS: + msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING; + break; + case STATE_EMIT_MSG_PACKET_BEGINNING: + msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN; + break; + case STATE_DSCOPE_EVENT_HEADER_BEGIN: + status = read_event_header_begin_state(msg_it); + break; + case STATE_DSCOPE_EVENT_HEADER_CONTINUE: + status = read_event_header_continue_state(msg_it); + break; + case STATE_AFTER_EVENT_HEADER: + status = after_event_header_state(msg_it); + break; + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: + status = read_event_common_context_begin_state(msg_it); + break; + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: + status = read_event_common_context_continue_state(msg_it); + break; + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: + status = read_event_spec_context_begin_state(msg_it); + break; + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: + status = read_event_spec_context_continue_state(msg_it); + break; + case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: + status = read_event_payload_begin_state(msg_it); + break; + case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: + status = read_event_payload_continue_state(msg_it); + break; + case STATE_EMIT_MSG_EVENT: + msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN; + break; + case STATE_EMIT_QUEUED_MSG_EVENT: + msg_it->state = STATE_EMIT_MSG_EVENT; + break; + case STATE_SKIP_PACKET_PADDING: + status = skip_packet_padding_state(msg_it); + break; + case STATE_EMIT_MSG_PACKET_END_MULTI: + msg_it->state = STATE_SKIP_PACKET_PADDING; + break; + case STATE_EMIT_MSG_PACKET_END_SINGLE: + msg_it->state = STATE_EMIT_MSG_STREAM_END; + break; + case STATE_EMIT_QUEUED_MSG_PACKET_END: + msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE; + break; + case STATE_CHECK_EMIT_MSG_STREAM_END: + msg_it->state = check_emit_msg_stream_end(msg_it); + break; + case STATE_EMIT_MSG_STREAM_END: + msg_it->state = STATE_DONE; + break; + case STATE_DONE: + break; + default: + BT_COMP_LOGF("Unknown CTF plugin message iterator state: " + "msg-it-addr=%p, state=%d", + msg_it, msg_it->state); + bt_common_abort(); + } + + BT_COMP_LOGT("Handled state: msg-it-addr=%p, status=%s, " + "prev-state=%s, cur-state=%s", + msg_it, ctf_msg_iter_status_string(status), state_string(state), + state_string(msg_it->state)); + return status; +} + +void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it) +{ + BT_ASSERT(msg_it); + BT_COMP_LOGD("Resetting message iterator: addr=%p", msg_it); + stack_clear(msg_it->stack); + msg_it->meta.sc = NULL; + msg_it->meta.ec = NULL; + BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); + BT_STREAM_PUT_REF_AND_RESET(msg_it->stream); + BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg); + release_all_dscopes(msg_it); + msg_it->cur_dscope_field = NULL; + + msg_it->buf.addr = NULL; + msg_it->buf.sz = 0; + msg_it->buf.at = 0; + msg_it->buf.last_eh_at = SIZE_MAX; + msg_it->buf.packet_offset = 0; + msg_it->state = STATE_INIT; + msg_it->cur_exp_packet_content_size = -1; + msg_it->cur_exp_packet_total_size = -1; + msg_it->cur_packet_offset = -1; + msg_it->cur_event_class_id = -1; + msg_it->snapshots.beginning_clock = UINT64_C(-1); + msg_it->snapshots.end_clock = UINT64_C(-1); +} + +/** + * Resets the internal state of a CTF message iterator. + */ +void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it) +{ + ctf_msg_iter_reset_for_next_stream_file(msg_it); + msg_it->cur_stream_class_id = -1; + msg_it->cur_data_stream_id = -1; + msg_it->snapshots.discarded_events = UINT64_C(-1); + msg_it->snapshots.packets = UINT64_C(-1); + msg_it->prev_packet_snapshots.discarded_events = UINT64_C(-1); + msg_it->prev_packet_snapshots.packets = UINT64_C(-1); + msg_it->prev_packet_snapshots.beginning_clock = UINT64_C(-1); + msg_it->prev_packet_snapshots.end_clock = UINT64_C(-1); + msg_it->emit_stream_beginning_message = true; + msg_it->emit_stream_end_message = false; +} + +static bt_field *borrow_next_field(struct ctf_msg_iter *msg_it) +{ + bt_field *next_field = NULL; + bt_field *base_field; + const bt_field_class *base_fc; + bt_field_class_type base_fc_type; + size_t index; + + BT_ASSERT_DBG(!stack_empty(msg_it->stack)); + index = stack_top(msg_it->stack)->index; + base_field = stack_top(msg_it->stack)->base; + BT_ASSERT_DBG(base_field); + base_fc = bt_field_borrow_class_const(base_field); + BT_ASSERT_DBG(base_fc); + base_fc_type = bt_field_class_get_type(base_fc); + + if (base_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) { + BT_ASSERT_DBG(index < bt_field_class_structure_get_member_count( + bt_field_borrow_class_const(base_field))); + next_field = bt_field_structure_borrow_member_field_by_index(base_field, index); + } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) { + BT_ASSERT_DBG(index < bt_field_array_get_length(base_field)); + next_field = bt_field_array_borrow_element_field_by_index(base_field, index); + } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_VARIANT)) { + BT_ASSERT_DBG(index == 0); + next_field = bt_field_variant_borrow_selected_option_field(base_field); + } else { + bt_common_abort(); + } + + BT_ASSERT_DBG(next_field); + return next_field; +} + +static void update_default_clock(struct ctf_msg_iter *msg_it, uint64_t new_val, + uint64_t new_val_size) +{ + uint64_t new_val_mask; + uint64_t cur_value_masked; + + BT_ASSERT_DBG(new_val_size > 0); + + /* + * Special case for a 64-bit new value, which is the limit + * of a clock value as of this version: overwrite the + * current value directly. + */ + if (new_val_size == 64) { + msg_it->default_clock_snapshot = new_val; + goto end; + } + + new_val_mask = (1ULL << new_val_size) - 1; + cur_value_masked = msg_it->default_clock_snapshot & new_val_mask; + + if (new_val < cur_value_masked) { + /* + * It looks like a wrap happened on the number of bits + * of the requested new value. Assume that the clock + * value wrapped only one time. + */ + msg_it->default_clock_snapshot += new_val_mask + 1; + } + + /* Clear the low bits of the current clock value. */ + msg_it->default_clock_snapshot &= ~new_val_mask; + + /* Set the low bits of the current clock value. */ + msg_it->default_clock_snapshot |= new_val; + +end: + BT_COMP_LOGT("Updated default clock's value from integer field's value: " + "value=%" PRIu64, + msg_it->default_clock_snapshot); +} + +/* + * Ensure the message iterator's `stored_values` array is large enough to + * accommodate `storing_index`. + * + * We may need more slots in the array than initially allocated if more + * metadata arrives along the way. + */ +static void ensure_stored_values_size(ctf_msg_iter *msg_it, uint64_t storing_index) +{ + if (G_UNLIKELY(storing_index >= msg_it->stored_values->len)) { + g_array_set_size(msg_it->stored_values, msg_it->meta.tc->stored_value_count); + } +} + +static enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value, struct ctf_field_class *fc, + void *data) +{ + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + bt_self_component *self_comp = msg_it->self_comp; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + + bt_field *field = NULL; + + BT_COMP_LOGT("Unsigned integer function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d, value=%" PRIu64, + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); + + ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + + if (G_LIKELY(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE)) { + goto update_def_clock; + } + + switch (int_fc->meaning) { + case CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID: + msg_it->cur_event_class_id = value; + break; + case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID: + msg_it->cur_data_stream_id = value; + break; + case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME: + msg_it->snapshots.beginning_clock = value; + break; + case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME: + msg_it->snapshots.end_clock = value; + break; + case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID: + msg_it->cur_stream_class_id = value; + break; + case CTF_FIELD_CLASS_MEANING_MAGIC: + if (value != 0xc1fc1fc1) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Invalid CTF magic number: msg-it-addr=%p, " + "magic=%" PRIx64, + msg_it, value); + status = BT_BFCR_STATUS_ERROR; + goto end; + } + + break; + case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT: + msg_it->snapshots.packets = value; + break; + case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT: + msg_it->snapshots.discarded_events = value; + break; + case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE: + msg_it->cur_exp_packet_total_size = value; + break; + case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE: + msg_it->cur_exp_packet_content_size = value; + break; + default: + bt_common_abort(); + } + +update_def_clock: + if (G_UNLIKELY(int_fc->mapped_clock_class)) { + update_default_clock(msg_it, value, int_fc->base.size); + } + + if (G_UNLIKELY(int_fc->storing_index >= 0)) { + ensure_stored_values_size(msg_it, int_fc->storing_index); + bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = value; + } + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + field = borrow_next_field(msg_it); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(field), + BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)); + bt_field_integer_unsigned_set_value(field, value); + stack_top(msg_it->stack)->index++; + +end: + return status; +} + +static enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value, struct ctf_field_class *fc, + void *data) +{ + int ret; + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + bt_self_component *self_comp = msg_it->self_comp; + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + bt_field *string_field = NULL; + char str[2] = {'\0', '\0'}; + + BT_COMP_LOGT("Unsigned integer character function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d, value=%" PRIu64, + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); + + ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); + BT_ASSERT_DBG(!int_fc->mapped_clock_class); + BT_ASSERT_DBG(int_fc->storing_index < 0); + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + if (msg_it->done_filling_string) { + goto end; + } + + if (value == 0) { + msg_it->done_filling_string = true; + goto end; + } + + string_field = stack_top(msg_it->stack)->base; + BT_ASSERT_DBG(bt_field_get_class_type(string_field) == BT_FIELD_CLASS_TYPE_STRING); + + /* Append character */ + str[0] = (char) value; + ret = bt_field_string_append_with_length(string_field, str, 1); + if (ret) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot append character to string field's value: " + "msg-it-addr=%p, field-addr=%p, ret=%d", + msg_it, string_field, ret); + status = BT_BFCR_STATUS_ERROR; + goto end; + } + +end: + return status; +} + +static enum bt_bfcr_status bfcr_signed_int_cb(int64_t value, struct ctf_field_class *fc, void *data) +{ + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + bt_field *field = NULL; + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + + BT_COMP_LOGT("Signed integer function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d, value=%" PRId64, + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); + + ctf_field_class_int *int_fc = ctf_field_class_as_int(fc); + BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE); + + if (G_UNLIKELY(int_fc->storing_index >= 0)) { + ensure_stored_values_size(msg_it, int_fc->storing_index); + bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = + (uint64_t) value; + } + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + field = borrow_next_field(msg_it); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG( + bt_field_class_type_is(bt_field_get_class_type(field), BT_FIELD_CLASS_TYPE_SIGNED_INTEGER)); + bt_field_integer_signed_set_value(field, value); + stack_top(msg_it->stack)->index++; + +end: + return status; +} + +static enum bt_bfcr_status bfcr_floating_point_cb(double value, struct ctf_field_class *fc, + void *data) +{ + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + bt_field *field = NULL; + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + bt_field_class_type type; + + BT_COMP_LOGT("Floating point number function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d, value=%f", + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value); + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + field = borrow_next_field(msg_it); + type = bt_field_get_class_type(field); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_REAL)); + + if (type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) { + bt_field_real_single_precision_set_value(field, (float) value); + } else { + bt_field_real_double_precision_set_value(field, value); + } + stack_top(msg_it->stack)->index++; + +end: + return status; +} + +static enum bt_bfcr_status bfcr_string_begin_cb(struct ctf_field_class *fc, void *data) +{ + bt_field *field = NULL; + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + + BT_COMP_LOGT("String (beginning) function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + field = borrow_next_field(msg_it); + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING); + bt_field_string_clear(field); + + /* + * Push on stack. Not a compound class per se, but we know that + * only bfcr_string_cb() may be called between this call and a + * subsequent call to bfcr_string_end_cb(). + */ + stack_push(msg_it->stack, field); + +end: + return BT_BFCR_STATUS_OK; +} + +static enum bt_bfcr_status bfcr_string_cb(const char *value, size_t len, struct ctf_field_class *fc, + void *data) +{ + enum bt_bfcr_status status = BT_BFCR_STATUS_OK; + bt_field *field = NULL; + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + bt_self_component *self_comp = msg_it->self_comp; + int ret; + + BT_COMP_LOGT("String (substring) function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d, string-length=%zu", + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, len); + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + field = stack_top(msg_it->stack)->base; + BT_ASSERT_DBG(field); + + /* Append current substring */ + ret = bt_field_string_append_with_length(field, value, len); + if (ret) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot append substring to string field's value: " + "msg-it-addr=%p, field-addr=%p, string-length=%zu, " + "ret=%d", + msg_it, field, len, ret); + status = BT_BFCR_STATUS_ERROR; + goto end; + } + +end: + return status; +} + +static enum bt_bfcr_status bfcr_string_end_cb(struct ctf_field_class *fc, void *data) +{ + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + + BT_COMP_LOGT("String (end) function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + /* Pop string field */ + stack_pop(msg_it->stack); + + /* Go to next field */ + stack_top(msg_it->stack)->index++; + +end: + return BT_BFCR_STATUS_OK; +} + +static enum bt_bfcr_status bfcr_compound_begin_cb(struct ctf_field_class *fc, void *data) +{ + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + bt_field *field; + + BT_COMP_LOGT("Compound (beginning) function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + /* Borrow field */ + if (stack_empty(msg_it->stack)) { + /* Root: already set by read_dscope_begin_state() */ + field = msg_it->cur_dscope_field; + } else { + field = borrow_next_field(msg_it); + BT_ASSERT_DBG(field); + } + + /* Push field */ + BT_ASSERT_DBG(field); + BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc); + stack_push(msg_it->stack, field); + + /* + * Change BFCR "unsigned int" callback if it's a text + * array/sequence. + */ + if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { + ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + if (array_fc->is_text) { + BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING); + msg_it->done_filling_string = false; + bt_field_string_clear(field); + bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_char_cb); + } + } + +end: + return BT_BFCR_STATUS_OK; +} + +static enum bt_bfcr_status bfcr_compound_end_cb(struct ctf_field_class *fc, void *data) +{ + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + + BT_COMP_LOGT("Compound (end) function called from BFCR: " + "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, " + "fc-type=%d, fc-in-ir=%d", + msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir); + + if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) { + goto end; + } + + BT_ASSERT_DBG(!stack_empty(msg_it->stack)); + BT_ASSERT_DBG(bt_field_borrow_class_const(stack_top(msg_it->stack)->base) == fc->ir_fc); + + /* + * Reset BFCR "unsigned int" callback if it's a text + * array/sequence. + */ + if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { + ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc); + + if (array_fc->is_text) { + BT_ASSERT_DBG(bt_field_get_class_type(stack_top(msg_it->stack)->base) == + BT_FIELD_CLASS_TYPE_STRING); + bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_cb); + } + } + + /* Pop stack */ + stack_pop(msg_it->stack); + + /* If the stack is not empty, increment the base's index */ + if (!stack_empty(msg_it->stack)) { + stack_top(msg_it->stack)->index++; + } + +end: + return BT_BFCR_STATUS_OK; +} + +static int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data) +{ + bt_field *seq_field; + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc); + int64_t length; + int ret; + + length = + (uint64_t) bt_g_array_index(msg_it->stored_values, uint64_t, seq_fc->stored_length_index); + + if (G_UNLIKELY(msg_it->dry_run)) { + goto end; + } + + seq_field = stack_top(msg_it->stack)->base; + BT_ASSERT_DBG(seq_field); + + /* + * bfcr_get_sequence_length_cb() also gets called back for a + * text sequence, but the destination field is a string field. + * Only set the field's sequence length if the destination field + * is a sequence field. + */ + if (!seq_fc->base.is_text) { + BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(seq_field), + BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)); + ret = bt_field_array_dynamic_set_length(seq_field, (uint64_t) length); + if (ret) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot set dynamic array field's length field: " + "msg-it-addr=%p, field-addr=%p, " + "length=%" PRIu64, + msg_it, seq_field, length); + length = -1; + } + } + +end: + return length; +} + +static struct ctf_field_class * +bfcr_borrow_variant_selected_field_class_cb(struct ctf_field_class *fc, void *data) +{ + int ret; + uint64_t i; + int64_t option_index = -1; + ctf_msg_iter *msg_it = (ctf_msg_iter *) data; + ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc); + struct ctf_named_field_class *selected_option = NULL; + bt_self_component *self_comp = msg_it->self_comp; + struct ctf_field_class *ret_fc = NULL; + union + { + uint64_t u; + int64_t i; + } tag; + + /* Get variant's tag */ + tag.u = bt_g_array_index(msg_it->stored_values, uint64_t, var_fc->stored_tag_index); + + /* + * Check each range to find the selected option's index. + */ + if (var_fc->tag_fc->base.is_signed) { + for (i = 0; i < var_fc->ranges->len; i++) { + struct ctf_field_class_variant_range *range = + ctf_field_class_variant_borrow_range_by_index(var_fc, i); + + if (tag.i >= range->range.lower.i && tag.i <= range->range.upper.i) { + option_index = (int64_t) range->option_index; + break; + } + } + } else { + for (i = 0; i < var_fc->ranges->len; i++) { + struct ctf_field_class_variant_range *range = + ctf_field_class_variant_borrow_range_by_index(var_fc, i); + + if (tag.u >= range->range.lower.u && tag.u <= range->range.upper.u) { + option_index = (int64_t) range->option_index; + break; + } + } + } + + if (option_index < 0) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot find variant field class's option: " + "msg-it-addr=%p, var-fc-addr=%p, u-tag=%" PRIu64 ", " + "i-tag=%" PRId64, + msg_it, var_fc, tag.u, tag.i); + ret_fc = NULL; + goto end; + } + + selected_option = + ctf_field_class_variant_borrow_option_by_index(var_fc, (uint64_t) option_index); + + if (selected_option->fc->in_ir && !msg_it->dry_run) { + bt_field *var_field = stack_top(msg_it->stack)->base; + + ret = bt_field_variant_select_option_by_index(var_field, option_index); + if (ret) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot select variant field's option field: " + "msg-it-addr=%p, var-field-addr=%p, " + "opt-index=%" PRId64, + msg_it, var_field, option_index); + ret_fc = NULL; + goto end; + } + } + + ret_fc = selected_option->fc; + +end: + return ret_fc; +} + +static bt_message *create_msg_stream_beginning(struct ctf_msg_iter *msg_it) +{ + bt_self_component *self_comp = msg_it->self_comp; + bt_message *msg; + + BT_ASSERT(msg_it->stream); + BT_ASSERT(msg_it->self_msg_iter); + msg = bt_message_stream_beginning_create(msg_it->self_msg_iter, msg_it->stream); + if (!msg) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create stream beginning message: " + "msg-it-addr=%p, stream-addr=%p", + msg_it, msg_it->stream); + } + + return msg; +} + +static bt_message *create_msg_stream_end(struct ctf_msg_iter *msg_it) +{ + bt_self_component *self_comp = msg_it->self_comp; + bt_message *msg; + + if (!msg_it->stream) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create stream end message because stream is NULL: " + "msg-it-addr=%p", + msg_it); + msg = NULL; + goto end; + } + + BT_ASSERT(msg_it->self_msg_iter); + msg = bt_message_stream_end_create(msg_it->self_msg_iter, msg_it->stream); + if (!msg) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create stream end message: " + "msg-it-addr=%p, stream-addr=%p", + msg_it, msg_it->stream); + } + +end: + return msg; +} + +static bt_message *create_msg_packet_beginning(struct ctf_msg_iter *msg_it, bool use_default_cs) +{ + bt_self_component *self_comp = msg_it->self_comp; + bt_message *msg; + const bt_stream_class *sc = msg_it->meta.sc->ir_sc; + + BT_ASSERT(msg_it->packet); + BT_ASSERT(sc); + BT_ASSERT(msg_it->self_msg_iter); + + if (msg_it->meta.sc->packets_have_ts_begin) { + BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1)); + uint64_t raw_cs_value; + + /* + * Either use the decoded packet `timestamp_begin` field or the + * current stream's default clock_snapshot. + */ + if (use_default_cs) { + raw_cs_value = msg_it->default_clock_snapshot; + } else { + raw_cs_value = msg_it->snapshots.beginning_clock; + } + + msg = bt_message_packet_beginning_create_with_default_clock_snapshot( + msg_it->self_msg_iter, msg_it->packet, raw_cs_value); + } else { + msg = bt_message_packet_beginning_create(msg_it->self_msg_iter, msg_it->packet); + } + + if (!msg) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create packet beginning message: " + "msg-it-addr=%p, packet-addr=%p", + msg_it, msg_it->packet); + goto end; + } + +end: + return msg; +} + +static bt_message *emit_delayed_packet_beg_msg(struct ctf_msg_iter *msg_it) +{ + bool packet_beg_ts_need_fix_up; + + msg_it->emit_delayed_packet_beginning_msg = false; + + /* + * Only fix the packet's timestamp_begin if it's larger than the first + * event of the packet. If there was no event in the packet, the + * `default_clock_snapshot` field will be either equal or greater than + * `snapshots.beginning_clock` so there is not fix needed. + */ + packet_beg_ts_need_fix_up = msg_it->default_clock_snapshot < msg_it->snapshots.beginning_clock; + + /* create_msg_packet_beginning() logs errors */ + return create_msg_packet_beginning(msg_it, packet_beg_ts_need_fix_up); +} + +static bt_message *create_msg_packet_end(struct ctf_msg_iter *msg_it) +{ + bt_message *msg; + bool update_default_cs = true; + bt_self_component *self_comp = msg_it->self_comp; + + if (!msg_it->packet) { + msg = NULL; + goto end; + } + + /* + * Check if we need to emit the delayed packet + * beginning message instead of the packet end message. + */ + if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) { + msg = emit_delayed_packet_beg_msg(msg_it); + /* Don't forget to emit the packet end message. */ + msg_it->state = STATE_EMIT_QUEUED_MSG_PACKET_END; + goto end; + } + + /* Check if may be affected by lttng-crash timestamp_end quirk. */ + if (G_UNLIKELY(msg_it->meta.tc->quirks.lttng_crash)) { + /* + * Check if the `timestamp_begin` field is non-zero but + * `timestamp_end` is zero. It means the trace is affected by + * the lttng-crash packet `timestamp_end` quirk and must be + * fixed up by omitting to update the default clock snapshot to + * the `timestamp_end` as is typically done. + */ + if (msg_it->snapshots.beginning_clock != 0 && msg_it->snapshots.end_clock == 0) { + update_default_cs = false; + } + } + + /* + * Check if may be affected by lttng event-after-packet `timestamp_end` + * quirk. + */ + if (msg_it->meta.tc->quirks.lttng_event_after_packet) { + /* + * Check if `timestamp_end` is smaller then the current + * default_clock_snapshot (which is set to the last event + * decoded). It means the trace is affected by the lttng + * `event-after-packet` packet `timestamp_end` quirk and must + * be fixed up by omitting to update the default clock snapshot + * to the `timestamp_end` as is typically done. + */ + if (msg_it->snapshots.end_clock < msg_it->default_clock_snapshot) { + update_default_cs = false; + } + } + + /* Update default clock from packet's end time. */ + if (msg_it->snapshots.end_clock != UINT64_C(-1) && update_default_cs) { + msg_it->default_clock_snapshot = msg_it->snapshots.end_clock; + } + + BT_ASSERT(msg_it->self_msg_iter); + + if (msg_it->meta.sc->packets_have_ts_end) { + BT_ASSERT(msg_it->snapshots.end_clock != UINT64_C(-1)); + msg = bt_message_packet_end_create_with_default_clock_snapshot( + msg_it->self_msg_iter, msg_it->packet, msg_it->default_clock_snapshot); + } else { + msg = bt_message_packet_end_create(msg_it->self_msg_iter, msg_it->packet); + } + + if (!msg) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create packet end message: " + "msg-it-addr=%p, packet-addr=%p", + msg_it, msg_it->packet); + goto end; + } + + BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); + +end: + return msg; +} + +static bt_message *create_msg_discarded_events(struct ctf_msg_iter *msg_it) +{ + bt_message *msg; + bt_self_component *self_comp = msg_it->self_comp; + uint64_t beginning_raw_value = UINT64_C(-1); + uint64_t end_raw_value = UINT64_C(-1); + + BT_ASSERT(msg_it->self_msg_iter); + BT_ASSERT(msg_it->stream); + BT_ASSERT(msg_it->meta.sc->has_discarded_events); + + if (msg_it->meta.sc->discarded_events_have_default_cs) { + if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) { + /* + * We discarded events, but before (and possibly + * including) the current packet: use this packet's time + * range, and do not have a specific count. + */ + beginning_raw_value = msg_it->snapshots.beginning_clock; + end_raw_value = msg_it->snapshots.end_clock; + } else { + beginning_raw_value = msg_it->prev_packet_snapshots.end_clock; + end_raw_value = msg_it->snapshots.end_clock; + } + + BT_ASSERT(beginning_raw_value != UINT64_C(-1)); + BT_ASSERT(end_raw_value != UINT64_C(-1)); + msg = bt_message_discarded_events_create_with_default_clock_snapshots( + msg_it->self_msg_iter, msg_it->stream, beginning_raw_value, end_raw_value); + } else { + msg = bt_message_discarded_events_create(msg_it->self_msg_iter, msg_it->stream); + } + + if (!msg) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create discarded events message: " + "msg-it-addr=%p, stream-addr=%p", + msg_it, msg_it->stream); + goto end; + } + + if (msg_it->prev_packet_snapshots.discarded_events != UINT64_C(-1)) { + bt_message_discarded_events_set_count(msg, + msg_it->snapshots.discarded_events - + msg_it->prev_packet_snapshots.discarded_events); + } + +end: + return msg; +} + +static bt_message *create_msg_discarded_packets(struct ctf_msg_iter *msg_it) +{ + bt_message *msg; + bt_self_component *self_comp = msg_it->self_comp; + + BT_ASSERT(msg_it->self_msg_iter); + BT_ASSERT(msg_it->stream); + BT_ASSERT(msg_it->meta.sc->has_discarded_packets); + BT_ASSERT(msg_it->prev_packet_snapshots.packets != UINT64_C(-1)); + + if (msg_it->meta.sc->discarded_packets_have_default_cs) { + BT_ASSERT(msg_it->prev_packet_snapshots.end_clock != UINT64_C(-1)); + BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1)); + msg = bt_message_discarded_packets_create_with_default_clock_snapshots( + msg_it->self_msg_iter, msg_it->stream, msg_it->prev_packet_snapshots.end_clock, + msg_it->snapshots.beginning_clock); + } else { + msg = bt_message_discarded_packets_create(msg_it->self_msg_iter, msg_it->stream); + } + + if (!msg) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, + "Cannot create discarded packets message: " + "msg-it-addr=%p, stream-addr=%p", + msg_it, msg_it->stream); + goto end; + } + + bt_message_discarded_packets_set_count(msg, msg_it->snapshots.packets - + msg_it->prev_packet_snapshots.packets - 1); + +end: + return msg; +} + +struct ctf_msg_iter *ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz, + struct ctf_msg_iter_medium_ops medops, void *data, + bt_logging_level log_level, bt_self_component *self_comp, + bt_self_message_iterator *self_msg_iter) +{ + struct ctf_msg_iter *msg_it = NULL; + struct bt_bfcr_cbs cbs = { + .classes = + { + .signed_int = bfcr_signed_int_cb, + .unsigned_int = bfcr_unsigned_int_cb, + .floating_point = bfcr_floating_point_cb, + .string_begin = bfcr_string_begin_cb, + .string = bfcr_string_cb, + .string_end = bfcr_string_end_cb, + .compound_begin = bfcr_compound_begin_cb, + .compound_end = bfcr_compound_end_cb, + }, + .query = + { + .get_sequence_length = bfcr_get_sequence_length_cb, + .borrow_variant_selected_field_class = bfcr_borrow_variant_selected_field_class_cb, + }, + }; + + BT_ASSERT(tc); + BT_ASSERT(medops.request_bytes); + BT_ASSERT(medops.borrow_stream); + BT_ASSERT(max_request_sz > 0); + + BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp, + "Creating CTF plugin message iterator: " + "trace-addr=%p, max-request-size=%zu, " + "data=%p, log-level=%s", + tc, max_request_sz, data, bt_common_logging_level_string(log_level)); + msg_it = g_new0(struct ctf_msg_iter, 1); + if (!msg_it) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, + "Failed to allocate one CTF plugin message iterator."); + goto end; + } + msg_it->self_comp = self_comp; + msg_it->self_msg_iter = self_msg_iter; + msg_it->log_level = log_level; + msg_it->meta.tc = tc; + msg_it->medium.medops = medops; + msg_it->medium.max_request_sz = max_request_sz; + msg_it->medium.data = data; + msg_it->stack = stack_new(msg_it); + msg_it->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t)); + g_array_set_size(msg_it->stored_values, tc->stored_value_count); + + if (!msg_it->stack) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create field stack."); + goto error; + } + + msg_it->bfcr = bt_bfcr_create(cbs, msg_it, log_level, NULL); + if (!msg_it->bfcr) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create binary class reader (BFCR)."); + goto error; + } + + ctf_msg_iter_reset(msg_it); + BT_COMP_LOGD("Created CTF plugin message iterator: " + "trace-addr=%p, max-request-size=%zu, " + "data=%p, msg-it-addr=%p, log-level=%s", + tc, max_request_sz, data, msg_it, bt_common_logging_level_string(log_level)); + msg_it->cur_packet_offset = 0; + +end: + return msg_it; + +error: + ctf_msg_iter_destroy(msg_it); + msg_it = NULL; + goto end; +} + +void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_it) +{ + BT_PACKET_PUT_REF_AND_RESET(msg_it->packet); + BT_STREAM_PUT_REF_AND_RESET(msg_it->stream); + release_all_dscopes(msg_it); + + BT_COMP_LOGD("Destroying CTF plugin message iterator: addr=%p", msg_it); + + if (msg_it->stack) { + BT_COMP_LOGD_STR("Destroying field stack."); + stack_destroy(msg_it->stack); + } + + if (msg_it->bfcr) { + BT_COMP_LOGD("Destroying BFCR: bfcr-addr=%p", msg_it->bfcr); + bt_bfcr_destroy(msg_it->bfcr); + } + + if (msg_it->stored_values) { + g_array_free(msg_it->stored_values, TRUE); + } + + g_free(msg_it); +} + +enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it, + const bt_message **message) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + + BT_ASSERT_DBG(msg_it); + BT_ASSERT_DBG(message); + BT_COMP_LOGD("Getting next message: msg-it-addr=%p", msg_it); + + while (true) { + status = handle_state(msg_it); + if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) { + BT_COMP_LOGD_STR("Medium returned CTF_MSG_ITER_STATUS_AGAIN."); + goto end; + } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot handle state: msg-it-addr=%p, state=%s", + msg_it, state_string(msg_it->state)); + goto end; + } + + switch (msg_it->state) { + case STATE_EMIT_MSG_EVENT: + BT_ASSERT_DBG(msg_it->event_msg); + + /* + * Check if we need to emit the delayed packet + * beginning message instead of the event message. + */ + if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) { + *message = emit_delayed_packet_beg_msg(msg_it); + if (!*message) { + status = CTF_MSG_ITER_STATUS_ERROR; + } + + /* + * Don't forget to emit the event message of + * the event record that was just decoded. + */ + msg_it->state = STATE_EMIT_QUEUED_MSG_EVENT; + + } else { + *message = msg_it->event_msg; + msg_it->event_msg = NULL; + } + goto end; + case STATE_EMIT_MSG_DISCARDED_EVENTS: + /* create_msg_discarded_events() logs errors */ + *message = create_msg_discarded_events(msg_it); + + if (!*message) { + status = CTF_MSG_ITER_STATUS_ERROR; + } + + goto end; + case STATE_EMIT_MSG_DISCARDED_PACKETS: + /* create_msg_discarded_packets() logs errors */ + *message = create_msg_discarded_packets(msg_it); + + if (!*message) { + status = CTF_MSG_ITER_STATUS_ERROR; + } + + goto end; + case STATE_EMIT_MSG_PACKET_BEGINNING: + if (G_UNLIKELY(msg_it->meta.tc->quirks.barectf_event_before_packet)) { + msg_it->emit_delayed_packet_beginning_msg = true; + /* + * There is no message to return yet as this + * packet beginning message is delayed until we + * decode the first event message of the + * packet. + */ + break; + } else { + /* create_msg_packet_beginning() logs errors */ + *message = create_msg_packet_beginning(msg_it, false); + if (!*message) { + status = CTF_MSG_ITER_STATUS_ERROR; + } + } + + goto end; + case STATE_EMIT_MSG_PACKET_END_SINGLE: + case STATE_EMIT_MSG_PACKET_END_MULTI: + /* create_msg_packet_end() logs errors */ + *message = create_msg_packet_end(msg_it); + + if (!*message) { + status = CTF_MSG_ITER_STATUS_ERROR; + } + + goto end; + case STATE_EMIT_MSG_STREAM_BEGINNING: + /* create_msg_stream_beginning() logs errors */ + *message = create_msg_stream_beginning(msg_it); + msg_it->emit_stream_beginning_message = false; + msg_it->emit_stream_end_message = true; + + if (!*message) { + status = CTF_MSG_ITER_STATUS_ERROR; + } + + goto end; + case STATE_EMIT_MSG_STREAM_END: + /* create_msg_stream_end() logs errors */ + *message = create_msg_stream_end(msg_it); + msg_it->emit_stream_end_message = false; + + if (!*message) { + status = CTF_MSG_ITER_STATUS_ERROR; + } + + goto end; + case STATE_DONE: + status = CTF_MSG_ITER_STATUS_EOF; + goto end; + default: + /* Non-emitting state: continue */ + break; + } + } + +end: + return status; +} + +static enum ctf_msg_iter_status decode_until_state(struct ctf_msg_iter *msg_it, + enum state target_state_1, + enum state target_state_2) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + bt_self_component *self_comp = msg_it->self_comp; + + BT_ASSERT_DBG(msg_it); + + do { + /* + * Check if we reached the state at which we want to stop + * decoding. + */ + if (msg_it->state == target_state_1 || msg_it->state == target_state_2) { + goto end; + } + + status = handle_state(msg_it); + if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) { + BT_COMP_LOGD_STR("Medium returned CTF_MSG_ITER_STATUS_AGAIN."); + goto end; + } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) { + BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot handle state: msg-it-addr=%p, state=%s", + msg_it, state_string(msg_it->state)); + goto end; + } + + switch (msg_it->state) { + case STATE_INIT: + case STATE_SWITCH_PACKET: + case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN: + case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE: + case STATE_AFTER_TRACE_PACKET_HEADER: + case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN: + case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE: + case STATE_AFTER_STREAM_PACKET_CONTEXT: + case STATE_EMIT_MSG_STREAM_BEGINNING: + case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS: + case STATE_EMIT_MSG_DISCARDED_EVENTS: + case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS: + case STATE_EMIT_MSG_DISCARDED_PACKETS: + case STATE_EMIT_MSG_PACKET_BEGINNING: + case STATE_DSCOPE_EVENT_HEADER_BEGIN: + case STATE_DSCOPE_EVENT_HEADER_CONTINUE: + case STATE_AFTER_EVENT_HEADER: + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN: + case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE: + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN: + case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE: + case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN: + case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE: + case STATE_EMIT_MSG_EVENT: + case STATE_EMIT_QUEUED_MSG_EVENT: + case STATE_SKIP_PACKET_PADDING: + case STATE_EMIT_MSG_PACKET_END_MULTI: + case STATE_EMIT_MSG_PACKET_END_SINGLE: + case STATE_EMIT_QUEUED_MSG_PACKET_END: + case STATE_EMIT_MSG_STREAM_END: + break; + case STATE_DONE: + /* fall-through */ + default: + /* We should never get to the STATE_DONE state. */ + BT_COMP_LOGF("Unexpected state: msg-it-addr=%p, state=%s", msg_it, + state_string(msg_it->state)); + bt_common_abort(); + } + } while (true); + +end: + return status; +} + +static enum ctf_msg_iter_status read_packet_header_context_fields(struct ctf_msg_iter *msg_it) +{ + int ret; + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + + status = decode_until_state(msg_it, STATE_EMIT_MSG_PACKET_BEGINNING, (state) -1); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + ret = set_current_packet_content_sizes(msg_it); + if (ret) { + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + +end: + return status; +} + +enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, off_t offset) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + enum ctf_msg_iter_medium_status medium_status; + + BT_ASSERT(msg_it); + BT_ASSERT(offset >= 0); + BT_ASSERT(msg_it->medium.medops.seek); + + medium_status = msg_it->medium.medops.seek(offset, msg_it->medium.data); + if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) { + if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) { + status = CTF_MSG_ITER_STATUS_EOF; + } else { + status = CTF_MSG_ITER_STATUS_ERROR; + goto end; + } + } + + ctf_msg_iter_reset(msg_it); + msg_it->cur_packet_offset = offset; + +end: + return status; +} + +static enum ctf_msg_iter_status clock_snapshot_at_msg_iter_state(struct ctf_msg_iter *msg_it, + enum state target_state_1, + enum state target_state_2, + uint64_t *clock_snapshot) +{ + enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK; + + BT_ASSERT_DBG(msg_it); + BT_ASSERT_DBG(clock_snapshot); + status = decode_until_state(msg_it, target_state_1, target_state_2); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + *clock_snapshot = msg_it->default_clock_snapshot; +end: + return status; +} + +enum ctf_msg_iter_status +ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it, + uint64_t *first_clock_snapshot) +{ + return clock_snapshot_at_msg_iter_state(msg_it, STATE_AFTER_EVENT_HEADER, (state) -1, + first_clock_snapshot); +} + +enum ctf_msg_iter_status +ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it, + uint64_t *last_clock_snapshot) +{ + return clock_snapshot_at_msg_iter_state(msg_it, STATE_EMIT_MSG_PACKET_END_SINGLE, + STATE_EMIT_MSG_PACKET_END_MULTI, last_clock_snapshot); +} + +enum ctf_msg_iter_status +ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it, + struct ctf_msg_iter_packet_properties *props) +{ + enum ctf_msg_iter_status status; + + BT_ASSERT_DBG(msg_it); + BT_ASSERT_DBG(props); + status = read_packet_header_context_fields(msg_it); + if (status != CTF_MSG_ITER_STATUS_OK) { + goto end; + } + + props->exp_packet_total_size = msg_it->cur_exp_packet_total_size; + props->exp_packet_content_size = msg_it->cur_exp_packet_content_size; + props->stream_class_id = (uint64_t) msg_it->cur_stream_class_id; + props->data_stream_id = msg_it->cur_data_stream_id; + props->snapshots.discarded_events = msg_it->snapshots.discarded_events; + props->snapshots.packets = msg_it->snapshots.packets; + props->snapshots.beginning_clock = msg_it->snapshots.beginning_clock; + props->snapshots.end_clock = msg_it->snapshots.end_clock; + +end: + return status; +} + +void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val) +{ + msg_it->dry_run = val; +} diff --git a/src/plugins/ctf/common/src/msg-iter/msg-iter.hpp b/src/plugins/ctf/common/src/msg-iter/msg-iter.hpp new file mode 100644 index 00000000..dea4615d --- /dev/null +++ b/src/plugins/ctf/common/src/msg-iter/msg-iter.hpp @@ -0,0 +1,341 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2016 Philippe Proulx + * + * Babeltrace - CTF message iterator + */ + +#ifndef CTF_MSG_ITER_H +#define CTF_MSG_ITER_H + +#include +#include +#include + +#include + +#include "../metadata/tsdl/ctf-meta.hpp" + +/** + * @file ctf-msg-iter.h + * + * CTF message iterator + * + * This is a common internal API used by CTF source plugins. It allows + * one to get messages from a user-provided medium. + */ + +/** + * Medium operations status codes. These use the same values as + * libbabeltrace2. + */ +enum ctf_msg_iter_medium_status +{ + /** + * End of file. + * + * The medium function called by the message iterator + * function reached the end of the file. + */ + CTF_MSG_ITER_MEDIUM_STATUS_EOF = 1, + + /** + * There is no data available right now, try again later. + */ + CTF_MSG_ITER_MEDIUM_STATUS_AGAIN = 11, + + /** General error. */ + CTF_MSG_ITER_MEDIUM_STATUS_ERROR = -1, + + /** Memory error. */ + CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR = -12, + + /** Everything okay. */ + CTF_MSG_ITER_MEDIUM_STATUS_OK = 0, +}; + +/** + * CTF message iterator API status code. + */ +enum ctf_msg_iter_status +{ + /** + * End of file. + * + * The medium function called by the message iterator + * function reached the end of the file. + */ + CTF_MSG_ITER_STATUS_EOF = CTF_MSG_ITER_MEDIUM_STATUS_EOF, + + /** + * There is no data available right now, try again later. + * + * Some condition resulted in the + * ctf_msg_iter_medium_ops::request_bytes() user function not + * having access to any data now. You should retry calling the + * last called message iterator function once the situation + * is resolved. + */ + CTF_MSG_ITER_STATUS_AGAIN = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN, + + /** General error. */ + CTF_MSG_ITER_STATUS_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_ERROR, + + /** Memory error. */ + CTF_MSG_ITER_STATUS_MEMORY_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR, + + /** Everything okay. */ + CTF_MSG_ITER_STATUS_OK = CTF_MSG_ITER_MEDIUM_STATUS_OK, +}; + +/** + * Medium operations. + * + * Those user functions are called by the message iterator + * functions to request medium actions. + */ +struct ctf_msg_iter_medium_ops +{ + /** + * Returns the next byte buffer to be used by the binary file + * reader to deserialize binary data. + * + * This function \em must be defined. + * + * The purpose of this function is to return a buffer of bytes + * to the message iterator, of a maximum of \p request_sz + * bytes. If this function cannot return a buffer of at least + * \p request_sz bytes, it may return a smaller buffer. In + * either cases, \p buffer_sz must be set to the returned buffer + * size (in bytes). + * + * The returned buffer's ownership remains the medium, in that + * it won't be freed by the message iterator functions. The + * returned buffer won't be modified by the message + * iterator functions either. + * + * When this function is called for the first time for a given + * file, the offset within the file is considered to be 0. The + * next times this function is called, the returned buffer's + * byte offset within the complete file must be the previous + * offset plus the last returned value of \p buffer_sz by this + * medium. + * + * This function must return one of the following statuses: + * + * - #CTF_MSG_ITER_MEDIUM_STATUS_OK: Everything + * is okay, i.e. \p buffer_sz is set to a positive value + * reflecting the number of available bytes in the buffer + * starting at the address written in \p buffer_addr. + * - #CTF_MSG_ITER_MEDIUM_STATUS_AGAIN: No data is + * available right now. In this case, the message + * iterator function called by the user returns + * #CTF_MSG_ITER_STATUS_AGAIN, and it is the user's + * responsibility to make sure enough data becomes available + * before calling the \em same message iterator + * function again to continue the decoding process. + * - #CTF_MSG_ITER_MEDIUM_STATUS_EOF: The end of + * the file was reached, and no more data will ever be + * available for this file. In this case, the message + * iterator function called by the user returns + * #CTF_MSG_ITER_STATUS_EOF. This must \em not be + * returned when returning at least one byte of data to the + * caller, i.e. this must be returned when there's + * absolutely nothing left; should the request size be + * larger than what's left in the file, this function must + * return what's left, setting \p buffer_sz to the number of + * remaining bytes, and return + * #CTF_MSG_ITER_MEDIUM_STATUS_EOF on the \em following + * call. + * - #CTF_MSG_ITER_MEDIUM_STATUS_ERROR: A fatal + * error occurred during this operation. In this case, the + * message iterator function called by the user returns + * #CTF_MSG_ITER_STATUS_ERROR. + * + * If #CTF_MSG_ITER_MEDIUM_STATUS_OK is not returned, the + * values of \p buffer_sz and \p buffer_addr are \em ignored by + * the caller. + * + * @param request_sz Requested buffer size (bytes) + * @param buffer_addr Returned buffer address + * @param buffer_sz Returned buffer's size (bytes) + * @param data User data + * @returns Status code (see description above) + */ + enum ctf_msg_iter_medium_status (*request_bytes)(size_t request_sz, uint8_t **buffer_addr, + size_t *buffer_sz, void *data); + + /** + * Repositions the underlying stream's position. + * + * This *optional* method repositions the underlying stream + * to a given absolute position in the medium. + * + * @param offset Offset to use for the given directive + * @param data User data + * @returns One of #ctf_msg_iter_medium_status values + */ + enum ctf_msg_iter_medium_status (*seek)(off_t offset, void *data); + + /** + * Called when the message iterator wishes to inform the medium that it + * is about to start a new packet. + * + * After the iterator has called switch_packet, the following call to + * request_bytes must return the content at the start of the next + * packet. */ + enum ctf_msg_iter_medium_status (*switch_packet)(void *data); + + /** + * Returns a stream instance (weak reference) for the given + * stream class. + * + * This is called after a packet header is read, and the + * corresponding stream class is found by the message + * iterator. + * + * @param stream_class Stream class of the stream to get + * @param stream_id Stream (instance) ID of the stream + * to get (-1ULL if not available) + * @param data User data + * @returns Stream instance (weak reference) or + * \c NULL on error + */ + bt_stream *(*borrow_stream)(bt_stream_class *stream_class, int64_t stream_id, void *data); +}; + +/** + * Creates a CTF message iterator. + * + * Upon successful completion, the reference count of \p trace is + * incremented. + * + * @param trace Trace to read + * @param max_request_sz Maximum buffer size, in bytes, to + * request to + * ctf_msg_iter_medium_ops::request_bytes() + * at a time + * @param medops Medium operations + * @param medops_data User data (passed to medium operations) + * @returns New CTF message iterator on + * success, or \c NULL on error + */ +struct ctf_msg_iter *ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz, + struct ctf_msg_iter_medium_ops medops, void *medops_data, + bt_logging_level log_level, bt_self_component *self_comp, + bt_self_message_iterator *self_msg_iter); + +/** + * Destroys a CTF message iterator, freeing all internal resources. + * + * The registered trace's reference count is decremented. + * + * @param msg_iter CTF message iterator + */ +void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_iter); + +/** + * Returns the next message from a CTF message iterator. + * + * Upon successful completion, #CTF_MSG_ITER_STATUS_OK is + * returned, and the next message is written to \p msg. + * In this case, the caller is responsible for calling + * bt_message_put() on the returned message. + * + * If this function returns #CTF_MSG_ITER_STATUS_AGAIN, the caller + * should make sure that data becomes available to its medium, and + * call this function again, until another status is returned. + * + * @param msg_iter CTF message iterator + * @param message Returned message if the function's + * return value is #CTF_MSG_ITER_STATUS_OK + * @returns One of #ctf_msg_iter_status values + */ +enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it, + const bt_message **message); + +struct ctf_msg_iter_packet_properties +{ + int64_t exp_packet_total_size; + int64_t exp_packet_content_size; + uint64_t stream_class_id; + int64_t data_stream_id; + + struct + { + uint64_t discarded_events; + uint64_t packets; + uint64_t beginning_clock; + uint64_t end_clock; + } snapshots; +}; + +enum ctf_msg_iter_status +ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it, + struct ctf_msg_iter_packet_properties *props); + +enum ctf_msg_iter_status +ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it, + uint64_t *first_event_cs); + +enum ctf_msg_iter_status +ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it, + uint64_t *last_event_cs); + +enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, off_t offset); + +/* + * Resets the iterator so that the next requested medium bytes are + * assumed to be the first bytes of a new stream. Depending on + * ctf_msg_iter_set_emit_stream_beginning_message(), the first message + * which this iterator emits after calling ctf_msg_iter_reset() is of + * type `CTF_MESSAGE_TYPE_STREAM_BEGINNING`. + */ +void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it); + +/* + * Like ctf_msg_iter_reset(), but preserves stream-dependent state. + */ +void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it); + +void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val); + +static inline const char *ctf_msg_iter_medium_status_string(enum ctf_msg_iter_medium_status status) +{ + switch (status) { + case CTF_MSG_ITER_MEDIUM_STATUS_EOF: + return "EOF"; + case CTF_MSG_ITER_MEDIUM_STATUS_AGAIN: + return "AGAIN"; + case CTF_MSG_ITER_MEDIUM_STATUS_ERROR: + return "ERROR"; + case CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR: + return "MEMORY_ERROR"; + case CTF_MSG_ITER_MEDIUM_STATUS_OK: + return "OK"; + } + + bt_common_abort(); +} + +static inline const char *ctf_msg_iter_status_string(enum ctf_msg_iter_status status) +{ + switch (status) { + case CTF_MSG_ITER_STATUS_EOF: + return "EOF"; + case CTF_MSG_ITER_STATUS_AGAIN: + return "AGAIN"; + case CTF_MSG_ITER_STATUS_ERROR: + return "ERROR"; + case CTF_MSG_ITER_STATUS_MEMORY_ERROR: + return "MEMORY_ERROR"; + case CTF_MSG_ITER_STATUS_OK: + return "OK"; + } + + bt_common_abort(); +} + +#endif /* CTF_MSG_ITER_H */ diff --git a/src/plugins/ctf/fs-src/data-stream-file.cpp b/src/plugins/ctf/fs-src/data-stream-file.cpp index 4a500221..7261fc74 100644 --- a/src/plugins/ctf/fs-src/data-stream-file.cpp +++ b/src/plugins/ctf/fs-src/data-stream-file.cpp @@ -17,18 +17,19 @@ #define BT_COMP_LOG_SELF_COMP (self_comp) #define BT_LOG_OUTPUT_LEVEL (log_level) #define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/DS" +#include + #include "logging/comp-logging.h" #include "common/assert.h" #include "compat/endian.h" /* IWYU pragma: keep */ #include "compat/mman.h" /* IWYU pragma: keep */ -#include "../common/msg-iter/msg-iter.hpp" +#include "../common/src/msg-iter/msg-iter.hpp" #include "data-stream-file.hpp" #include "file.hpp" #include "fs.hpp" #include "lttng-index.hpp" -#include "plugins/ctf/common/metadata/ctf-meta.hpp" static inline size_t remaining_mmap_bytes(struct ctf_fs_ds_file *ds_file) { diff --git a/src/plugins/ctf/fs-src/data-stream-file.hpp b/src/plugins/ctf/fs-src/data-stream-file.hpp index 297c859f..011abe85 100644 --- a/src/plugins/ctf/fs-src/data-stream-file.hpp +++ b/src/plugins/ctf/fs-src/data-stream-file.hpp @@ -12,7 +12,7 @@ #include -#include "../common/msg-iter/msg-iter.hpp" +#include "../common/src/msg-iter/msg-iter.hpp" struct ctf_fs_ds_file_info { diff --git a/src/plugins/ctf/fs-src/fs.cpp b/src/plugins/ctf/fs-src/fs.cpp index 5306b421..a60c8ddc 100644 --- a/src/plugins/ctf/fs-src/fs.cpp +++ b/src/plugins/ctf/fs-src/fs.cpp @@ -23,13 +23,12 @@ #include "plugins/common/param-validation/param-validation.h" -#include "../common/metadata/ctf-meta-configure-ir-trace.hpp" -#include "../common/msg-iter/msg-iter.hpp" +#include "../common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp" +#include "../common/src/msg-iter/msg-iter.hpp" #include "data-stream-file.hpp" #include "file.hpp" #include "fs.hpp" #include "metadata.hpp" -#include "plugins/ctf/common/metadata/ctf-meta.hpp" #include "query.hpp" struct tracer_info diff --git a/src/plugins/ctf/fs-src/metadata.cpp b/src/plugins/ctf/fs-src/metadata.cpp index ad215f9f..021512e8 100644 --- a/src/plugins/ctf/fs-src/metadata.cpp +++ b/src/plugins/ctf/fs-src/metadata.cpp @@ -18,7 +18,7 @@ #include "common/assert.h" -#include "../common/metadata/decoder.hpp" +#include "../common/src/metadata/tsdl/decoder.hpp" #include "file.hpp" #include "fs.hpp" #include "metadata.hpp" diff --git a/src/plugins/ctf/fs-src/query.cpp b/src/plugins/ctf/fs-src/query.cpp index fa73ab19..22f35106 100644 --- a/src/plugins/ctf/fs-src/query.cpp +++ b/src/plugins/ctf/fs-src/query.cpp @@ -19,7 +19,7 @@ #include "common/assert.h" -#include "../common/metadata/decoder.hpp" +#include "../common/src/metadata/tsdl/decoder.hpp" #include "fs.hpp" #include "metadata.hpp" #include "query.hpp" diff --git a/src/plugins/ctf/lttng-live/data-stream.cpp b/src/plugins/ctf/lttng-live/data-stream.cpp index 4bba7ddb..d749816c 100644 --- a/src/plugins/ctf/lttng-live/data-stream.cpp +++ b/src/plugins/ctf/lttng-live/data-stream.cpp @@ -13,17 +13,22 @@ #include -#include "plugins/ctf/common/metadata/decoder.hpp" - #define BT_COMP_LOG_SELF_COMP self_comp #define BT_LOG_OUTPUT_LEVEL log_level #define BT_LOG_TAG "PLUGIN/SRC.CTF.LTTNG-LIVE/DS" +#include +#include +#include +#include + +#include + #include "logging/comp-logging.h" #include "common/assert.h" #include "compat/mman.h" /* IWYU pragma: keep */ -#include "../common/msg-iter/msg-iter.hpp" +#include "../common/src/msg-iter/msg-iter.hpp" #include "data-stream.hpp" #define STREAM_NAME_PREFIX "stream-" diff --git a/src/plugins/ctf/lttng-live/lttng-live.hpp b/src/plugins/ctf/lttng-live/lttng-live.hpp index 9ca87401..d79cec7e 100644 --- a/src/plugins/ctf/lttng-live/lttng-live.hpp +++ b/src/plugins/ctf/lttng-live/lttng-live.hpp @@ -16,7 +16,8 @@ #include -#include "../common/msg-iter/msg-iter.hpp" +#include "../common/src/metadata/tsdl/decoder.hpp" +#include "../common/src/msg-iter/msg-iter.hpp" #include "viewer-connection.hpp" enum lttng_live_stream_state diff --git a/src/plugins/ctf/lttng-live/metadata.cpp b/src/plugins/ctf/lttng-live/metadata.cpp index b081d639..46a11511 100644 --- a/src/plugins/ctf/lttng-live/metadata.cpp +++ b/src/plugins/ctf/lttng-live/metadata.cpp @@ -20,8 +20,9 @@ #include "compat/memstream.h" -#include "../common/metadata/ctf-meta-configure-ir-trace.hpp" -#include "../common/metadata/decoder.hpp" +#include "../common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp" +#include "../common/src/metadata/tsdl/decoder.hpp" +#include "lttng-live.hpp" #include "metadata.hpp" #define TSDL_MAGIC 0x75d11d57