ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = include types compat lib formats plugins converter bindings tests doc extras ctf-reader-proto
+SUBDIRS = include types compat lib formats plugins converter bindings tests doc extras
dist_doc_DATA = ChangeLog LICENSE mit-license.txt gpl-2.0.txt \
std-ext-lib.txt README
Makefile
types/Makefile
compat/Makefile
- ctf-reader-proto/Makefile
- ctf-reader-proto/metadata-parsing/Makefile
- ctf-reader-proto/ctf-notif-iter/Makefile
- ctf-reader-proto/ctf-btr/Makefile
formats/Makefile
formats/ctf/Makefile
formats/ctf/types/Makefile
extras/valgrind/Makefile
plugins/Makefile
plugins/ctf/Makefile
+ plugins/ctf/common/Makefile
+ plugins/ctf/common/btr/Makefile
+ plugins/ctf/common/metadata/Makefile
+ plugins/ctf/common/notif-iter/Makefile
plugins/ctf/fs/Makefile
plugins/ctf/lttng-live/Makefile
plugins/text/Makefile
+++ /dev/null
-define ctf-btr-show-stack
- if (stack_empty($arg0))
- printf "stack is empty!\n"
- else
- set $stack_size = stack_size($arg0)
- set $stack_at = (int) ($stack_size - 1)
- printf "%3s %10s %4s %3s\n", "pos", "base addr", "blen", "idx"
-
- while ($stack_at >= 0)
- set $stack_entry = (struct stack_entry *) g_ptr_array_index($arg0->entries, $stack_at)
-
- if ($stack_at == $stack_size - 1)
- printf "%3d %10p %3d %3d <-- top\n", $stack_at, \
- $stack_entry->base_type, $stack_entry->base_len, \
- $stack_entry->index
- else
- printf "%3d %10p %3d %3d\n", $stack_at, \
- $stack_entry->base_type, $stack_entry->base_len, \
- $stack_entry->index
- end
- set $stack_at = $stack_at - 1
- end
- end
-end
+++ /dev/null
-AM_CFLAGS = $(PACKAGE_CFLAGS)
-AM_CPPFLAGS = -I$(top_srcdir)/include
-
-noinst_LTLIBRARIES = libctf-btr.la
-
-libctf_btr_la_SOURCES = ctf-btr.c
+++ /dev/null
-/*
- * Babeltrace - CTF binary type reader (BTR)
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <assert.h>
-#include <string.h>
-#include <babeltrace/bitfield.h>
-#include <babeltrace/ctf-ir/field-types.h>
-#include <babeltrace/ref.h>
-#include <babeltrace/align.h>
-#include <glib.h>
-
-#include "ctf-btr.h"
-
-#define PRINT_ERR_STREAM btr->err_stream
-#define PRINT_PREFIX "ctf-btr"
-#include "print.h"
-
-#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 type of base field, one of:
- *
- * * Structure
- * * Array
- * * Sequence
- * * Variant
- *
- * Owned by this.
- */
- struct bt_ctf_field_type *base_type;
-
- /* Length of base field (always 1 for variant types) */
- int64_t base_len;
-
- /* Lndex of next field to read */
- int64_t index;
-};
-
-/* Visit stack */
-struct stack {
- /* Entries (struct stack_entry *) (top is last element) */
- GPtrArray *entries;
-};
-
-/* Reading states */
-enum btr_state {
- BTR_STATE_NEXT_FIELD,
- BTR_STATE_ALIGN_BASIC,
- BTR_STATE_ALIGN_COMPOUND,
- BTR_STATE_READ_BASIC_BEGIN,
- BTR_STATE_READ_BASIC_CONTINUE,
- BTR_STATE_DONE,
-};
-
-/* Binary type reader */
-struct bt_ctf_btr {
- /* Bisit stack */
- struct stack *stack;
-
- /* Error stream */
- FILE *err_stream;
-
- /* Current basic field type */
- struct bt_ctf_field_type *cur_basic_field_type;
-
- /* Current state */
- enum btr_state state;
-
- /*
- * Last basic field type's byte order.
- *
- * This is used to detect errors since two contiguous basic
- * types for which the common boundary is not the boundary of
- * a byte cannot have different byte orders.
- *
- * This is set to BT_CTF_BYTE_ORDER_UNKNOWN on reset and when
- * the last basic field type was a string type.
- */
- enum bt_ctf_byte_order last_bo;
-
- /* Current byte order (copied to last_bo after a successful read) */
- enum bt_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_ctf_btr_cbs cbs;
-
- /* Private data */
- void *data;
- } user;
-};
-
-static
-void stack_entry_free_func(gpointer data)
-{
- struct stack_entry *entry = data;
-
- BT_PUT(entry->base_type);
- g_free(entry);
-}
-
-static
-struct stack *stack_new(void)
-{
- struct stack *stack = NULL;
-
- stack = g_new0(struct stack, 1);
- if (!stack) {
- goto error;
- }
-
- stack->entries = g_ptr_array_new_with_free_func(stack_entry_free_func);
- if (!stack->entries) {
- goto error;
- }
-
- return stack;
-
-error:
- g_free(stack);
-
- return NULL;
-}
-
-static
-void stack_destroy(struct stack *stack)
-{
- if (!stack) {
- return;
- }
-
- g_ptr_array_free(stack->entries, TRUE);
- g_free(stack);
-}
-
-static inline
-int64_t get_compound_field_type_length(struct bt_ctf_btr *btr,
- struct bt_ctf_field_type *field_type)
-{
- int64_t length;
-
- switch (bt_ctf_field_type_get_type_id(field_type)) {
- case BT_CTF_TYPE_ID_STRUCT:
- length = (int64_t) bt_ctf_field_type_structure_get_field_count(
- field_type);
- break;
- case BT_CTF_TYPE_ID_VARIANT:
- /* Variant field types always "contain" a single type */
- length = 1;
- break;
- case BT_CTF_TYPE_ID_ARRAY:
- length = bt_ctf_field_type_array_get_length(field_type);
- break;
- case BT_CTF_TYPE_ID_SEQUENCE:
- length = btr->user.cbs.query.get_sequence_length(field_type,
- btr->user.data);
- break;
- default:
- PERR("Cannot get length of field type with type ID %d\n",
- bt_ctf_field_type_get_type_id(field_type));
- length = BT_CTF_BTR_STATUS_ERROR;
- }
-
- return length;
-}
-
-static
-int stack_push(struct stack *stack, struct bt_ctf_field_type *base_type,
- size_t base_len)
-{
- int ret = 0;
- struct stack_entry *entry;
-
- assert(stack);
- assert(base_type);
-
- entry = g_new0(struct stack_entry, 1);
- if (!entry) {
- ret = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- entry->base_type = base_type;
- bt_get(entry->base_type);
- entry->base_len = base_len;
- g_ptr_array_add(stack->entries, entry);
-
-end:
- return ret;
-}
-
-static
-int stack_push_with_len(struct bt_ctf_btr *btr,
- struct bt_ctf_field_type *base_type)
-{
- int ret = 0;
- int64_t base_len = get_compound_field_type_length(btr, base_type);
-
- if (base_len < 0) {
- PERR("Failed to get compound field type's length\n");
- ret = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- ret = stack_push(btr->stack, base_type, (size_t) base_len);
-
-end:
- return ret;
-}
-
-static inline
-unsigned int stack_size(struct stack *stack)
-{
- assert(stack);
-
- return stack->entries->len;
-}
-
-static
-void stack_pop(struct stack *stack)
-{
- assert(stack);
- assert(stack_size(stack));
- g_ptr_array_remove_index(stack->entries, stack->entries->len - 1);
-}
-
-static inline
-bool stack_empty(struct stack *stack)
-{
- return stack_size(stack) == 0;
-}
-
-static
-void stack_clear(struct stack *stack)
-{
- assert(stack);
-
- if (!stack_empty(stack)) {
- g_ptr_array_remove_range(stack->entries, 0, stack_size(stack));
- }
-
- assert(stack_empty(stack));
-}
-
-static inline
-struct stack_entry *stack_top(struct stack *stack)
-{
- assert(stack);
- assert(stack_size(stack));
-
- return g_ptr_array_index(stack->entries, stack->entries->len - 1);
-}
-
-static inline
-size_t available_bits(struct bt_ctf_btr *btr)
-{
- return btr->buf.sz - btr->buf.at;
-}
-
-static inline
-void consume_bits(struct bt_ctf_btr *btr, size_t incr)
-{
- btr->buf.at += incr;
-}
-
-static inline
-bool has_enough_bits(struct bt_ctf_btr *btr, size_t sz)
-{
- return available_bits(btr) >= sz;
-}
-
-static inline
-bool at_least_one_bit_left(struct bt_ctf_btr *btr)
-{
- return has_enough_bits(btr, 1);
-}
-
-static inline
-size_t packet_at(struct bt_ctf_btr *btr)
-{
- return btr->buf.packet_offset + btr->buf.at;
-}
-
-static inline
-size_t buf_at_from_addr(struct bt_ctf_btr *btr)
-{
- /*
- * Considering this:
- *
- * ====== offset ===== (17)
- *
- * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
- * ^
- * addr (0) ==== at ==== (12)
- *
- * We want this:
- *
- * =============================== (29)
- */
- return btr->buf.offset + btr->buf.at;
-}
-
-static inline
-int get_basic_field_type_size(struct bt_ctf_btr *btr,
- struct bt_ctf_field_type *field_type)
-{
- int size;
-
- switch (bt_ctf_field_type_get_type_id(field_type)) {
- case BT_CTF_TYPE_ID_INTEGER:
- size = bt_ctf_field_type_integer_get_size(field_type);
- break;
- case BT_CTF_TYPE_ID_FLOAT:
- {
- int exp_dig, mant_dig;
-
- exp_dig =
- bt_ctf_field_type_floating_point_get_exponent_digits(
- field_type);
- mant_dig =
- bt_ctf_field_type_floating_point_get_mantissa_digits(
- field_type);
- if (exp_dig < 0 || mant_dig < 0) {
- PERR("Failed to get floating point number type's sizes\n");
- size = BT_CTF_BTR_STATUS_ERROR;
- }
-
- size = exp_dig + mant_dig;
- break;
- }
- case BT_CTF_TYPE_ID_ENUM:
- {
- struct bt_ctf_field_type *int_type;
-
- int_type = bt_ctf_field_type_enumeration_get_container_type(
- field_type);
- if (!int_type) {
- PERR("Failed to get enumeration type's container type\n");
- size = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- size = get_basic_field_type_size(btr, int_type);
- BT_PUT(int_type);
- break;
- }
- default:
- size = BT_CTF_BTR_STATUS_ERROR;
- break;
- }
-
-end:
- return size;
-}
-
-static
-void stitch_reset(struct bt_ctf_btr *btr)
-{
- btr->stitch.offset = 0;
- btr->stitch.at = 0;
-}
-
-static inline
-size_t stitch_at_from_addr(struct bt_ctf_btr *btr)
-{
- return btr->stitch.offset + btr->stitch.at;
-}
-
-static
-void stitch_append_from_buf(struct bt_ctf_btr *btr, 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(btr));
- buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(btr));
- nb_bytes = BITS_TO_BYTES_CEIL(sz);
- assert(nb_bytes > 0);
- memcpy(&btr->stitch.buf[stitch_byte_at], &btr->buf.addr[buf_byte_at],
- nb_bytes);
- btr->stitch.at += sz;
- consume_bits(btr, sz);
-}
-
-static
-void stitch_append_from_remaining_buf(struct bt_ctf_btr *btr)
-{
- stitch_append_from_buf(btr, available_bits(btr));
-}
-
-static
-void stitch_set_from_remaining_buf(struct bt_ctf_btr *btr)
-{
- stitch_reset(btr);
- btr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(btr));
- stitch_append_from_remaining_buf(btr);
-}
-
-static inline
-enum bt_ctf_btr_status read_unsigned_bitfield(const uint8_t *buf, size_t at,
- int64_t field_size, enum bt_ctf_byte_order bo, uint64_t *v)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- switch (bo) {
- case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
- case BT_CTF_BYTE_ORDER_NETWORK:
- bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
- break;
- case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
- bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
- break;
- default:
- status = BT_CTF_BTR_STATUS_ERROR;
- }
-
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status read_signed_bitfield(const uint8_t *buf, size_t at,
- int64_t field_size, enum bt_ctf_byte_order bo, int64_t *v)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- switch (bo) {
- case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
- case BT_CTF_BYTE_ORDER_NETWORK:
- bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
- break;
- case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
- bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
- break;
- default:
- status = BT_CTF_BTR_STATUS_ERROR;
- }
-
- return status;
-}
-
-typedef enum bt_ctf_btr_status (* read_basic_and_call_cb_t)(struct bt_ctf_btr *,
- const uint8_t *, size_t);
-
-static inline
-enum bt_ctf_btr_status validate_contiguous_bo(struct bt_ctf_btr *btr,
- enum bt_ctf_byte_order next_bo)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- /* Always valid when at a byte boundary */
- if (packet_at(btr) % 8 == 0) {
- goto end;
- }
-
- /* Always valid if last byte order is unknown */
- if (btr->last_bo == BT_CTF_BYTE_ORDER_UNKNOWN) {
- goto end;
- }
-
- /* Always valid if next byte order is unknown */
- if (next_bo == BT_CTF_BYTE_ORDER_UNKNOWN) {
- goto end;
- }
-
- /* Make sure last byte order is compatible with the next byte order */
- switch (btr->last_bo) {
- case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
- case BT_CTF_BYTE_ORDER_NETWORK:
- if (next_bo != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
- next_bo != BT_CTF_BYTE_ORDER_NETWORK) {
- status = BT_CTF_BTR_STATUS_ERROR;
- }
- break;
- case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
- if (next_bo != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN) {
- status = BT_CTF_BTR_STATUS_ERROR;
- }
- break;
- default:
- status = BT_CTF_BTR_STATUS_ERROR;
- }
-
-end:
- return status;
-}
-
-static
-enum bt_ctf_btr_status read_basic_float_and_call_cb(struct bt_ctf_btr *btr,
- const uint8_t *buf, size_t at)
-{
- int ret;
- double dblval;
- int64_t field_size;
- enum bt_ctf_byte_order bo;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
- bo = bt_ctf_field_type_get_byte_order(btr->cur_basic_field_type);
- btr->cur_bo = bo;
-
- switch (field_size) {
- case 32:
- {
- uint64_t v;
- union {
- uint32_t u;
- float f;
- } f32;
-
- ret = bt_ctf_field_type_floating_point_get_mantissa_digits(
- btr->cur_basic_field_type);
- assert(ret == 24);
- ret = bt_ctf_field_type_floating_point_get_exponent_digits(
- btr->cur_basic_field_type);
- assert(ret == 8);
- status = read_unsigned_bitfield(buf, at, field_size, bo, &v);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("Failed to reader unsigned bitfield\n");
- goto end;
- }
-
- f32.u = (uint32_t) v;
- dblval = (double) f32.f;
- break;
- }
- case 64:
- {
- union {
- uint64_t u;
- double d;
- } f64;
-
- ret = bt_ctf_field_type_floating_point_get_mantissa_digits(
- btr->cur_basic_field_type);
- assert(ret == 53);
- ret = bt_ctf_field_type_floating_point_get_exponent_digits(
- btr->cur_basic_field_type);
- assert(ret == 11);
- status = read_unsigned_bitfield(buf, at, field_size, bo,
- &f64.u);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("Failed to reader unsigned bitfield\n");
- goto end;
- }
-
- dblval = f64.d;
- break;
- }
- default:
- /* Only 32-bit and 64-bit fields are supported currently */
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- if (btr->user.cbs.types.floating_point) {
- status = btr->user.cbs.types.floating_point(dblval,
- btr->cur_basic_field_type, btr->user.data);
- }
-
-end:
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_int_and_call(struct bt_ctf_btr *btr,
- const uint8_t *buf, size_t at, struct bt_ctf_field_type *int_type,
- struct bt_ctf_field_type *orig_type)
-{
- int signd;
- int64_t field_size;
- enum bt_ctf_byte_order bo;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- signd = bt_ctf_field_type_integer_get_signed(int_type);
- field_size = get_basic_field_type_size(btr, int_type);
- if (field_size < 1) {
- PERR("Failed to get basic field type's size\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- bo = bt_ctf_field_type_get_byte_order(int_type);
-
- /*
- * Update current byte order now because we could be reading
- * the integer value of an enumeration type, and thus we know
- * here the actual supporting integer type's byte order.
- */
- btr->cur_bo = bo;
-
- if (signd) {
- int64_t v;
-
- status = read_signed_bitfield(buf, at, field_size, bo, &v);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("Failed to reader signed bitfield\n");
- goto end;
- }
-
- if (btr->user.cbs.types.signed_int) {
- status = btr->user.cbs.types.signed_int(v,
- btr->cur_basic_field_type, btr->user.data);
- }
- } else {
- uint64_t v;
-
- status = read_unsigned_bitfield(buf, at, field_size, bo, &v);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("Failed to reader unsigned bitfield\n");
- goto end;
- }
-
- if (btr->user.cbs.types.unsigned_int) {
- status = btr->user.cbs.types.unsigned_int(v,
- btr->cur_basic_field_type, btr->user.data);
- }
- }
-
-end:
- return status;
-}
-
-static
-enum bt_ctf_btr_status read_basic_int_and_call_cb(struct bt_ctf_btr *btr,
- const uint8_t *buf, size_t at)
-{
- return read_basic_int_and_call(btr, buf, at, btr->cur_basic_field_type,
- btr->cur_basic_field_type);
-}
-
-static
-enum bt_ctf_btr_status read_basic_enum_and_call_cb(struct bt_ctf_btr *btr,
- const uint8_t *buf, size_t at)
-{
- struct bt_ctf_field_type *int_field_type;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- int_field_type = bt_ctf_field_type_enumeration_get_container_type(
- btr->cur_basic_field_type);
- if (!int_field_type) {
- PERR("Failed to get enumeration type's container type\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- status = read_basic_int_and_call(btr, buf, at,
- int_field_type, btr->cur_basic_field_type);
-
-end:
- BT_PUT(int_field_type);
-
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_type_and_call_continue(struct bt_ctf_btr *btr,
- read_basic_and_call_cb_t read_basic_and_call_cb)
-{
- size_t available;
- int64_t field_size;
- int64_t needed_bits;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- if (!at_least_one_bit_left(btr)) {
- status = BT_CTF_BTR_STATUS_EOF;
- goto end;
- }
-
- field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
- if (field_size < 1) {
- PERR("Failed to get basic field type's size\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- available = available_bits(btr);
- needed_bits = field_size - btr->stitch.at;
- if (needed_bits <= available) {
- /* We have all the bits; append to stitch, then decode */
- stitch_append_from_buf(btr, needed_bits);
- status = read_basic_and_call_cb(btr, btr->stitch.buf,
- btr->stitch.offset);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("Failed to read basic field\n");
- goto end;
- }
-
- if (stack_empty(btr->stack)) {
- /* Root is a basic type */
- btr->state = BTR_STATE_DONE;
- } else {
- /* Go to next field */
- stack_top(btr->stack)->index++;
- btr->state = BTR_STATE_NEXT_FIELD;
- btr->last_bo = btr->cur_bo;
- }
- goto end;
- }
-
- /* We are here; it means we don't have enough data to decode this */
- stitch_append_from_remaining_buf(btr);
- status = BT_CTF_BTR_STATUS_EOF;
-
-end:
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_type_and_call_begin(struct bt_ctf_btr *btr,
- read_basic_and_call_cb_t read_basic_and_call_cb)
-{
- size_t available;
- int64_t field_size;
- enum bt_ctf_byte_order bo;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- if (!at_least_one_bit_left(btr)) {
- status = BT_CTF_BTR_STATUS_EOF;
- goto end;
- }
-
- field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
-
- if (field_size < 1) {
- PERR("Failed to get basic field type's size\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- bo = bt_ctf_field_type_get_byte_order(btr->cur_basic_field_type);
- status = validate_contiguous_bo(btr, bo);
-
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("Invalid contiguous byte orders\n");
- goto end;
- }
-
- available = available_bits(btr);
-
- if (field_size <= available) {
- /* We have all the bits; decode and set now */
- status = read_basic_and_call_cb(btr, btr->buf.addr,
- buf_at_from_addr(btr));
-
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("Failed to read basic type\n");
- goto end;
- }
-
- consume_bits(btr, field_size);
-
- if (stack_empty(btr->stack)) {
- /* Root is a basic type */
- btr->state = BTR_STATE_DONE;
- } else {
- /* Go to next field */
- stack_top(btr->stack)->index++;
- btr->state = BTR_STATE_NEXT_FIELD;
- btr->last_bo = btr->cur_bo;
- }
-
- goto end;
- }
-
- /* We are here; it means we don't have enough data to decode this */
- stitch_set_from_remaining_buf(btr);
- btr->state = BTR_STATE_READ_BASIC_CONTINUE;
- status = BT_CTF_BTR_STATUS_EOF;
-
-end:
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_int_type_and_call_begin(
- struct bt_ctf_btr *btr)
-{
- return read_basic_type_and_call_begin(btr, read_basic_int_and_call_cb);
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_int_type_and_call_continue(
- struct bt_ctf_btr *btr)
-{
- return read_basic_type_and_call_continue(btr,
- read_basic_int_and_call_cb);
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_float_type_and_call_begin(
- struct bt_ctf_btr *btr)
-{
- return read_basic_type_and_call_begin(btr,
- read_basic_float_and_call_cb);
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_float_type_and_call_continue(
- struct bt_ctf_btr *btr)
-{
- return read_basic_type_and_call_continue(btr,
- read_basic_float_and_call_cb);
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_enum_type_and_call_begin(
- struct bt_ctf_btr *btr)
-{
- return read_basic_type_and_call_begin(btr,
- read_basic_enum_and_call_cb);
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_enum_type_and_call_continue(
- struct bt_ctf_btr *btr)
-{
- return read_basic_type_and_call_continue(btr,
- read_basic_enum_and_call_cb);
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_string_type_and_call(
- struct bt_ctf_btr *btr, bool begin)
-{
- size_t buf_at_bytes;
- const uint8_t *result;
- size_t available_bytes;
- const uint8_t *first_chr;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- if (!at_least_one_bit_left(btr)) {
- status = BT_CTF_BTR_STATUS_EOF;
- goto end;
- }
-
- assert(buf_at_from_addr(btr) % 8 == 0);
- available_bytes = BITS_TO_BYTES_FLOOR(available_bits(btr));
- buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(btr));
- first_chr = &btr->buf.addr[buf_at_bytes];
- result = memchr(first_chr, '\0', available_bytes);
-
- if (begin && btr->user.cbs.types.string_begin) {
- status = btr->user.cbs.types.string_begin(
- btr->cur_basic_field_type, btr->user.data);
-
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("string_begin() user callback function failed\n");
- goto end;
- }
- }
-
- if (!result) {
- /* No null character yet */
- if (btr->user.cbs.types.string) {
- status = btr->user.cbs.types.string(
- (const char *) first_chr,
- available_bytes, btr->cur_basic_field_type,
- btr->user.data);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("string() user callback function failed\n");
- goto end;
- }
- }
-
- consume_bits(btr, BYTES_TO_BITS(available_bytes));
- btr->state = BTR_STATE_READ_BASIC_CONTINUE;
- status = BT_CTF_BTR_STATUS_EOF;
- } else {
- /* Found the null character */
- size_t result_len = (size_t) (result - first_chr);
-
- if (btr->user.cbs.types.string && result_len) {
- status = btr->user.cbs.types.string(
- (const char *) first_chr,
- result_len, btr->cur_basic_field_type,
- btr->user.data);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("string() user callback function failed\n");
- goto end;
- }
- }
-
- if (btr->user.cbs.types.string_end) {
- status = btr->user.cbs.types.string_end(
- btr->cur_basic_field_type, btr->user.data);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("string_end() user callback function failed\n");
- goto end;
- }
- }
-
- consume_bits(btr, BYTES_TO_BITS(result_len + 1));
-
- if (stack_empty(btr->stack)) {
- /* Root is a basic type */
- btr->state = BTR_STATE_DONE;
- } else {
- /* Go to next field */
- stack_top(btr->stack)->index++;
- btr->state = BTR_STATE_NEXT_FIELD;
- btr->last_bo = btr->cur_bo;
- }
- }
-
-end:
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_begin_state(struct bt_ctf_btr *btr)
-{
- enum bt_ctf_btr_status status;
-
- assert(btr->cur_basic_field_type);
-
- switch (bt_ctf_field_type_get_type_id(btr->cur_basic_field_type)) {
- case BT_CTF_TYPE_ID_INTEGER:
- status = read_basic_int_type_and_call_begin(btr);
- break;
- case BT_CTF_TYPE_ID_FLOAT:
- status = read_basic_float_type_and_call_begin(btr);
- break;
- case BT_CTF_TYPE_ID_ENUM:
- status = read_basic_enum_type_and_call_begin(btr);
- break;
- case BT_CTF_TYPE_ID_STRING:
- status = read_basic_string_type_and_call(btr, true);
- break;
- default:
- assert(false);
- }
-
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status read_basic_continue_state(struct bt_ctf_btr *btr)
-{
- enum bt_ctf_btr_status status;
-
- assert(btr->cur_basic_field_type);
-
- switch (bt_ctf_field_type_get_type_id(btr->cur_basic_field_type)) {
- case BT_CTF_TYPE_ID_INTEGER:
- status = read_basic_int_type_and_call_continue(btr);
- break;
- case BT_CTF_TYPE_ID_FLOAT:
- status = read_basic_float_type_and_call_continue(btr);
- break;
- case BT_CTF_TYPE_ID_ENUM:
- status = read_basic_enum_type_and_call_continue(btr);
- break;
- case BT_CTF_TYPE_ID_STRING:
- status = read_basic_string_type_and_call(btr, false);
- break;
- default:
- assert(false);
- }
-
- return status;
-}
-
-static inline
-size_t bits_to_skip_to_align_to(struct bt_ctf_btr *btr, size_t align)
-{
- size_t aligned_packet_at;
-
- aligned_packet_at = ALIGN(packet_at(btr), align);
-
- return aligned_packet_at - packet_at(btr);
-}
-
-static inline
-enum bt_ctf_btr_status align_type_state(struct bt_ctf_btr *btr,
- struct bt_ctf_field_type *field_type, enum btr_state next_state)
-{
- int field_alignment;
- size_t skip_bits;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- /* Get field's alignment */
- field_alignment = bt_ctf_field_type_get_alignment(field_type);
- if (field_alignment < 0) {
- PERR("Failed to get type alignment\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- /*
- * 0 means "undefined" for variants; what we really want is 1
- * (always aligned)
- */
- if (field_alignment == 0) {
- field_alignment = 1;
- }
-
- /* Compute how many bits we need to skip */
- skip_bits = bits_to_skip_to_align_to(btr, field_alignment);
-
- /* Nothing to skip? aligned */
- if (skip_bits == 0) {
- btr->state = next_state;
- goto end;
- }
-
- /* Make sure there's at least one bit left */
- if (!at_least_one_bit_left(btr)) {
- status = BT_CTF_BTR_STATUS_EOF;
- goto end;
- }
-
- /* Consume as many bits as possible in what's left */
- consume_bits(btr, MIN(available_bits(btr), skip_bits));
-
- /* Are we done now? */
- skip_bits = bits_to_skip_to_align_to(btr, field_alignment);
-
- if (skip_bits == 0) {
- /* Yes: go to next state */
- btr->state = next_state;
- goto end;
- } else {
- /* No: need more data */
- status = BT_CTF_BTR_STATUS_EOF;
- }
-
-end:
- return status;
-}
-
-static inline
-bool is_compound_type(struct bt_ctf_field_type *field_type)
-{
- enum bt_ctf_type_id id = bt_ctf_field_type_get_type_id(field_type);
-
- return id == BT_CTF_TYPE_ID_STRUCT || id == BT_CTF_TYPE_ID_ARRAY ||
- id == BT_CTF_TYPE_ID_SEQUENCE || id == BT_CTF_TYPE_ID_VARIANT;
-}
-
-static inline
-enum bt_ctf_btr_status next_field_state(struct bt_ctf_btr *btr)
-{
- int ret;
- struct stack_entry *top;
- struct bt_ctf_field_type *next_field_type = NULL;
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- if (stack_empty(btr->stack)) {
- goto end;
- }
-
- top = stack_top(btr->stack);
-
- /* Are we done with this base type? */
- while (top->index == top->base_len) {
- if (btr->user.cbs.types.compound_end) {
- status = btr->user.cbs.types.compound_end(
- top->base_type, btr->user.data);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("compound_end() user callback function failed\n");
- goto end;
- }
- }
-
- stack_pop(btr->stack);
-
- /* Are we done with the root type? */
- if (stack_empty(btr->stack)) {
- btr->state = BTR_STATE_DONE;
- goto end;
- }
-
- top = stack_top(btr->stack);
- top->index++;
- }
-
- /* Get next field's type */
- switch (bt_ctf_field_type_get_type_id(top->base_type)) {
- case BT_CTF_TYPE_ID_STRUCT:
- ret = bt_ctf_field_type_structure_get_field(
- top->base_type, NULL, &next_field_type,
- top->index);
- if (ret) {
- next_field_type = NULL;
- }
- break;
- case BT_CTF_TYPE_ID_ARRAY:
- next_field_type =
- bt_ctf_field_type_array_get_element_type(
- top->base_type);
- break;
- case BT_CTF_TYPE_ID_SEQUENCE:
- next_field_type =
- bt_ctf_field_type_sequence_get_element_type(
- top->base_type);
- break;
- case BT_CTF_TYPE_ID_VARIANT:
- /* Variant types are dynamic: query the user, he should know! */
- next_field_type =
- btr->user.cbs.query.get_variant_type(
- top->base_type, btr->user.data);
- break;
- default:
- break;
- }
-
- if (!next_field_type) {
- PERR("Failed to get next field's type\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- if (is_compound_type(next_field_type)) {
- if (btr->user.cbs.types.compound_begin) {
- status = btr->user.cbs.types.compound_begin(
- next_field_type, btr->user.data);
- if (status != BT_CTF_BTR_STATUS_OK) {
- PERR("compound_begin() user callback function failed\n");
- goto end;
- }
- }
-
- ret = stack_push_with_len(btr, next_field_type);
- if (ret) {
- PERR("Failed to push compound type onto the stack\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- /* Next state: align a compound type */
- btr->state = BTR_STATE_ALIGN_COMPOUND;
- } else {
- /* Replace current basic field type */
- BT_MOVE(btr->cur_basic_field_type, next_field_type);
-
- /* Next state: align a basic type */
- btr->state = BTR_STATE_ALIGN_BASIC;
- }
-
-end:
- BT_PUT(next_field_type);
-
- return status;
-}
-
-static inline
-enum bt_ctf_btr_status handle_state(struct bt_ctf_btr *btr)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
-
- switch (btr->state) {
- case BTR_STATE_NEXT_FIELD:
- status = next_field_state(btr);
- break;
- case BTR_STATE_ALIGN_BASIC:
- status = align_type_state(btr, btr->cur_basic_field_type,
- BTR_STATE_READ_BASIC_BEGIN);
- break;
- case BTR_STATE_ALIGN_COMPOUND:
- status = align_type_state(btr, stack_top(btr->stack)->base_type,
- BTR_STATE_NEXT_FIELD);
- break;
- case BTR_STATE_READ_BASIC_BEGIN:
- status = read_basic_begin_state(btr);
- break;
- case BTR_STATE_READ_BASIC_CONTINUE:
- status = read_basic_continue_state(btr);
- break;
- case BTR_STATE_DONE:
- break;
- }
-
- return status;
-}
-
-struct bt_ctf_btr *bt_ctf_btr_create(struct bt_ctf_btr_cbs cbs, void *data,
- FILE *err_stream)
-{
- struct bt_ctf_btr *btr;
-
- btr = g_new0(struct bt_ctf_btr, 1);
- if (!btr) {
- PERR("Failed to allocate memory for binary type reader\n");
- goto end;
- }
-
- btr->stack = stack_new();
- if (!btr->stack) {
- PERR("Failed to create stack\n");
- bt_ctf_btr_destroy(btr);
- btr = NULL;
- goto end;
- }
-
- btr->state = BTR_STATE_NEXT_FIELD;
- btr->user.cbs = cbs;
- btr->user.data = data;
- btr->err_stream = err_stream;
-
-end:
- return btr;
-}
-
-void bt_ctf_btr_destroy(struct bt_ctf_btr *btr)
-{
- if (btr->stack) {
- stack_destroy(btr->stack);
- }
-
- BT_PUT(btr->cur_basic_field_type);
- g_free(btr);
-}
-
-static
-void reset(struct bt_ctf_btr *btr)
-{
- stack_clear(btr->stack);
- BT_PUT(btr->cur_basic_field_type);
- stitch_reset(btr);
- btr->buf.addr = NULL;
- btr->last_bo = BT_CTF_BYTE_ORDER_UNKNOWN;
-}
-
-size_t bt_ctf_btr_start(struct bt_ctf_btr *btr,
- struct bt_ctf_field_type *type, const uint8_t *buf,
- size_t offset, size_t packet_offset, size_t sz,
- enum bt_ctf_btr_status *status)
-{
- assert(btr);
- assert(buf);
- assert(sz > 0);
- assert(BYTES_TO_BITS(sz) > offset);
- reset(btr);
- btr->buf.addr = buf;
- btr->buf.offset = offset;
- btr->buf.at = 0;
- btr->buf.packet_offset = packet_offset;
- btr->buf.buf_sz = sz;
- btr->buf.sz = BYTES_TO_BITS(sz) - offset;
- *status = BT_CTF_BTR_STATUS_OK;
-
- /* Set root type */
- if (is_compound_type(type)) {
- /* Compound type: push on visit stack */
- int stack_ret;
-
- if (btr->user.cbs.types.compound_begin) {
- *status = btr->user.cbs.types.compound_begin(
- type, btr->user.data);
- if (*status != BT_CTF_BTR_STATUS_OK) {
- PERR("compound_begin() user callback function failed\n");
- goto end;
- }
- }
-
- stack_ret = stack_push_with_len(btr, type);
- if (stack_ret) {
- PERR("Failed to push initial compound type onto the stack\n");
- *status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- btr->state = BTR_STATE_ALIGN_COMPOUND;
- } else {
- /* Basic type: set as current basic type */
- btr->cur_basic_field_type = type;
- bt_get(btr->cur_basic_field_type);
- btr->state = BTR_STATE_ALIGN_BASIC;
- }
-
- /* Run the machine! */
- while (true) {
- *status = handle_state(btr);
- if (*status != BT_CTF_BTR_STATUS_OK) {
- break;
- } else if (btr->state == BTR_STATE_DONE) {
- break;
- }
- }
-
- /* Update packet offset for next time */
- btr->buf.packet_offset += btr->buf.at;
-
-end:
- return btr->buf.at;
-}
-
-size_t bt_ctf_btr_continue(struct bt_ctf_btr *btr,
- const uint8_t *buf, size_t sz,
- enum bt_ctf_btr_status *status)
-{
- assert(btr);
- assert(buf);
- assert(sz > 0);
- btr->buf.addr = buf;
- btr->buf.offset = 0;
- btr->buf.at = 0;
- btr->buf.buf_sz = sz;
- btr->buf.sz = BYTES_TO_BITS(sz);
- *status = BT_CTF_BTR_STATUS_OK;
-
- /* Continue running the machine */
- while (true) {
- *status = handle_state(btr);
- if (*status != BT_CTF_BTR_STATUS_OK) {
- break;
- } else if (btr->state == BTR_STATE_DONE) {
- break;
- }
- }
-
- /* Update packet offset for next time */
- btr->buf.packet_offset += btr->buf.at;
-
- return btr->buf.at;
-}
+++ /dev/null
-#ifndef CTF_BTR_H
-#define CTF_BTR_H
-
-/*
- * Babeltrace - CTF binary type reader (BTR)
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <babeltrace/ctf-ir/field-types.h>
-#include <babeltrace/babeltrace-internal.h>
-
-/**
- * @file ctf-btr.h
- *
- * Event-driven CTF binary type reader (BTR).
- *
- * This is a common, internal API used by CTF source plugins. It allows
- * a binary CTF IR field type to be decoded from user-provided buffers.
- * As the type is decoded (and, possibly, its nested types), registered
- * user callback functions are called.
- *
- * This API is only concerned with reading one CTF type 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 types are
- * requested to the user when needed.
- */
-
-/**
- * Binary type reader API status codes.
- */
-enum bt_ctf_btr_status {
- /**
- * The binary stream reader reached the end of the user-provided
- * buffer, but data is still needed to finish decoding the
- * requested type.
- *
- * The user needs to call bt_ctf_btr_continue() as long as
- * #BT_CTF_BTR_STATUS_EOF is returned to complete the decoding
- * process of a given type.
- */
- BT_CTF_BTR_STATUS_EOF = -4,
-
- /** Invalid argument. */
- BT_CTF_BTR_STATUS_INVAL = -3,
-
- /** General error. */
- BT_CTF_BTR_STATUS_ERROR = -1,
-
- /** Everything okay. */
- BT_CTF_BTR_STATUS_OK = 0,
-};
-
-/** Type reader. */
-struct bt_ctf_btr;
-
-/*
- * Type reader user callback functions.
- */
-struct bt_ctf_btr_cbs {
- /**
- * Type callback functions.
- *
- * This CTF binary type reader is event-driven. The following
- * functions are called during the decoding process, either when
- * a compound type begins/ends, or when a basic type is
- * completely decoded (along with its value).
- *
- * Each function also receives the CTF IR field type associated
- * with the call, and user data (registered to the type reader
- * calling them). This field type is a weak reference; the
- * callback function must use bt_ctf_field_type_get() to keep
- * its own reference of it.
- *
- * Actual CTF IR fields are \em not created here; this would be
- * the responsibility of a type reader's user (the provider of
- * those callback functions).
- *
- * All the type callback functions return one of the following
- * values:
- *
- * - <b>#BT_CTF_BTR_STATUS_OK</b>: Everything is okay;
- * continue the decoding process.
- * - <b>#BT_CTF_BTR_STATUS_ERROR</b>: General error (reported
- * to type reader's user).
- *
- * Any member of this structure may be set to \c NULL, should
- * a specific notification be not needed.
- */
- struct {
- /**
- * Called when a signed integer type is completely
- * decoded. This could also be the supporting signed
- * integer type of an enumeration type (\p type will
- * indicate this).
- *
- * @param value Signed integer value
- * @param type Integer or enumeration type (weak
- * reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* signed_int)(int64_t value,
- struct bt_ctf_field_type *type, void *data);
-
- /**
- * Called when an unsigned integer type is completely
- * decoded. This could also be the supporting signed
- * integer type of an enumeration type (\p type will
- * indicate this).
- *
- * @param value Unsigned integer value
- * @param type Integer or enumeration type (weak
- * reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* unsigned_int)(uint64_t value,
- struct bt_ctf_field_type *type, void *data);
-
- /**
- * Called when a floating point number type is
- * completely decoded.
- *
- * @param value Floating point number value
- * @param type Floating point number type (weak
- * reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* floating_point)(double value,
- struct bt_ctf_field_type *type, void *data);
-
- /**
- * Called when a string type begins.
- *
- * All the following user callback function calls will
- * be made to bt_ctf_btr_cbs::types::string(), each of
- * them providing one substring of the complete string
- * type's value.
- *
- * @param type Beginning string type (weak reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* string_begin)(
- struct bt_ctf_field_type *type, void *data);
-
- /**
- * Called when a string type's substring is decoded
- * (between a call to bt_ctf_btr_cbs::types::string_begin()
- * and a call to bt_ctf_btr_cbs::types::string_end()).
- *
- * @param value String value (\em not null-terminated)
- * @param len String value length
- * @param type String type (weak reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* string)(const char *value,
- size_t len, struct bt_ctf_field_type *type,
- void *data);
-
- /**
- * Called when a string type ends.
- *
- * @param type Ending string type (weak reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* string_end)(
- struct bt_ctf_field_type *type, void *data);
-
- /**
- * Called when a compound type begins.
- *
- * All the following type callback function calls will
- * signal sequential elements of this compound type,
- * until the next corresponding
- * bt_ctf_btr_cbs::types::compound_end() is called.
- *
- * If \p type is a variant type, then only one type
- * callback function call will follow before the call to
- * bt_ctf_btr_cbs::types::compound_end(). This single
- * call indicates the selected type of this variant
- * type.
- *
- * @param type Beginning compound type (weak reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* compound_begin)(
- struct bt_ctf_field_type *type, void *data);
-
- /**
- * Called when a compound type ends.
- *
- * @param type Ending compound type (weak reference)
- * @param data User data
- * @returns #BT_CTF_BTR_STATUS_OK or
- * #BT_CTF_BTR_STATUS_ERROR
- */
- enum bt_ctf_btr_status (* compound_end)(
- struct bt_ctf_field_type *type, void *data);
- } types;
-
- /**
- * Query callback functions are used when the type reader needs
- * dynamic information, i.e. a sequence type's current length
- * or a variant type's current selected type.
- *
- * 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
- * type.
- *
- * @param type Sequence type (weak reference)
- * @param data User data
- * @returns Sequence length or
- * #BT_CTF_BTR_STATUS_ERROR on error
- */
- int64_t (* get_sequence_length)(struct bt_ctf_field_type *type,
- void *data);
-
- /**
- * Called to query the current selected type of a given
- * variant type.
- *
- * @param type Variant type (weak reference)
- * @param data User data
- * @returns Current selected type (owned by
- * this) or \c NULL on error
- */
- struct bt_ctf_field_type * (* get_variant_type)(
- struct bt_ctf_field_type *type, void *data);
- } query;
-};
-
-/**
- * Creates a CTF binary type reader.
- *
- * @param cbs User callback functions
- * @param data User data (passed to user callback functions)
- * @param err_stream Error stream (can be \c NULL to disable)
- * @returns New binary type reader on success, or \c NULL on error
- */
-struct bt_ctf_btr *bt_ctf_btr_create(struct bt_ctf_btr_cbs cbs, void *data,
- FILE *err_stream);
-
-/**
- * Destroys a CTF binary type reader, freeing all internal resources.
- *
- * @param btr Binary type reader
- */
-void bt_ctf_btr_destroy(struct bt_ctf_btr *btr);
-
-/**
- * Decodes a given CTF type 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:
- *
- * - <b>#BT_CTF_BTR_STATUS_OK</b>: Decoding is done.
- * - <b>#BT_CTF_BTR_STATUS_EOF</b>: The end of the buffer was reached,
- * but more data is needed to finish the decoding process of the
- * requested type. The user needs to call bt_ctf_btr_continue()
- * as long as #BT_CTF_BTR_STATUS_EOF is returned to complete the
- * decoding process of the original type.
- * - <b>#BT_CTF_BTR_STATUS_INVAL</b>: Invalid argument.
- * - <b>#BT_CTF_BTR_STATUS_ERROR</b>: General error.
- *
- * Calling this function resets the type reader's internal state. If
- * #BT_CTF_BTR_STATUS_EOF is returned, bt_ctf_btr_continue() needs to
- * be called next, \em not bt_ctf_btr_decode().
- *
- * @param btr Binary type reader
- * @param type Type to decode (weak reference)
- * @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 type (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_ctf_btr_start(struct bt_ctf_btr *btr,
- struct bt_ctf_field_type *type, const uint8_t *buf,
- size_t offset, size_t packet_offset, size_t sz,
- enum bt_ctf_btr_status *status);
-
-/**
- * Continues the decoding process a given CTF type.
- *
- * The number of bits consumed by this function is returned.
- *
- * The \p status output parameter is where a status is placed, amongst
- * the following:
- *
- * - <b>#BT_CTF_BTR_STATUS_OK</b>: decoding is done.
- * - <b>#BT_CTF_BTR_STATUS_EOF</b>: the end of the buffer was reached,
- * but more data is needed to finish the decoding process of the
- * requested type. The user needs to call bt_ctf_btr_continue()
- * as long as #BT_CTF_BTR_STATUS_EOF is returned to complete the
- * decoding process of the original type.
- * - <b>#BT_CTF_BTR_STATUS_INVAL</b>: invalid argument.
- * - <b>#BT_CTF_BTR_STATUS_ERROR</b>: general error.
- *
- * @param btr Binary type 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_ctf_btr_continue(struct bt_ctf_btr *btr,
- const uint8_t *buf, size_t sz,
- enum bt_ctf_btr_status *status);
-
-#endif /* CTF_BTR_H */
+++ /dev/null
-#ifndef CTF_BTR_PRINT_H
-#define CTF_BTR_PRINT_H
-
-/*
- * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <babeltrace/babeltrace-internal.h>
-
-#define PERR(fmt, ...) \
- do { \
- if (PRINT_ERR_STREAM) { \
- fprintf(PRINT_ERR_STREAM, \
- "Error: " PRINT_PREFIX ": " fmt, \
- ##__VA_ARGS__); \
- } \
- } while (0)
-
-#define PWARN(fmt, ...) \
- do { \
- if (PRINT_ERR_STREAM) { \
- fprintf(PRINT_ERR_STREAM, \
- "Warning: " PRINT_PREFIX ": " fmt, \
- ##__VA_ARGS__); \
- } \
- } while (0)
-
-#define PDBG(fmt, ...) \
- do { \
- if (babeltrace_debug) { \
- fprintf(stderr, \
- "Debug: " PRINT_PREFIX ": " fmt, \
- ##__VA_ARGS__); \
- } \
- } while (0)
-
-#endif /* CTF_BTR_PRINT_H */
+++ /dev/null
-AM_CFLAGS = $(PACKAGE_CFLAGS)
-AM_CPPFLAGS = -I$(top_srcdir)/include
-
-noinst_LTLIBRARIES = libctf-notif-iter.la
-
-libctf_notif_iter_la_SOURCES = ctf-notif-iter.c
+++ /dev/null
-/*
- * Babeltrace - CTF notification iterator
- * ¯¯¯¯¯ ¯¯¯¯
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <assert.h>
-#include <string.h>
-#include <babeltrace/ctf-ir/field-types.h>
-#include <babeltrace/ctf-ir/field-path.h>
-#include <babeltrace/ctf-ir/fields.h>
-#include <babeltrace/ctf-ir/stream-class.h>
-#include <babeltrace/ctf-ir/packet.h>
-#include <babeltrace/ctf-ir/stream.h>
-#include <babeltrace/ctf-ir/clock.h>
-#include <babeltrace/ctf-ir/event-class.h>
-#include <babeltrace/ref.h>
-#include <glib.h>
-
-#define PRINT_ERR_STREAM notit->err_stream
-#define PRINT_PREFIX "ctf-notif-iter"
-#include "print.h"
-
-#include "ctf-notif-iter.h"
-#include "../ctf-btr/ctf-btr.h"
-
-#define BYTES_TO_BITS(x) ((x) * 8)
-
-struct bt_ctf_notif_iter;
-
-/* A visit stack entry */
-struct stack_entry {
- /*
- * Current base field, one of:
- *
- * * string
- * * structure
- * * array
- * * sequence
- * * variant
- *
- * Field is owned by this.
- */
- struct bt_ctf_field *base;
-
- /* index of next field to set */
- size_t index;
-};
-
-/* Visit stack */
-struct stack {
- /* Entries (struct stack_entry *) (top is last element) */
- GPtrArray *entries;
-
- /* Link to owner */
- struct bt_ctf_notif_iter *notit;
-};
-
-/* State */
-enum state {
- STATE_INIT,
- 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_NOTIF_NEW_PACKET,
- STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN,
- STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
- STATE_AFTER_STREAM_EVENT_HEADER,
- STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN,
- STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
- STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
- STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
- STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
- STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
- STATE_EMIT_NOTIF_EVENT,
- STATE_EMIT_NOTIF_END_OF_PACKET,
- STATE_SKIP_PACKET_PADDING,
-};
-
-/* CTF notification iterator */
-struct bt_ctf_notif_iter {
- /* Visit stack */
- struct stack *stack;
-
- /* Error stream (may be NULL) */
- FILE *err_stream;
-
- /*
- * Current dynamic scope field pointer.
- *
- * This is set when a dynamic scope field is first created by
- * btr_compound_begin_cb(). It points to one of the fields in
- * dscopes below.
- */
- struct bt_ctf_field **cur_dscope_field;
-
- /* Trace and classes (owned by this) */
- struct {
- struct bt_ctf_trace *trace;
- struct bt_ctf_stream_class *stream_class;
- struct bt_ctf_event_class *event_class;
- } meta;
-
- /* Current packet (NULL if not created yet) */
- struct bt_ctf_packet *packet;
-
- /* Database of current dynamic scopes (owned by this) */
- struct {
- struct bt_ctf_field *trace_packet_header;
- struct bt_ctf_field *stream_packet_context;
- struct bt_ctf_field *stream_event_header;
- struct bt_ctf_field *stream_event_context;
- struct bt_ctf_field *event_context;
- struct bt_ctf_field *event_payload;
- } dscopes;
-
- /* Current state */
- enum state state;
-
- /* User buffer stuff */
- 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;
- } buf;
-
- /* Binary type reader */
- struct bt_ctf_btr *btr;
-
- /* Medium stuff */
- struct {
- struct bt_ctf_notif_iter_medium_ops medops;
- size_t max_request_sz;
- void *data;
- } medium;
-
- /* Current packet size (bits) (-1 if unknown) */
- size_t cur_packet_size;
-
- /* Current content size (bits) (-1 if unknown) */
- size_t cur_content_size;
-};
-
-static
-void stack_entry_free_func(gpointer data)
-{
- struct stack_entry *entry = data;
-
- bt_put(entry->base);
- g_free(entry);
-}
-
-static
-struct stack *stack_new(struct bt_ctf_notif_iter *notit)
-{
- struct stack *stack = NULL;
-
- stack = g_new0(struct stack, 1);
- if (!stack) {
- goto error;
- }
-
- stack->entries = g_ptr_array_new_with_free_func(stack_entry_free_func);
- if (!stack->entries) {
- goto error;
- }
-
- stack->notit = notit;
-
- return stack;
-
-error:
- g_free(stack);
-
- return NULL;
-}
-
-static
-void stack_destroy(struct stack *stack)
-{
- assert(stack);
- g_ptr_array_free(stack->entries, TRUE);
- g_free(stack);
-}
-
-static
-int stack_push(struct stack *stack, struct bt_ctf_field *base)
-{
- int ret = 0;
- struct stack_entry *entry;
- struct bt_ctf_notif_iter *notit;
-
- assert(stack);
- assert(base);
- notit = stack->notit;
- entry = g_new0(struct stack_entry, 1);
- if (!entry) {
- PERR("Cannot create new stack entry\n");
- ret = -1;
- goto end;
- }
-
- entry->base = bt_get(base);
- g_ptr_array_add(stack->entries, entry);
-
-end:
- return ret;
-}
-
-static inline
-unsigned int stack_size(struct stack *stack)
-{
- assert(stack);
-
- return stack->entries->len;
-}
-
-static
-void stack_pop(struct stack *stack)
-{
- assert(stack);
- assert(stack_size(stack));
- g_ptr_array_remove_index(stack->entries, stack->entries->len - 1);
-}
-
-static inline
-struct stack_entry *stack_top(struct stack *stack)
-{
- assert(stack);
- assert(stack_size(stack));
-
- return g_ptr_array_index(stack->entries, stack->entries->len - 1);
-}
-
-static inline
-bool stack_empty(struct stack *stack)
-{
- return stack_size(stack) == 0;
-}
-
-static
-void stack_clear(struct stack *stack)
-{
- assert(stack);
-
- if (!stack_empty(stack)) {
- g_ptr_array_remove_range(stack->entries, 0, stack_size(stack));
- }
-
- assert(stack_empty(stack));
-}
-
-static inline
-enum bt_ctf_notif_iter_status notif_iter_status_from_m_status(
- enum bt_ctf_notif_iter_medium_status m_status)
-{
- return m_status;
-}
-
-static inline
-size_t buf_size_bits(struct bt_ctf_notif_iter *notit)
-{
- return BYTES_TO_BITS(notit->buf.sz);
-}
-
-static inline
-size_t buf_available_bits(struct bt_ctf_notif_iter *notit)
-{
- return buf_size_bits(notit) - notit->buf.at;
-}
-
-static inline
-size_t packet_at(struct bt_ctf_notif_iter *notit)
-{
- return notit->buf.packet_offset + notit->buf.at;
-}
-
-static inline
-size_t remaining_content_bits(struct bt_ctf_notif_iter *notit)
-{
- if (notit->cur_content_size == -1) {
- return -1;
- }
-
- return notit->cur_content_size - packet_at(notit);
-}
-
-static inline
-size_t remaining_packet_bits(struct bt_ctf_notif_iter *notit)
-{
- if (notit->cur_packet_size == -1) {
- return -1;
- }
-
- return notit->cur_packet_size - packet_at(notit);
-}
-
-static inline
-void buf_consume_bits(struct bt_ctf_notif_iter *notit, size_t incr)
-{
- notit->buf.at += incr;
-}
-
-static inline
-bool buf_has_enough_bits(struct bt_ctf_notif_iter *notit, size_t sz)
-{
- return buf_available_bits(notit) >= sz;
-}
-
-static
-enum bt_ctf_notif_iter_status request_medium_bytes(struct bt_ctf_notif_iter *notit)
-{
- uint8_t *buffer_addr;
- size_t buffer_sz;
- enum bt_ctf_notif_iter_medium_status m_status;
-
- m_status = notit->medium.medops.request_bytes(
- notit->medium.max_request_sz, &buffer_addr,
- &buffer_sz, notit->medium.data);
- if (m_status == BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK) {
- assert(buffer_sz != 0);
-
- /* New packet offset is old one + old size (in bits) */
- notit->buf.packet_offset += buf_size_bits(notit);
-
- /* Restart at the beginning of the new medium buffer */
- notit->buf.at = 0;
-
- /* New medium buffer size */
- notit->buf.sz = buffer_sz;
-
- /* New medium buffer address */
- notit->buf.addr = buffer_addr;
- }
-
- return notif_iter_status_from_m_status(m_status);
-}
-
-static inline
-enum bt_ctf_notif_iter_status buf_ensure_available_bits(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
-
- if (buf_available_bits(notit) == 0) {
- /*
- * This _cannot_ return BT_CTF_NOTIF_ITER_STATUS_OK
- * _and_ no bits.
- */
- status = request_medium_bytes(notit);
- }
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_dscope_begin_state(
- struct bt_ctf_notif_iter *notit,
- struct bt_ctf_field_type *dscope_field_type,
- enum state done_state, enum state continue_state,
- struct bt_ctf_field **dscope_field)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- enum bt_ctf_btr_status btr_status;
- size_t consumed_bits;
-
- status = buf_ensure_available_bits(notit);
- if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
- goto end;
- }
-
- bt_put(*dscope_field);
- notit->cur_dscope_field = dscope_field;
- consumed_bits = bt_ctf_btr_start(notit->btr, dscope_field_type,
- notit->buf.addr, notit->buf.at, packet_at(notit),
- notit->buf.sz, &btr_status);
-
- switch (btr_status) {
- case BT_CTF_BTR_STATUS_OK:
- /* type was read completely */
- notit->state = done_state;
- break;
- case BT_CTF_BTR_STATUS_EOF:
- notit->state = continue_state;
- break;
- default:
- PERR("Binary type reader failed to start\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- /* Consume bits now since we know we're not in an error state */
- buf_consume_bits(notit, consumed_bits);
-
-end:
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_dscope_continue_state(
- struct bt_ctf_notif_iter *notit, enum state done_state)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- enum bt_ctf_btr_status btr_status;
- size_t consumed_bits;
-
- status = buf_ensure_available_bits(notit);
- if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
- goto end;
- }
-
- consumed_bits = bt_ctf_btr_continue(notit->btr, notit->buf.addr,
- notit->buf.sz, &btr_status);
-
- switch (btr_status) {
- case BT_CTF_BTR_STATUS_OK:
- /* Type was read completely */
- notit->state = done_state;
- break;
- case BT_CTF_BTR_STATUS_EOF:
- /* Stay in this continue state */
- break;
- default:
- PERR("Binary type reader failed to continue\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- /* Consume bits now since we know we're not in an error state */
- buf_consume_bits(notit, consumed_bits);
-
-end:
- return status;
-}
-
-static
-void put_event_dscopes(struct bt_ctf_notif_iter *notit)
-{
- BT_PUT(notit->dscopes.stream_event_header);
- BT_PUT(notit->dscopes.stream_event_context);
- BT_PUT(notit->dscopes.event_context);
- BT_PUT(notit->dscopes.event_payload);
-}
-
-static
-void put_all_dscopes(struct bt_ctf_notif_iter *notit)
-{
- BT_PUT(notit->dscopes.trace_packet_header);
- BT_PUT(notit->dscopes.stream_packet_context);
- put_event_dscopes(notit);
-}
-
-static
-enum bt_ctf_notif_iter_status read_packet_header_begin_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *packet_header_type;
-
- /* Reset all dynamic scopes since we're reading a new packet */
- put_all_dscopes(notit);
- BT_PUT(notit->packet);
- BT_PUT(notit->meta.stream_class);
- BT_PUT(notit->meta.event_class);
-
- /* Packet header type is common to the whole trace */
- packet_header_type = bt_ctf_trace_get_packet_header_type(
- notit->meta.trace);
- if (!packet_header_type) {
- PERR("Failed to retrieve trace's packet header type\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- status = read_dscope_begin_state(notit, packet_header_type,
- STATE_AFTER_TRACE_PACKET_HEADER,
- STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
- ¬it->dscopes.trace_packet_header);
-
-end:
- BT_PUT(packet_header_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_packet_header_continue_state(
- struct bt_ctf_notif_iter *notit)
-{
- return read_dscope_continue_state(notit,
- STATE_AFTER_TRACE_PACKET_HEADER);
-}
-
-static inline
-bool is_struct_type(struct bt_ctf_field_type *field_type)
-{
- return bt_ctf_field_type_get_type_id(field_type) == BT_CTF_TYPE_ID_STRUCT;
-}
-
-static inline
-bool is_variant_type(struct bt_ctf_field_type *field_type)
-{
- return bt_ctf_field_type_get_type_id(field_type) == BT_CTF_TYPE_ID_VARIANT;
-}
-
-static inline
-enum bt_ctf_notif_iter_status set_current_stream_class(struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *packet_header_type;
- struct bt_ctf_field_type *stream_id_field_type = NULL;
- uint64_t stream_id;
-
- /* Is there any "stream_id" field in the packet header? */
- packet_header_type = bt_ctf_trace_get_packet_header_type(
- notit->meta.trace);
- if (!packet_header_type) {
- PERR("Failed to retrieve trace's packet header type\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- assert(is_struct_type(packet_header_type));
-
- // TODO: optimalize!
- stream_id_field_type =
- bt_ctf_field_type_structure_get_field_type_by_name(
- packet_header_type, "stream_id");
- if (stream_id_field_type) {
- /* Find appropriate stream class using current stream ID */
- struct bt_ctf_field *stream_id_field = NULL;
- int ret;
-
- assert(notit->dscopes.trace_packet_header);
-
- // TODO: optimalize!
- stream_id_field = bt_ctf_field_structure_get_field(
- notit->dscopes.trace_packet_header, "stream_id");
- assert(stream_id_field);
- ret = bt_ctf_field_unsigned_integer_get_value(
- stream_id_field, &stream_id);
- assert(!ret);
- BT_PUT(stream_id_field);
- } else {
- /* Only one stream: pick the first stream class */
- assert(bt_ctf_trace_get_stream_class_count(
- notit->meta.trace) == 1);
- stream_id = 0;
- }
-
- BT_PUT(notit->meta.stream_class);
-
- // TODO: get by ID
- notit->meta.stream_class = bt_ctf_trace_get_stream_class(
- notit->meta.trace, stream_id);
- if (!notit->meta.stream_class) {
- PERR("Cannot find stream class with ID %" PRIu64 "\n",
- stream_id);
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
-end:
- BT_PUT(packet_header_type);
- BT_PUT(stream_id_field_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status after_packet_header_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status;
-
- status = set_current_stream_class(notit);
- if (status == BT_CTF_NOTIF_ITER_STATUS_OK) {
- notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
- }
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_packet_context_begin_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *packet_context_type;
-
- assert(notit->meta.stream_class);
- packet_context_type = bt_ctf_stream_class_get_packet_context_type(
- notit->meta.stream_class);
- if (!packet_context_type) {
- PERR("Failed to retrieve stream class's packet context\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- status = read_dscope_begin_state(notit, packet_context_type,
- STATE_AFTER_STREAM_PACKET_CONTEXT,
- STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
- ¬it->dscopes.stream_packet_context);
-
-end:
- BT_PUT(packet_context_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_packet_context_continue_state(
- struct bt_ctf_notif_iter *notit)
-{
- return read_dscope_continue_state(notit,
- STATE_AFTER_STREAM_PACKET_CONTEXT);
-}
-
-static inline
-enum bt_ctf_notif_iter_status set_current_packet_content_sizes(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field *packet_size_field = NULL;
- struct bt_ctf_field *content_size_field = NULL;
- uint64_t content_size = -1, packet_size = -1;
-
- assert(notit->dscopes.stream_packet_context);
-
- // TODO: optimalize!
- packet_size_field = bt_ctf_field_structure_get_field(
- notit->dscopes.stream_packet_context, "packet_size");
- content_size_field = bt_ctf_field_structure_get_field(
- notit->dscopes.stream_packet_context, "content_size");
- if (packet_size_field) {
- int ret = bt_ctf_field_unsigned_integer_get_value(
- packet_size_field, &packet_size);
- assert(!ret);
-
- if (packet_size == 0) {
- PERR("Decoded packet size is 0\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- } else if ((packet_size % 8) != 0) {
- PERR("Decoded packet size is not a multiple of 8\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
- }
- if (content_size_field) {
- int ret = bt_ctf_field_unsigned_integer_get_value(
- content_size_field, &content_size);
- assert(!ret);
- } else {
- content_size = packet_size;
- }
-
- notit->cur_packet_size = packet_size;
- notit->cur_content_size = content_size;
-
-end:
- BT_PUT(packet_size_field);
- BT_PUT(content_size_field);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status after_packet_context_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status;
-
- status = set_current_packet_content_sizes(notit);
- if (status == BT_CTF_NOTIF_ITER_STATUS_OK) {
- notit->state = STATE_EMIT_NOTIF_NEW_PACKET;
- }
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_event_header_begin_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *event_header_type = NULL;
-
- /* Check if we have some content left */
- if (notit->cur_content_size >= 0) {
- if (packet_at(notit) == notit->cur_content_size) {
- /* No more events! */
- notit->state = STATE_EMIT_NOTIF_END_OF_PACKET;
- goto end;
- } else if (packet_at(notit) > notit->cur_content_size) {
- /* That's not supposed to happen */
- PERR("Cursor passed packet's content size:\n");
- PERR(" Decoded content size: %zu\n",
- notit->cur_content_size);
- PERR(" Cursor position: %zu\n", packet_at(notit));
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
- }
-
- event_header_type = bt_ctf_stream_class_get_event_header_type(
- notit->meta.stream_class);
- if (!event_header_type) {
- PERR("Failed to retrieve stream class's event header type\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- put_event_dscopes(notit);
- status = read_dscope_begin_state(notit, event_header_type,
- STATE_AFTER_STREAM_EVENT_HEADER,
- STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
- ¬it->dscopes.stream_event_header);
-
-end:
- BT_PUT(event_header_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_event_header_continue_state(
- struct bt_ctf_notif_iter *notit)
-{
- return read_dscope_continue_state(notit,
- STATE_AFTER_STREAM_EVENT_HEADER);
-}
-
-static inline
-enum bt_ctf_notif_iter_status set_current_event_class(struct bt_ctf_notif_iter *notit)
-{
- /*
- * The assert() calls in this function are okay because it is
- * assumed here that all the metadata objects have been
- * validated for CTF correctness before decoding actual streams.
- */
-
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *event_header_type;
- struct bt_ctf_field_type *id_field_type = NULL;
- struct bt_ctf_field_type *v_field_type = NULL;
- uint64_t event_id = -1ULL;
- int ret;
-
- event_header_type = bt_ctf_stream_class_get_event_header_type(
- notit->meta.stream_class);
- if (!event_header_type) {
- PERR("Failed to retrieve stream class's event header type\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- /* Is there any "id"/"v" field in the event header? */
- assert(is_struct_type(event_header_type));
- id_field_type = bt_ctf_field_type_structure_get_field_type_by_name(
- event_header_type, "id");
- v_field_type = bt_ctf_field_type_structure_get_field_type_by_name(
- event_header_type, "v");
- assert(notit->dscopes.stream_event_header);
- if (v_field_type) {
- /*
- * _ _____ _____
- * | | |_ _|_ _| __ __ _
- * | | | | | || '_ \ / _` |
- * | |___| | | || | | | (_| | S P E C I A L
- * |_____|_| |_||_| |_|\__, | C A S E ™
- * |___/
- */
- struct bt_ctf_field *v_field = NULL;
- struct bt_ctf_field *v_struct_field = NULL;
- struct bt_ctf_field *v_struct_id_field = NULL;
-
- // TODO: optimalize!
- v_field = bt_ctf_field_structure_get_field(
- notit->dscopes.stream_event_header, "v");
- assert(v_field);
-
- v_struct_field =
- bt_ctf_field_variant_get_current_field(v_field);
- if (!v_struct_field) {
- goto end_v_field_type;
- }
-
- // TODO: optimalize!
- v_struct_id_field =
- bt_ctf_field_structure_get_field(v_struct_field, "id");
- if (!v_struct_id_field) {
- goto end_v_field_type;
- }
-
- ret = bt_ctf_field_unsigned_integer_get_value(
- v_struct_id_field, &event_id);
- if (ret) {
- event_id = -1ULL;
- }
-
-end_v_field_type:
- BT_PUT(v_field);
- BT_PUT(v_struct_field);
- BT_PUT(v_struct_id_field);
- }
-
- if (id_field_type && event_id == -1ULL) {
- /* Check "id" field */
- struct bt_ctf_field *id_field = NULL;
- int ret;
-
- // TODO: optimalize!
- id_field = bt_ctf_field_structure_get_field(
- notit->dscopes.stream_event_header, "id");
- assert(id_field);
- assert(bt_ctf_field_is_integer(id_field) ||
- bt_ctf_field_is_enumeration(id_field));
-
- if (bt_ctf_field_is_integer(id_field)) {
- ret = bt_ctf_field_unsigned_integer_get_value(
- id_field, &event_id);
- } else {
- struct bt_ctf_field *container;
-
- container = bt_ctf_field_enumeration_get_container(
- id_field);
- assert(container);
- ret = bt_ctf_field_unsigned_integer_get_value(
- container, &event_id);
- BT_PUT(container);
- }
- assert(!ret);
- BT_PUT(id_field);
- }
-
- if (event_id == -1ULL) {
- /* Event ID not found: single event? */
- assert(bt_ctf_stream_class_get_event_class_count(
- notit->meta.stream_class) == 1);
- event_id = 0;
- }
-
- BT_PUT(notit->meta.event_class);
- notit->meta.event_class = bt_ctf_stream_class_get_event_class_by_id(
- notit->meta.stream_class, event_id);
- if (!notit->meta.event_class) {
- PERR("Cannot find event class with ID %" PRIu64 "\n", event_id);
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
-end:
- BT_PUT(event_header_type);
- BT_PUT(id_field_type);
- BT_PUT(v_field_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status after_event_header_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status;
-
- status = set_current_packet_content_sizes(notit);
- if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
- PERR("Failed to set current packet and content sizes\n");
- goto end;
- }
-
- status = set_current_event_class(notit);
- if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
- PERR("Failed to set current event class\n");
- goto end;
- }
-
- notit->state = STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN;
-
-end:
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_stream_event_context_begin_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *stream_event_context_type;
-
- stream_event_context_type = bt_ctf_stream_class_get_event_context_type(
- notit->meta.stream_class);
- if (!stream_event_context_type) {
- PERR("Failed to retrieve stream class's event context type\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- status = read_dscope_begin_state(notit, stream_event_context_type,
- STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
- STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
- ¬it->dscopes.stream_event_context);
-
-end:
- BT_PUT(stream_event_context_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_stream_event_context_continue_state(
- struct bt_ctf_notif_iter *notit)
-{
- return read_dscope_continue_state(notit,
- STATE_DSCOPE_EVENT_CONTEXT_BEGIN);
-}
-
-static
-enum bt_ctf_notif_iter_status read_event_context_begin_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *event_context_type;
-
- event_context_type = bt_ctf_event_class_get_context_type(
- notit->meta.event_class);
- if (!event_context_type) {
- PERR("Failed to retrieve event class's context type\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- status = read_dscope_begin_state(notit, event_context_type,
- STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
- STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
- ¬it->dscopes.event_context);
-
-end:
- BT_PUT(event_context_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_event_context_continue_state(
- struct bt_ctf_notif_iter *notit)
-{
- return read_dscope_continue_state(notit,
- STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
-}
-
-static
-enum bt_ctf_notif_iter_status read_event_payload_begin_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- struct bt_ctf_field_type *event_payload_type;
-
- event_payload_type = bt_ctf_event_class_get_payload_type(
- notit->meta.event_class);
- if (!event_payload_type) {
- PERR("Failed to retrieve event class's payload type\n");
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- goto end;
- }
-
- status = read_dscope_begin_state(notit, event_payload_type,
- STATE_EMIT_NOTIF_EVENT,
- STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
- ¬it->dscopes.event_payload);
-
-end:
- BT_PUT(event_payload_type);
-
- return status;
-}
-
-static
-enum bt_ctf_notif_iter_status read_event_payload_continue_state(
- struct bt_ctf_notif_iter *notit)
-{
- return read_dscope_continue_state(notit, STATE_EMIT_NOTIF_EVENT);
-}
-
-static
-enum bt_ctf_notif_iter_status skip_packet_padding_state(
- struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
- size_t bits_to_skip;
-
- assert(notit->cur_packet_size > 0);
- bits_to_skip = notit->cur_packet_size - packet_at(notit);
- if (bits_to_skip == 0) {
- notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
- goto end;
- } else {
- size_t bits_to_consume;
- status = buf_ensure_available_bits(notit);
- if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
- goto end;
- }
-
- bits_to_consume = MIN(buf_available_bits(notit), bits_to_skip);
- buf_consume_bits(notit, bits_to_consume);
- bits_to_skip = notit->cur_packet_size - packet_at(notit);
- if (bits_to_skip == 0) {
- notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
- goto end;
- }
- }
-
-end:
- return status;
-}
-
-static inline
-enum bt_ctf_notif_iter_status handle_state(struct bt_ctf_notif_iter *notit)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
-
- PDBG("Handling state %d\n", notit->state);
-
- // TODO: optimalize!
- switch (notit->state) {
- case STATE_INIT:
- notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
- break;
- case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
- status = read_packet_header_begin_state(notit);
- break;
- case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
- status = read_packet_header_continue_state(notit);
- break;
- case STATE_AFTER_TRACE_PACKET_HEADER:
- status = after_packet_header_state(notit);
- break;
- case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
- status = read_packet_context_begin_state(notit);
- break;
- case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
- status = read_packet_context_continue_state(notit);
- break;
- case STATE_AFTER_STREAM_PACKET_CONTEXT:
- status = after_packet_context_state(notit);
- break;
- case STATE_EMIT_NOTIF_NEW_PACKET:
- notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
- break;
- case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN:
- status = read_event_header_begin_state(notit);
- break;
- case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE:
- status = read_event_header_continue_state(notit);
- break;
- case STATE_AFTER_STREAM_EVENT_HEADER:
- status = after_event_header_state(notit);
- break;
- case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN:
- status = read_stream_event_context_begin_state(notit);
- break;
- case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE:
- status = read_stream_event_context_continue_state(notit);
- break;
- case STATE_DSCOPE_EVENT_CONTEXT_BEGIN:
- status = read_event_context_begin_state(notit);
- break;
- case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE:
- status = read_event_context_continue_state(notit);
- break;
- case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
- status = read_event_payload_begin_state(notit);
- break;
- case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
- status = read_event_payload_continue_state(notit);
- break;
- case STATE_EMIT_NOTIF_EVENT:
- notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
- break;
- case STATE_SKIP_PACKET_PADDING:
- status = skip_packet_padding_state(notit);
- break;
- case STATE_EMIT_NOTIF_END_OF_PACKET:
- notit->state = STATE_SKIP_PACKET_PADDING;
- break;
- }
-
- return status;
-}
-
-void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notit)
-{
- assert(notit);
- stack_clear(notit->stack);
- BT_PUT(notit->meta.stream_class);
- BT_PUT(notit->meta.event_class);
- BT_PUT(notit->packet);
- put_all_dscopes(notit);
- notit->buf.addr = NULL;
- notit->buf.sz = 0;
- notit->buf.at = 0;
- notit->buf.packet_offset = 0;
- notit->state = STATE_INIT;
- notit->cur_content_size = -1;
- notit->cur_packet_size = -1;
-}
-
-static
-struct bt_ctf_field *get_next_field(struct bt_ctf_notif_iter *notit)
-{
- struct bt_ctf_field *next_field = NULL;
- struct bt_ctf_field *base_field;
- struct bt_ctf_field_type *base_type;
- size_t index;
-
- assert(!stack_empty(notit->stack));
- index = stack_top(notit->stack)->index;
- base_field = stack_top(notit->stack)->base;
- base_type = bt_ctf_field_get_type(base_field);
- if (!base_type) {
- PERR("Failed to get base field's type\n");
- goto end;
- }
-
- switch (bt_ctf_field_type_get_type_id(base_type)) {
- case BT_CTF_TYPE_ID_STRUCT:
- next_field = bt_ctf_field_structure_get_field_by_index(
- base_field, index);
- break;
- case BT_CTF_TYPE_ID_ARRAY:
- next_field = bt_ctf_field_array_get_field(base_field, index);
- break;
- case BT_CTF_TYPE_ID_SEQUENCE:
- next_field = bt_ctf_field_sequence_get_field(base_field, index);
- break;
- case BT_CTF_TYPE_ID_VARIANT:
- next_field = bt_ctf_field_variant_get_current_field(base_field);
- break;
- default:
- assert(false);
- break;
- }
-
-end:
- BT_PUT(base_type);
-
- return next_field;
-}
-
-static
-enum bt_ctf_btr_status btr_signed_int_cb(int64_t value,
- struct bt_ctf_field_type *type, void *data)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
- struct bt_ctf_field *field = NULL;
- struct bt_ctf_field *int_field = NULL;
- struct bt_ctf_notif_iter *notit = data;
- int ret;
-
- /* create next field */
- field = get_next_field(notit);
- if (!field) {
- PERR("Failed to get next field (signed int)\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- switch(bt_ctf_field_type_get_type_id(type)) {
- case BT_CTF_TYPE_ID_INTEGER:
- /* Integer field is created field */
- BT_MOVE(int_field, field);
- break;
- case BT_CTF_TYPE_ID_ENUM:
- int_field = bt_ctf_field_enumeration_get_container(field);
- break;
- default:
- break;
- }
-
- if (!int_field) {
- PERR("Failed to get integer field\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- ret = bt_ctf_field_signed_integer_set_value(int_field, value);
- assert(!ret);
- stack_top(notit->stack)->index++;
-
-end:
- BT_PUT(field);
- BT_PUT(int_field);
-
- return status;
-}
-
-static
-enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value,
- struct bt_ctf_field_type *type, void *data)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
- struct bt_ctf_field *field = NULL;
- struct bt_ctf_field *int_field = NULL;
- struct bt_ctf_notif_iter *notit = data;
- int ret;
-
- /* Create next field */
- field = get_next_field(notit);
- if (!field) {
- PERR("Failed to get next field (unsigned int)\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- switch(bt_ctf_field_type_get_type_id(type)) {
- case BT_CTF_TYPE_ID_INTEGER:
- /* Integer field is created field */
- BT_MOVE(int_field, field);
- break;
- case BT_CTF_TYPE_ID_ENUM:
- int_field = bt_ctf_field_enumeration_get_container(field);
- break;
- default:
- break;
- }
-
- if (!int_field) {
- PERR("Failed to get integer field\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- ret = bt_ctf_field_unsigned_integer_set_value(int_field, value);
- assert(!ret);
- stack_top(notit->stack)->index++;
-
-end:
- BT_PUT(field);
- BT_PUT(int_field);
-
- return status;
-}
-
-static
-enum bt_ctf_btr_status btr_floating_point_cb(double value,
- struct bt_ctf_field_type *type, void *data)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
- struct bt_ctf_field *field = NULL;
- struct bt_ctf_notif_iter *notit = data;
- int ret;
-
- /* Create next field */
- field = get_next_field(notit);
- if (!field) {
- PERR("Failed to get next field (floating point number)\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- ret = bt_ctf_field_floating_point_set_value(field, value);
- assert(!ret);
- stack_top(notit->stack)->index++;
-
-end:
- BT_PUT(field);
-
- return status;
-}
-
-static
-enum bt_ctf_btr_status btr_string_begin_cb(
- struct bt_ctf_field_type *type, void *data)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
- struct bt_ctf_field *field = NULL;
- struct bt_ctf_notif_iter *notit = data;
- int ret;
-
- /* Create next field */
- field = get_next_field(notit);
- if (!field) {
- PERR("Failed to get next field (string)\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- /*
- * Push on stack. Not a compound type per se, but we know that only
- * btr_string_cb() may be called between this call and a subsequent
- * call to btr_string_end_cb().
- */
- ret = stack_push(notit->stack, field);
- if (ret) {
- PERR("Failed to push string field onto the stack\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
-end:
- BT_PUT(field);
-
- return status;
-}
-
-static
-enum bt_ctf_btr_status btr_string_cb(const char *value,
- size_t len, struct bt_ctf_field_type *type, void *data)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
- struct bt_ctf_field *field = NULL;
- struct bt_ctf_notif_iter *notit = data;
- int ret;
-
- /* Get string field */
- field = stack_top(notit->stack)->base;
- assert(field);
-
- /* Append current string */
- ret = bt_ctf_field_string_append_len(field, value, len);
- if (ret) {
- PERR("Failed to append a string to a string field\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
-end:
- return status;
-}
-
-static
-enum bt_ctf_btr_status btr_string_end_cb(
- struct bt_ctf_field_type *type, void *data)
-{
- struct bt_ctf_notif_iter *notit = data;
-
- /* Pop string field */
- stack_pop(notit->stack);
-
- /* Go to next field */
- stack_top(notit->stack)->index++;
-
- return BT_CTF_BTR_STATUS_OK;
-}
-
-enum bt_ctf_btr_status btr_compound_begin_cb(
- struct bt_ctf_field_type *type, void *data)
-{
- enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
- struct bt_ctf_notif_iter *notit = data;
- struct bt_ctf_field *field;
- int ret;
-
- /* Create field */
- if (stack_empty(notit->stack)) {
- /* Root: create dynamic scope field */
- *notit->cur_dscope_field = bt_ctf_field_create(type);
- field = *notit->cur_dscope_field;
-
- /*
- * Field will be put at the end of this function
- * (stack_push() will take one reference, but this
- * reference is lost upon the equivalent stack_pop()
- * later), so also get it for our context to own it.
- */
- bt_get(*notit->cur_dscope_field);
- } else {
- field = get_next_field(notit);
- }
-
- if (!field) {
- PERR("Failed to get next field or create dynamic scope field\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
- /* Push field */
- ret = stack_push(notit->stack, field);
- if (ret) {
- PERR("Failed to push compound field onto the stack\n");
- status = BT_CTF_BTR_STATUS_ERROR;
- goto end;
- }
-
-end:
- BT_PUT(field);
-
- return status;
-}
-
-enum bt_ctf_btr_status btr_compound_end_cb(
- struct bt_ctf_field_type *type, void *data)
-{
- struct bt_ctf_notif_iter *notit = data;
-
- assert(!stack_empty(notit->stack));
-
- /* Pop stack */
- stack_pop(notit->stack);
-
- /* If the stack is not empty, increment the base's index */
- if (!stack_empty(notit->stack)) {
- stack_top(notit->stack)->index++;
- }
-
- return BT_CTF_BTR_STATUS_OK;
-}
-
-static
-struct bt_ctf_field *resolve_field(struct bt_ctf_notif_iter *notit,
- struct bt_ctf_field_path *path)
-{
- struct bt_ctf_field *field = NULL;
- unsigned int i;
-
- switch (bt_ctf_field_path_get_root_scope(path)) {
- case BT_CTF_SCOPE_TRACE_PACKET_HEADER:
- field = notit->dscopes.trace_packet_header;
- break;
- case BT_CTF_SCOPE_STREAM_PACKET_CONTEXT:
- field = notit->dscopes.stream_packet_context;
- break;
- case BT_CTF_SCOPE_STREAM_EVENT_HEADER:
- field = notit->dscopes.stream_event_header;
- break;
- case BT_CTF_SCOPE_STREAM_EVENT_CONTEXT:
- field = notit->dscopes.stream_event_context;
- break;
- case BT_CTF_SCOPE_EVENT_CONTEXT:
- field = notit->dscopes.event_context;
- break;
- case BT_CTF_SCOPE_EVENT_FIELDS:
- field = notit->dscopes.event_payload;
- break;
- default:
- break;
- }
-
- if (!field) {
- goto end;
- }
-
- bt_get(field);
-
- for (i = 0; i < bt_ctf_field_path_get_index_count(path); ++i) {
- struct bt_ctf_field *next_field = NULL;
- struct bt_ctf_field_type *field_type;
- int index = bt_ctf_field_path_get_index(path, i);
-
- field_type = bt_ctf_field_get_type(field);
- if (!field_type) {
- BT_PUT(field);
- goto end;
- }
-
- if (is_struct_type(field_type)) {
- next_field = bt_ctf_field_structure_get_field_by_index(
- field, index);
- } else if (is_variant_type(field_type)) {
- next_field =
- bt_ctf_field_variant_get_current_field(field);
- }
-
- BT_PUT(field);
- BT_PUT(field_type);
-
- if (!next_field) {
- goto end;
- }
-
- /* Move next field -> field */
- BT_MOVE(field, next_field);
- }
-
-end:
- return field;
-}
-
-static
-int64_t btr_get_sequence_length_cb(struct bt_ctf_field_type *type, void *data)
-{
- int64_t ret = -1;
- int iret;
- struct bt_ctf_field_path *field_path;
- struct bt_ctf_notif_iter *notit = data;
- struct bt_ctf_field *field = NULL;
- uint64_t length;
-
- field_path = bt_ctf_field_type_sequence_get_length_field_path(type);
- if (!field_path) {
- goto end;
- }
-
- field = resolve_field(notit, field_path);
- if (!field) {
- goto end;
- }
-
- iret = bt_ctf_field_unsigned_integer_get_value(field, &length);
- if (iret) {
- goto end;
- }
-
- ret = (int64_t) length;
-
-end:
- BT_PUT(field);
- BT_PUT(field_path);
-
- return ret;
-}
-
-static
-struct bt_ctf_field_type *btr_get_variant_type_cb(
- struct bt_ctf_field_type *type, void *data)
-{
- struct bt_ctf_field_path *path;
- struct bt_ctf_notif_iter *notit = data;
- struct bt_ctf_field *tag_field = NULL;
- struct bt_ctf_field *selected_field = NULL;
- struct bt_ctf_field_type *selected_field_type = NULL;
-
- path = bt_ctf_field_type_variant_get_tag_field_path(type);
- if (!path) {
- goto end;
- }
-
- tag_field = resolve_field(notit, path);
- if (!tag_field) {
- goto end;
- }
-
- /*
- * We found the enumeration tag field instance which should be
- * able to select a current field for this variant. This
- * callback function we're in is called _after_
- * compound_begin(), so the current stack top's base field is
- * the variant field in question. We get the selected field here
- * thanks to this tag field (thus creating the selected field),
- * which will also provide us with its type. Then, this field
- * will remain the current selected one until the next callback
- * function call which is used to fill the current selected
- * field.
- */
- selected_field = bt_ctf_field_variant_get_field(
- stack_top(notit->stack)->base, tag_field);
- if (!selected_field) {
- goto end;
- }
-
- selected_field_type = bt_ctf_field_get_type(selected_field);
-
-end:
- BT_PUT(tag_field);
- BT_PUT(selected_field);
-
- return selected_field_type;
-}
-
-static struct bt_ctf_event *create_event(struct bt_ctf_notif_iter *notit)
-{
- struct bt_ctf_event *event;
- int ret;
-
- /* Create event object */
- event = bt_ctf_event_create(notit->meta.event_class);
- if (!event) {
- goto error;
- }
-
- /* Set header, stream event context, context, and payload fields */
- ret = bt_ctf_event_set_header(event,
- notit->dscopes.stream_event_header);
- if (ret) {
- goto error;
- }
-
- ret = bt_ctf_event_set_stream_event_context(event,
- notit->dscopes.stream_event_context);
- if (ret) {
- goto error;
- }
-
- ret = bt_ctf_event_set_event_context(event,
- notit->dscopes.event_context);
- if (ret) {
- goto error;
- }
-
- ret = bt_ctf_event_set_payload_field(event,
- notit->dscopes.event_payload);
- if (ret) {
- goto error;
- }
-
- /* Associate with current packet */
- assert(notit->packet);
- ret = bt_ctf_event_set_packet(event, notit->packet);
- if (ret) {
- goto error;
- }
-
- goto end;
-
-error:
- BT_PUT(event);
-
-end:
- return event;
-}
-
-static void create_packet(struct bt_ctf_notif_iter *notit)
-{
- int ret;
- struct bt_ctf_stream *stream = NULL;
- struct bt_ctf_packet *packet = NULL;
-
- /* Ask the user for the stream */
- stream = notit->medium.medops.get_stream(notit->meta.stream_class,
- notit->medium.data);
- if (!stream) {
- goto error;
- }
-
- /* Create packet */
- packet = bt_ctf_packet_create(stream);
- if (!packet) {
- goto error;
- }
-
- /* Set packet's context and header fields */
- if (notit->dscopes.trace_packet_header) {
- ret = bt_ctf_packet_set_header(packet,
- notit->dscopes.trace_packet_header);
- if (ret) {
- goto error;
- }
- }
-
- if (notit->dscopes.stream_packet_context) {
- ret = bt_ctf_packet_set_context(packet,
- notit->dscopes.stream_packet_context);
- if (ret) {
- goto error;
- }
- }
-
- goto end;
-
-error:
- BT_PUT(packet);
-
-end:
- BT_MOVE(notit->packet, packet);
-}
-
-static void notify_new_packet(struct bt_ctf_notif_iter *notit,
- struct bt_ctf_notif_iter_notif **notification)
-{
- struct bt_ctf_notif_iter_notif_new_packet *rnotif;
-
- rnotif = g_new0(struct bt_ctf_notif_iter_notif_new_packet, 1);
- if (!rnotif) {
- goto error;
- }
-
- rnotif->base.type = BT_CTF_NOTIF_ITER_NOTIF_NEW_PACKET;
-
- /* Create packet */
- create_packet(notit);
- if (!notit->packet) {
- goto error;
- }
-
- rnotif->packet = bt_get(notit->packet);
- *notification = (struct bt_ctf_notif_iter_notif *) rnotif;
- return;
-
-error:
- bt_ctf_notif_iter_notif_destroy(rnotif);
-}
-
-static void notify_end_of_packet(struct bt_ctf_notif_iter *notit,
- struct bt_ctf_notif_iter_notif **notification)
-{
- struct bt_ctf_notif_iter_notif_end_of_packet *rnotif;
-
- rnotif = g_new0(struct bt_ctf_notif_iter_notif_end_of_packet, 1);
- if (!rnotif) {
- goto error;
- }
-
- rnotif->base.type = BT_CTF_NOTIF_ITER_NOTIF_END_OF_PACKET;
-
- /* Create packet */
- create_packet(notit);
- if (!notit->packet) {
- goto error;
- }
-
- rnotif->packet = bt_get(notit->packet);
- *notification = (struct bt_ctf_notif_iter_notif *) rnotif;
- return;
-
-error:
- bt_ctf_notif_iter_notif_destroy(rnotif);
-}
-
-static void notify_event(struct bt_ctf_notif_iter *notit,
- struct bt_ctf_notif_iter_notif **notification)
-{
- struct bt_ctf_notif_iter_notif_event *rnotif;
- struct bt_ctf_event *event = NULL;
-
- rnotif = g_new0(struct bt_ctf_notif_iter_notif_event, 1);
- if (!rnotif) {
- goto error;
- }
-
- rnotif->base.type = BT_CTF_NOTIF_ITER_NOTIF_EVENT;
-
- /* Create event */
- event = create_event(notit);
- if (!event) {
- goto error;
- }
-
- BT_MOVE(rnotif->event, event);
- *notification = (struct bt_ctf_notif_iter_notif *) rnotif;
- return;
-
-error:
- BT_PUT(event);
- bt_ctf_notif_iter_notif_destroy(rnotif);
-}
-
-void bt_ctf_notif_iter_notif_destroy(void *vnotif)
-{
- struct bt_ctf_notif_iter_notif *notif = vnotif;
-
- switch (notif->type) {
- case BT_CTF_NOTIF_ITER_NOTIF_NEW_PACKET:
- {
- struct bt_ctf_notif_iter_notif_new_packet *rnotif =
- (struct bt_ctf_notif_iter_notif_new_packet *) notif;
-
- BT_PUT(rnotif->packet);
- break;
- }
- case BT_CTF_NOTIF_ITER_NOTIF_END_OF_PACKET:
- {
- struct bt_ctf_notif_iter_notif_end_of_packet *rnotif =
- (struct bt_ctf_notif_iter_notif_end_of_packet *) notif;
-
- BT_PUT(rnotif->packet);
- break;
- }
- case BT_CTF_NOTIF_ITER_NOTIF_EVENT:
- {
- struct bt_ctf_notif_iter_notif_event *rnotif =
- (struct bt_ctf_notif_iter_notif_event *) notif;
-
- BT_PUT(rnotif->event);
- break;
- }
- default:
- assert(false);
- }
-
- g_free(notif);
-}
-
-struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
- size_t max_request_sz,
- struct bt_ctf_notif_iter_medium_ops medops,
- void *data, FILE *err_stream)
-{
- struct bt_ctf_notif_iter *notit = NULL;
- struct bt_ctf_btr_cbs cbs = {
- .types = {
- .signed_int = btr_signed_int_cb,
- .unsigned_int = btr_unsigned_int_cb,
- .floating_point = btr_floating_point_cb,
- .string_begin = btr_string_begin_cb,
- .string = btr_string_cb,
- .string_end = btr_string_end_cb,
- .compound_begin = btr_compound_begin_cb,
- .compound_end = btr_compound_end_cb,
- },
- .query = {
- .get_sequence_length = btr_get_sequence_length_cb,
- .get_variant_type = btr_get_variant_type_cb,
- },
- };
-
- assert(trace);
- assert(medops.request_bytes);
- notit = g_new0(struct bt_ctf_notif_iter, 1);
- if (!notit) {
- PERR("Failed to allocate memory for CTF notification iterator\n");
- goto end;
- }
-
- notit->meta.trace = trace;
- bt_get(notit->meta.trace);
- notit->medium.medops = medops;
- notit->medium.max_request_sz = max_request_sz;
- notit->medium.data = data;
- notit->err_stream = err_stream;
- notit->stack = stack_new(notit);
- if (!notit->stack) {
- PERR("Failed to create stack\n");
- bt_ctf_notif_iter_destroy(notit);
- notit = NULL;
- goto end;
- }
-
- notit->btr = bt_ctf_btr_create(cbs, notit, err_stream);
- if (!notit->btr) {
- PERR("Failed to create binary type reader\n");
- bt_ctf_notif_iter_destroy(notit);
- notit = NULL;
- goto end;
- }
-
- bt_ctf_notif_iter_reset(notit);
-
-end:
- return notit;
-}
-
-void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notit)
-{
- BT_PUT(notit->meta.trace);
- BT_PUT(notit->meta.stream_class);
- BT_PUT(notit->meta.event_class);
- BT_PUT(notit->packet);
- put_all_dscopes(notit);
-
- if (notit->stack) {
- stack_destroy(notit->stack);
- }
-
- if (notit->btr) {
- bt_ctf_btr_destroy(notit->btr);
- }
-
- g_free(notit);
-}
-
-enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification(
- struct bt_ctf_notif_iter *notit,
- struct bt_ctf_notif_iter_notif **notification)
-{
- enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
-
- assert(notit);
- assert(notification);
-
- while (true) {
- status = handle_state(notit);
- if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
- if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
- PDBG("Medium operation reported end of file\n");
- } else {
- PERR("Failed to handle state:\n");
- PERR(" State: %d\n", notit->state);
- }
- goto end;
- }
-
- switch (notit->state) {
- case STATE_EMIT_NOTIF_NEW_PACKET:
- PDBG("Emitting new packet notification\n");
- notify_new_packet(notit, notification);
- if (!*notification) {
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- }
- goto end;
- case STATE_EMIT_NOTIF_EVENT:
- PDBG("Emitting event notification\n");
- notify_event(notit, notification);
- if (!*notification) {
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- }
- goto end;
- case STATE_EMIT_NOTIF_END_OF_PACKET:
- PDBG("Emitting end of packet notification\n");
- notify_end_of_packet(notit, notification);
- if (!*notification) {
- status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
- }
- goto end;
- default:
- /* Non-emitting state: continue */
- break;
- }
- }
-
-end:
- return status;
-}
+++ /dev/null
-#ifndef CTF_NOTIF_ITER_H
-#define CTF_NOTIF_ITER_H
-
-/*
- * Babeltrace - CTF notification iterator
- * ¯¯¯¯¯ ¯¯¯¯
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <babeltrace/ctf-ir/trace.h>
-#include <babeltrace/ctf-ir/fields.h>
-#include <babeltrace/ctf-ir/event.h>
-#include <babeltrace/babeltrace-internal.h>
-
-/**
- * @file ctf-notif-iter.h
- *
- * CTF notification iterator
- * ¯¯¯¯¯ ¯¯¯¯
- * This is a common internal API used by CTF source plugins. It allows
- * one to get notifications from a user-provided medium.
- */
-
-/**
- * Medium operations status codes.
- */
-enum bt_ctf_notif_iter_medium_status {
- /**
- * End of file.
- *
- * The medium function called by the notification iterator
- * function reached the end of the file.
- */
- BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF = -4,
-
- /**
- * There is no data available right now, try again later.
- */
- BT_CTF_NOTIF_ITER_MEDIUM_STATUS_AGAIN = -3,
-
- /** Invalid argument. */
- BT_CTF_NOTIF_ITER_MEDIUM_STATUS_INVAL = -2,
-
- /** General error. */
- BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR = -1,
-
- /** Everything okay. */
- BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK = 0,
-};
-
-/**
- * CTF notification iterator API status code.
- */
-enum bt_ctf_notif_iter_status {
- /**
- * End of file.
- *
- * The medium function called by the notification iterator
- * function reached the end of the file.
- */
- BT_CTF_NOTIF_ITER_STATUS_EOF = -4,
-
- /**
- * There is no data available right now, try again later.
- *
- * Some condition resulted in the
- * bt_ctf_notif_iter_medium_ops::request_bytes() user function not
- * having access to any data now. You should retry calling the
- * last called notification iterator function once the situation
- * is resolved.
- */
- BT_CTF_NOTIF_ITER_STATUS_AGAIN = -3,
-
- /** Invalid argument. */
- BT_CTF_NOTIF_ITER_STATUS_INVAL = -2,
-
- /** General error. */
- BT_CTF_NOTIF_ITER_STATUS_ERROR = -1,
-
- /** Everything okay. */
- BT_CTF_NOTIF_ITER_STATUS_OK = 0,
-};
-
-/**
- * Medium operations.
- *
- * Those user functions are called by the notification iterator
- * functions to request medium actions.
- */
-struct bt_ctf_notif_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 notification 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 notification iterator functions. The
- * returned buffer won't be modified by the notification
- * 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:
- *
- * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK</b>: 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.
- * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_AGAIN</b>: No data is
- * available right now. In this case, the notification
- * iterator function called by the user returns
- * #BT_CTF_NOTIF_ITER_STATUS_AGAIN, and it is the user's
- * responsibility to make sure enough data becomes available
- * before calling the \em same notification iterator
- * function again to continue the decoding process.
- * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF</b>: The end of
- * the file was reached, and no more data will ever be
- * available for this file. In this case, the notification
- * iterator function called by the user returns
- * #BT_CTF_NOTIF_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
- * #BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF on the \em following
- * call.
- * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR</b>: A fatal
- * error occured during this operation. In this case, the
- * notification iterator function called by the user returns
- * #BT_CTF_NOTIF_ITER_STATUS_ERROR.
- *
- * If #BT_CTF_NOTIF_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 bt_ctf_notif_iter_medium_status (* request_bytes)(
- size_t request_sz, uint8_t **buffer_addr,
- size_t *buffer_sz, 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 notification
- * iterator.
- *
- * @param stream_class Stream class associated to the stream
- * @param data User data
- * @returns Stream instance (weak reference) or
- * \c NULL on error
- */
- struct bt_ctf_stream * (* get_stream)(
- struct bt_ctf_stream_class *stream_class, void *data);
-};
-
-/** CTF notification iterator. */
-struct bt_ctf_notif_iter;
-
-// TODO: Replace by the real thing
-enum bt_ctf_notif_iter_notif_type {
- BT_CTF_NOTIF_ITER_NOTIF_NEW_PACKET,
- BT_CTF_NOTIF_ITER_NOTIF_END_OF_PACKET,
- BT_CTF_NOTIF_ITER_NOTIF_EVENT,
-};
-
-struct bt_ctf_notif_iter_notif {
- enum bt_ctf_notif_iter_notif_type type;
-};
-
-struct bt_ctf_notif_iter_notif_new_packet {
- struct bt_ctf_notif_iter_notif base;
- struct bt_ctf_packet *packet;
-};
-
-struct bt_ctf_notif_iter_notif_end_of_packet {
- struct bt_ctf_notif_iter_notif base;
- struct bt_ctf_packet *packet;
-};
-
-struct bt_ctf_notif_iter_notif_event {
- struct bt_ctf_notif_iter_notif base;
- struct bt_ctf_event *event;
-};
-
-void bt_ctf_notif_iter_notif_destroy(void *notif);
-
-/**
- * Creates a CTF notification 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
- * bt_ctf_notif_iter_medium_ops::request_bytes()
- * at a time
- * @param medops Medium operations
- * @param medops_data User data (passed to medium operations)
- * @param err_stream Error stream (can be \c NULL to disable)
- * @returns New CTF notification iterator on
- * success, or \c NULL on error
- */
-struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
- size_t max_request_sz, struct bt_ctf_notif_iter_medium_ops medops,
- void *medops_data, FILE *err_stream);
-
-/**
- * Destroys a CTF notification iterator, freeing all internal resources.
- *
- * The registered trace's reference count is decremented.
- *
- * @param notif_iter CTF notification iterator
- */
-void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notif_iter);
-
-/**
- * Resets the internal state of a CTF notification iterator.
- *
- * This function can be used when it is desired to seek to the beginning
- * of another packet. It is expected that the next call to
- * bt_ctf_notif_iter_medium_ops::request_bytes() made by this
- * notification iterator will return the \em first bytes of a \em
- * packet.
- *
- * @param notif_iter CTF notification iterator
- */
-void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notif_iter);
-
-/**
- * Returns the next notification from a CTF notification iterator.
- *
- * Upon successful completion, #BT_CTF_NOTIF_ITER_STATUS_OK is
- * returned, and the next notification is written to \p notif.
- * In this case, the caller is responsible for calling
- * bt_notification_put() on the returned notification.
- *
- * If this function returns #BT_CTF_NOTIF_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 notif_iter CTF notification iterator
- * @param notification Returned notification if the function's
- * return value is #BT_CTF_NOTIF_ITER_STATUS_OK
- * @returns One of #bt_ctf_notif_iter_status values
- */
-enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification(
- struct bt_ctf_notif_iter *notif_iter,
- struct bt_ctf_notif_iter_notif **notification);
-
-#endif /* CTF_NOTIF_ITER_H */
+++ /dev/null
-#ifndef CTF_NOTIF_ITER_PRINT_H
-#define CTF_NOTIF_ITER_PRINT_H
-
-/*
- * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <babeltrace/babeltrace-internal.h>
-
-#define PERR(fmt, ...) \
- do { \
- if (PRINT_ERR_STREAM) { \
- fprintf(PRINT_ERR_STREAM, \
- "Error: " PRINT_PREFIX ": " fmt, \
- ##__VA_ARGS__); \
- } \
- } while (0)
-
-#define PWARN(fmt, ...) \
- do { \
- if (PRINT_ERR_STREAM) { \
- fprintf(PRINT_ERR_STREAM, \
- "Warning: " PRINT_PREFIX ": " fmt, \
- ##__VA_ARGS__); \
- } \
- } while (0)
-
-#define PDBG(fmt, ...) \
- do { \
- if (babeltrace_debug) { \
- fprintf(stderr, \
- "Debug: " PRINT_PREFIX ": " fmt, \
- ##__VA_ARGS__); \
- } \
- } while (0)
-
-#endif /* CTF_NOTIF_ITER_PRINT_H */
+++ /dev/null
-AM_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir)/include -I$(srcdir)
-AM_CFLAGS = $(PACKAGE_CFLAGS)
-BUILT_SOURCES = ctf-parser.h ctf-parser.c ctf-lexer.c
-AM_YFLAGS = -t -d -v
-
-noinst_LTLIBRARIES = libctf-parser.la libctf-ast.la
-
-noinst_HEADERS = \
- ctf-scanner.h \
- ctf-ast.h \
- ctf-scanner-symbols.h
-
-libctf_parser_la_SOURCES = ctf-lexer.l ctf-parser.y objstack.c
-# ctf-scanner-symbols.h is included to prefix generated yy_* symbols
-# with bt_.
-libctf_parser_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir) \
- -include $(srcdir)/ctf-scanner-symbols.h
-
-libctf_ast_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)
-libctf_ast_la_SOURCES = \
- ctf-visitor-generate-ir.c \
- ctf-visitor-semantic-validator.c \
- ctf-visitor-parent-links.c
-libctf_ast_la_LIBADD = $(top_builddir)/lib/libbabeltrace.la
-
-if BABELTRACE_BUILD_WITH_LIBUUID
-libctf_ast_la_LIBADD += -luuid
-endif
-
-if BABELTRACE_BUILD_WITH_LIBC_UUID
-libctf_ast_la_LIBADD += -lc
-endif
-
-if BABELTRACE_BUILD_WITH_MINGW
-libctf_ast_la_LIBADD += -lrpcrt4 -lintl -liconv -lole32 -lpopt
-endif
-
-CLEANFILES = $(BUILT_SOURCES) ctf-parser.output
+++ /dev/null
-#ifndef _CTF_AST_H
-#define _CTF_AST_H
-
-/*
- * ctf-ast.h
- *
- * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace/list.h>
-#include <babeltrace/ctf-ir/trace.h>
-
-// 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;
-
-#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
- NR_NODE_TYPES,
-};
-
-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, typedef,
- * typealias and type_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, typedef,
- * typealias and type_specifier_list.
- */
- struct bt_list_head declaration_list;
- } event;
- struct {
- /*
- * Children nodes are ctf_expression, typedef,
- * typealias and type_specifier_list.
- */
- struct bt_list_head declaration_list;
- } stream;
- struct {
- /*
- * Children nodes are ctf_expression, typedef,
- * typealias and type_specifier_list.
- */
- struct bt_list_head declaration_list;
- } env;
- struct {
- /*
- * Children nodes are ctf_expression, typedef,
- * typealias and type_specifier_list.
- */
- struct bt_list_head declaration_list;
- } trace;
- struct {
- /*
- * Children nodes are ctf_expression, typedef,
- * typealias and type_specifier_list.
- */
- struct bt_list_head declaration_list;
- } clock;
- struct {
- /*
- * Children nodes are ctf_expression, typedef,
- * typealias and type_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 {
- enum {
- UNARY_UNKNOWN = 0,
- UNARY_STRING,
- UNARY_SIGNED_CONSTANT,
- UNARY_UNSIGNED_CONSTANT,
- UNARY_SBRAC,
- } 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;
- enum {
- UNARY_LINK_UNKNOWN = 0,
- UNARY_DOTLINK,
- UNARY_ARROWLINK,
- UNARY_DOTDOTDOT,
- } link;
- } unary_expression;
- struct {
- struct ctf_node *type_specifier_list;
- struct bt_list_head type_declarators;
- } _typedef;
- /* new type is "alias", existing type "target" */
- struct {
- struct ctf_node *type_specifier_list;
- struct bt_list_head type_declarators;
- } typealias_target;
- struct {
- struct ctf_node *type_specifier_list;
- struct bt_list_head type_declarators;
- } typealias_alias;
- struct {
- struct ctf_node *target;
- struct ctf_node *alias;
- } typealias;
- struct {
- enum {
- 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,
- } type;
- /* For struct, variant and enum */
- struct ctf_node *node;
- const char *id_type;
- } type_specifier;
- struct {
- /* list of type_specifier */
- struct bt_list_head head;
- } type_specifier_list;
- struct {
- unsigned int const_qualifier;
- } pointer;
- struct {
- struct bt_list_head pointers;
- enum {
- TYPEDEC_UNKNOWN = 0,
- TYPEDEC_ID, /* identifier */
- TYPEDEC_NESTED, /* (), array or sequence */
- } type;
- union {
- char *id;
- struct {
- /* typedec has no pointer list */
- struct ctf_node *type_declarator;
- /*
- * unary expression (value) or
- * type_specifier_list.
- */
- struct bt_list_head length;
- /* for abstract type declarator */
- unsigned int abstract_array;
- } nested;
- } u;
- struct ctf_node *bitfield_len;
- } type_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
- * type_specifier_list.
- */
- struct ctf_node *container_type;
- struct bt_list_head enumerator_list;
- int has_body;
- } _enum;
- struct {
- struct ctf_node *type_specifier_list;
- struct bt_list_head type_declarators;
- } struct_or_variant_declaration;
- struct {
- char *name;
- char *choice;
- /* list of typedef, typealias and declarations */
- struct bt_list_head declaration_list;
- int has_body;
- } variant;
- struct {
- char *name;
- /* list of typedef, typealias 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 ctf_trace;
-
-BT_HIDDEN
-int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
- struct bt_ctf_trace **trace);
-
-BT_HIDDEN
-int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node);
-
-BT_HIDDEN
-int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node);
-
-BT_HIDDEN
-int ctf_destroy_metadata(struct ctf_trace *trace);
-
-#endif /* _CTF_AST_H */
+++ /dev/null
-%{
-/*
- * ctf-lexer.l
- *
- * Common Trace Formal Lexer
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <babeltrace/babeltrace-internal.h>
-#include "ctf-scanner.h"
-#include "ctf-parser.h"
-#include "ctf-ast.h"
-
-#define PARSE_INTEGER_LITERAL(base) \
- do { \
- errno = 0; \
- yylval->ull = strtoull(yytext, NULL, base); \
- if (errno) { \
- printfl_perror(yylineno, "Integer literal"); \
- return ERROR; \
- } \
- } while (0)
-
-BT_HIDDEN
-void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src);
-
-static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
- __attribute__((unused));
-static int input (yyscan_t yyscanner) __attribute__((unused));
-
-BT_HIDDEN
-int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim);
-
-%}
-
-%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);
-<comment_ml>[^*\n]* /* eat anything that's not a '*' */
-<comment_ml>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
-<comment_ml>\n
-<comment_ml>"*"+"/" BEGIN(INITIAL);
-
-"//"[^\n]*\n /* skip comment */
-
-L?\"(\\.|[^\\"])*\" { if (import_string(yyextra, yylval, yytext, '\"') < 0) return ERROR; else return STRING_LITERAL; }
-L?\'(\\.|[^\\'])*\' { if (import_string(yyextra, yylval, yytext, '\'') < 0) return ERROR; else return CHARACTER_LITERAL; }
-
-"[" return LSBRAC;
-"]" return RSBRAC;
-"(" return LPAREN;
-")" return RPAREN;
-"{" return LBRAC;
-"}" return RBRAC;
-"->" return RARROW;
-"*" return STAR;
-"+" return PLUS;
-"-" return MINUS;
-"<" return LT;
-">" return GT;
-:= return TYPEASSIGN;
-: return COLON;
-; return SEMICOLON;
-"..." return DOTDOTDOT;
-"." return DOT;
-= return EQUAL;
-"," return COMMA;
-align setstring(yyextra, yylval, yytext); return TOK_ALIGN;
-const setstring(yyextra, yylval, yytext); return CONST;
-char setstring(yyextra, yylval, yytext); return CHAR;
-clock setstring(yyextra, yylval, yytext); return CLOCK;
-double setstring(yyextra, yylval, yytext); return DOUBLE;
-enum setstring(yyextra, yylval, yytext); return ENUM;
-env setstring(yyextra, yylval, yytext); return ENV;
-event setstring(yyextra, yylval, yytext); return EVENT;
-floating_point setstring(yyextra, yylval, yytext); return FLOATING_POINT;
-float setstring(yyextra, yylval, yytext); return FLOAT;
-integer setstring(yyextra, yylval, yytext); return INTEGER;
-int setstring(yyextra, yylval, yytext); return INT;
-long setstring(yyextra, yylval, yytext); return LONG;
-short setstring(yyextra, yylval, yytext); return SHORT;
-signed setstring(yyextra, yylval, yytext); return SIGNED;
-stream setstring(yyextra, yylval, yytext); return STREAM;
-string setstring(yyextra, yylval, yytext); return STRING;
-struct setstring(yyextra, yylval, yytext); return STRUCT;
-trace setstring(yyextra, yylval, yytext); return TRACE;
-callsite setstring(yyextra, yylval, yytext); return CALLSITE;
-typealias setstring(yyextra, yylval, yytext); return TYPEALIAS;
-typedef setstring(yyextra, yylval, yytext); return TYPEDEF;
-unsigned setstring(yyextra, yylval, yytext); return UNSIGNED;
-variant setstring(yyextra, yylval, yytext); return VARIANT;
-void setstring(yyextra, yylval, yytext); return VOID;
-_Bool setstring(yyextra, yylval, yytext); return _BOOL;
-_Complex setstring(yyextra, yylval, yytext); return _COMPLEX;
-_Imaginary setstring(yyextra, yylval, yytext); return _IMAGINARY;
-[1-9]{DIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(10); return INTEGER_LITERAL;
-0{OCTALDIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(8); return INTEGER_LITERAL;
-0[xX]{HEXDIGIT}+{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(16); return INTEGER_LITERAL;
-
-{IDENTIFIER} printf_debug("<IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); if (is_type(yyextra, yytext)) return ID_TYPE; else return IDENTIFIER;
-[ \t\r\n] ; /* ignore */
-. printfl_error(yylineno, "invalid character '0x%02X'", yytext[0]); return ERROR;
-%%
+++ /dev/null
-%{
-/*
- * ctf-parser.y
- *
- * Common Trace Format Metadata Grammar.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <glib.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <babeltrace/list.h>
-#include <babeltrace/babeltrace-internal.h>
-#include "ctf-scanner.h"
-#include "ctf-parser.h"
-#include "ctf-ast.h"
-#include "objstack.h"
-
-BT_HIDDEN
-int yydebug;
-
-/* 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;
- }
-}
-
-BT_HIDDEN
-int yyparse(struct ctf_scanner *scanner, yyscan_t yyscanner);
-BT_HIDDEN
-int yylex(union YYSTYPE *yyval, yyscan_t yyscanner);
-BT_HIDDEN
-int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals);
-BT_HIDDEN
-int yylex_destroy(yyscan_t yyscanner);
-BT_HIDDEN
-void yyrestart(FILE * in_str, yyscan_t yyscanner);
-BT_HIDDEN
-int yyget_lineno(yyscan_t yyscanner);
-BT_HIDDEN
-char *yyget_text(yyscan_t yyscanner);
-
-static const char *node_type_to_str[] = {
-#define ENTRY(S) [S] = #S,
- FOREACH_CTF_NODES(ENTRY)
-#undef ENTRY
-};
-
-/*
- * 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 = {
- .type = NODE_ERROR,
-};
-
-BT_HIDDEN
-const char *node_type(struct ctf_node *node)
-{
- if (node->type < NR_NODE_TYPES)
- return node_type_to_str[node->type];
- else
- return NULL;
-}
-
-void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src)
-{
- lvalp->s = 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;
- }
- }
- assert(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 = objstack_alloc(scanner->objstack, len);
- if (src[0] == 'L') {
- // TODO: import wide string
- printfl_error(yyget_lineno(scanner),
- "Wide string not supported yet.");
- 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->types = 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->types);
-}
-
-static void push_scope(struct ctf_scanner *scanner)
-{
- struct ctf_scanner_scope *ns;
-
- printf_debug("push scope\n");
- ns = 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;
-
- printf_debug("pop scope\n");
- 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 = (int) (long) g_hash_table_lookup(s->types, id);
- printf_debug("lookup %p %s %d\n", s, id, ret);
- return ret;
-}
-
-BT_HIDDEN
-int is_type(struct ctf_scanner *scanner, const char *id)
-{
- struct ctf_scanner_scope *it;
- int ret = 0;
-
- for (it = scanner->cs; it != NULL; it = it->parent) {
- if (lookup_type(it, id)) {
- ret = 1;
- break;
- }
- }
- printf_debug("is type %s %d\n", id, ret);
- return ret;
-}
-
-static void add_type(struct ctf_scanner *scanner, char *id)
-{
- printf_debug("add type %s\n", id);
- if (lookup_type(scanner->cs, id))
- return;
- g_hash_table_insert(scanner->cs->types, id, id);
-}
-
-static struct ctf_node *make_node(struct ctf_scanner *scanner,
- enum node_type type)
-{
- struct ctf_node *node;
-
- node = objstack_alloc(scanner->objstack, sizeof(*node));
- if (!node) {
- printfl_fatal(yyget_lineno(scanner->scanner), "out of memory");
- 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;
- printfn_fatal(node, "trying to create root node");
- 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._typedef.type_declarators);
- break;
- case NODE_TYPEALIAS_TARGET:
- BT_INIT_LIST_HEAD(&node->u.typealias_target.type_declarators);
- break;
- case NODE_TYPEALIAS_ALIAS:
- BT_INIT_LIST_HEAD(&node->u.typealias_alias.type_declarators);
- break;
- case NODE_TYPEALIAS:
- break;
-
- case NODE_TYPE_SPECIFIER:
- break;
- case NODE_TYPE_SPECIFIER_LIST:
- BT_INIT_LIST_HEAD(&node->u.type_specifier_list.head);
- break;
- case NODE_POINTER:
- break;
- case NODE_TYPE_DECLARATOR:
- BT_INIT_LIST_HEAD(&node->u.type_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.type_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;
- printfn_fatal(node, "unknown node type '%d'", (int) 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:
- printfn_fatal(node, "unknown node type '%d'", (int) 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:
- printfn_fatal(node, "unknown node type %d", parent->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static int reparent_typealias(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:
- printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static int reparent_type_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.type_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:
- printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static int reparent_type_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._typedef.type_specifier_list = node;
- break;
- case NODE_TYPEALIAS_TARGET:
- parent->u.typealias_target.type_specifier_list = node;
- break;
- case NODE_TYPEALIAS_ALIAS:
- parent->u.typealias_alias.type_specifier_list = node;
- break;
- case NODE_ENUM:
- parent->u._enum.container_type = node;
- break;
- case NODE_STRUCT_OR_VARIANT_DECLARATION:
- parent->u.struct_or_variant_declaration.type_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:
- printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static int reparent_type_declarator(struct ctf_node *node,
- struct ctf_node *parent)
-{
- switch (parent->type) {
- case NODE_TYPE_DECLARATOR:
- parent->u.type_declarator.type = TYPEDEC_NESTED;
- parent->u.type_declarator.u.nested.type_declarator = node;
- break;
- case NODE_STRUCT_OR_VARIANT_DECLARATION:
- _bt_list_splice_tail(&node->tmp_head, &parent->u.struct_or_variant_declaration.type_declarators);
- break;
- case NODE_TYPEDEF:
- _bt_list_splice_tail(&node->tmp_head, &parent->u._typedef.type_declarators);
- break;
- case NODE_TYPEALIAS_TARGET:
- _bt_list_splice_tail(&node->tmp_head, &parent->u.typealias_target.type_declarators);
- break;
- case NODE_TYPEALIAS_ALIAS:
- _bt_list_splice_tail(&node->tmp_head, &parent->u.typealias_alias.type_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:
- printfn_fatal(node, "unknown node type '%d'", (int) 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:
- printfn_fatal(node, "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.type_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.typealias.target = node;
- else
- return -EINVAL;
- case NODE_TYPEALIAS_ALIAS:
- if (parent->type == NODE_TYPEALIAS)
- parent->u.typealias.alias = node;
- else
- return -EINVAL;
- case NODE_TYPEALIAS:
- return reparent_typealias(node, parent);
-
- case NODE_POINTER:
- if (parent->type == NODE_TYPE_DECLARATOR) {
- _bt_list_splice_tail(&node->tmp_head, &parent->u.type_declarator.pointers);
- } else
- return -EPERM;
- break;
- case NODE_TYPE_DECLARATOR:
- return reparent_type_declarator(node, parent);
-
- case NODE_TYPE_SPECIFIER_LIST:
- return reparent_type_specifier_list(node, parent);
-
- case NODE_TYPE_SPECIFIER:
- return reparent_type_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:
- printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
- return -EINVAL;
- }
- return 0;
-}
-
-BT_HIDDEN
-void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str)
-{
- printfl_error(yyget_lineno(scanner->scanner),
- "token \"%s\": %s\n",
- yyget_text(scanner->scanner), str);
-}
-
-BT_HIDDEN
-int yywrap(void)
-{
- return 1;
-}
-
-#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 = 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);
- if (yydebug)
- fprintf(stdout, "Scanner input is a%s.\n",
- isatty(fileno(input)) ? "n interactive tty" :
- " noninteractive file");
- return yyparse(scanner, scanner->scanner);
-}
-
-struct ctf_scanner *ctf_scanner_alloc(void)
-{
- struct ctf_scanner *scanner;
- int ret;
-
- yydebug = babeltrace_debug;
-
- scanner = malloc(sizeof(*scanner));
- if (!scanner)
- return NULL;
- memset(scanner, 0, sizeof(*scanner));
- ret = yylex_init_extra(scanner, &scanner->scanner);
- if (ret) {
- printf_fatal("yylex_init error");
- 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)
- printf_fatal("yylex_destroy error");
-cleanup_scanner:
- free(scanner);
- return NULL;
-}
-
-void ctf_scanner_free(struct ctf_scanner *scanner)
-{
- int ret;
-
- if (!scanner)
- return;
- finalize_scope(&scanner->root_scope);
- objstack_destroy(scanner->objstack);
- ret = yylex_destroy(scanner->scanner);
- if (ret)
- printf_error("yylex_destroy error");
- free(scanner);
-}
-
-%}
-
-%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 INTEGER_LITERAL STRING_LITERAL CHARACTER_LITERAL LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW STAR PLUS MINUS LT GT TYPEASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA CONST CHAR DOUBLE ENUM ENV EVENT FLOATING_POINT FLOAT INTEGER INT LONG SHORT SIGNED STREAM STRING STRUCT TRACE CALLSITE CLOCK TYPEALIAS TYPEDEF UNSIGNED VARIANT VOID _BOOL _COMPLEX _IMAGINARY TOK_ALIGN
-%token <s> IDENTIFIER ID_TYPE
-%token ERROR
-%union
-{
- long long ll;
- unsigned long long ull;
- char c;
- char *s;
- struct ctf_node *n;
-}
-
-%type <s> STRING_LITERAL CHARACTER_LITERAL
-
-%type <s> keywords
-
-%type <ull> INTEGER_LITERAL
-%type <n> postfix_expression unary_expression unary_expression_or_range
-
-%type <n> declaration
-%type <n> event_declaration
-%type <n> stream_declaration
-%type <n> env_declaration
-%type <n> trace_declaration
-%type <n> clock_declaration
-%type <n> callsite_declaration
-%type <n> integer_declaration_specifiers
-%type <n> declaration_specifiers
-%type <n> alias_declaration_specifiers
-
-%type <n> type_declarator_list
-%type <n> integer_type_specifier
-%type <n> type_specifier
-%type <n> struct_type_specifier
-%type <n> variant_type_specifier
-%type <n> enum_type_specifier
-%type <n> struct_or_variant_declaration_list
-%type <n> struct_or_variant_declaration
-%type <n> struct_or_variant_declarator_list
-%type <n> struct_or_variant_declarator
-%type <n> enumerator_list
-%type <n> enumerator
-%type <n> abstract_declarator_list
-%type <n> abstract_declarator
-%type <n> direct_abstract_declarator
-%type <n> alias_abstract_declarator_list
-%type <n> alias_abstract_declarator
-%type <n> direct_alias_abstract_declarator
-%type <n> declarator
-%type <n> direct_declarator
-%type <n> type_declarator
-%type <n> direct_type_declarator
-%type <n> pointer
-%type <n> ctf_assignment_expression_list
-%type <n> 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:
- VOID
- { $$ = yylval.s; }
- | CHAR
- { $$ = yylval.s; }
- | SHORT
- { $$ = yylval.s; }
- | INT
- { $$ = yylval.s; }
- | LONG
- { $$ = yylval.s; }
- | FLOAT
- { $$ = yylval.s; }
- | DOUBLE
- { $$ = yylval.s; }
- | SIGNED
- { $$ = yylval.s; }
- | UNSIGNED
- { $$ = yylval.s; }
- | _BOOL
- { $$ = yylval.s; }
- | _COMPLEX
- { $$ = yylval.s; }
- | _IMAGINARY
- { $$ = yylval.s; }
- | FLOATING_POINT
- { $$ = yylval.s; }
- | INTEGER
- { $$ = yylval.s; }
- | STRING
- { $$ = yylval.s; }
- | ENUM
- { $$ = yylval.s; }
- | VARIANT
- { $$ = yylval.s; }
- | STRUCT
- { $$ = yylval.s; }
- | CONST
- { $$ = yylval.s; }
- | TYPEDEF
- { $$ = yylval.s; }
- | EVENT
- { $$ = yylval.s; }
- | STREAM
- { $$ = yylval.s; }
- | ENV
- { $$ = yylval.s; }
- | TRACE
- { $$ = yylval.s; }
- | CLOCK
- { $$ = yylval.s; }
- | CALLSITE
- { $$ = yylval.s; }
- | 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;
- }
- | INTEGER_LITERAL
- {
- $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
- $$->u.unary_expression.type = UNARY_UNSIGNED_CONSTANT;
- $$->u.unary_expression.u.unsigned_constant = $1;
- }
- | STRING_LITERAL
- {
- $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
- $$->u.unary_expression.type = UNARY_STRING;
- $$->u.unary_expression.u.string = $1;
- }
- | CHARACTER_LITERAL
- {
- $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
- $$->u.unary_expression.type = UNARY_STRING;
- $$->u.unary_expression.u.string = $1;
- }
- | LPAREN unary_expression RPAREN
- {
- $$ = $2;
- }
- | postfix_expression LSBRAC unary_expression 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 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 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 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 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 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; }
- | 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");
- }
- }
- | 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_UNSIGNED_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 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 SEMICOLON
- { $$ = $1; }
- | event_declaration
- { $$ = $1; }
- | stream_declaration
- { $$ = $1; }
- | env_declaration
- { $$ = $1; }
- | trace_declaration
- { $$ = $1; }
- | clock_declaration
- { $$ = $1; }
- | callsite_declaration
- { $$ = $1; }
- | declaration_specifiers TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEDEF);
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u._typedef.type_specifier_list = list;
- _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEDEF);
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u._typedef.type_specifier_list = list;
- _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | declaration_specifiers TYPEDEF type_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEDEF);
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u._typedef.type_specifier_list = list;
- _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | TYPEALIAS declaration_specifiers abstract_declarator_list TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEALIAS);
- $$->u.typealias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
- $$->u.typealias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u.typealias.target->u.typealias_target.type_specifier_list = list;
- _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.typealias.target->u.typealias_target.type_declarators);
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u.typealias.alias->u.typealias_alias.type_specifier_list = list;
- _bt_list_splice_tail(&($5)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.typealias.alias->u.typealias_alias.type_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:
- EVENT LBRAC
- { push_scope(scanner); }
- ;
-
-event_declaration_end:
- RBRAC 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:
- STREAM LBRAC
- { push_scope(scanner); }
- ;
-
-stream_declaration_end:
- RBRAC 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:
- ENV LBRAC
- { push_scope(scanner); }
- ;
-
-env_declaration_end:
- RBRAC 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:
- TRACE LBRAC
- { push_scope(scanner); }
- ;
-
-trace_declaration_end:
- RBRAC SEMICOLON
- { pop_scope(scanner); }
- ;
-
-clock_declaration:
- CLOCK clock_declaration_begin clock_declaration_end
- {
- $$ = make_node(scanner, NODE_CLOCK);
- }
- | 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:
- LBRAC
- { push_scope(scanner); }
- ;
-
-clock_declaration_end:
- RBRAC SEMICOLON
- { pop_scope(scanner); }
- ;
-
-callsite_declaration:
- CALLSITE callsite_declaration_begin callsite_declaration_end
- {
- $$ = make_node(scanner, NODE_CALLSITE);
- }
- | 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:
- LBRAC
- { push_scope(scanner); }
- ;
-
-callsite_declaration_end:
- RBRAC SEMICOLON
- { pop_scope(scanner); }
- ;
-
-integer_declaration_specifiers:
- CONST
- {
- struct ctf_node *node;
-
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- node = make_node(scanner, NODE_TYPE_SPECIFIER);
- node->u.type_specifier.type = TYPESPEC_CONST;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | integer_type_specifier
- {
- struct ctf_node *node;
-
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- node = $1;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | integer_declaration_specifiers CONST
- {
- struct ctf_node *node;
-
- $$ = $1;
- node = make_node(scanner, NODE_TYPE_SPECIFIER);
- node->u.type_specifier.type = TYPESPEC_CONST;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | integer_declaration_specifiers integer_type_specifier
- {
- $$ = $1;
- bt_list_add_tail(&($2)->siblings, &($$)->u.type_specifier_list.head);
- }
- ;
-
-declaration_specifiers:
- CONST
- {
- struct ctf_node *node;
-
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- node = make_node(scanner, NODE_TYPE_SPECIFIER);
- node->u.type_specifier.type = TYPESPEC_CONST;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | type_specifier
- {
- struct ctf_node *node;
-
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- node = $1;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | declaration_specifiers CONST
- {
- struct ctf_node *node;
-
- $$ = $1;
- node = make_node(scanner, NODE_TYPE_SPECIFIER);
- node->u.type_specifier.type = TYPESPEC_CONST;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | declaration_specifiers type_specifier
- {
- $$ = $1;
- bt_list_add_tail(&($2)->siblings, &($$)->u.type_specifier_list.head);
- }
- ;
-
-type_declarator_list:
- type_declarator
- { $$ = $1; }
- | type_declarator_list COMMA type_declarator
- {
- $$ = $1;
- bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
- }
- ;
-
-integer_type_specifier:
- CHAR
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_CHAR;
- }
- | SHORT
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_SHORT;
- }
- | INT
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_INT;
- }
- | LONG
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_LONG;
- }
- | SIGNED
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_SIGNED;
- }
- | UNSIGNED
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_UNSIGNED;
- }
- | _BOOL
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_BOOL;
- }
- | ID_TYPE
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_ID_TYPE;
- $$->u.type_specifier.id_type = yylval.s;
- }
- | INTEGER LBRAC RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_INTEGER;
- $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
- }
- | INTEGER LBRAC ctf_assignment_expression_list RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_INTEGER;
- $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
- if (set_parent_node($3, $$->u.type_specifier.node))
- reparent_error(scanner, "integer reparent error");
- }
- ;
-
-type_specifier:
- VOID
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_VOID;
- }
- | CHAR
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_CHAR;
- }
- | SHORT
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_SHORT;
- }
- | INT
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_INT;
- }
- | LONG
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_LONG;
- }
- | FLOAT
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_FLOAT;
- }
- | DOUBLE
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_DOUBLE;
- }
- | SIGNED
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_SIGNED;
- }
- | UNSIGNED
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_UNSIGNED;
- }
- | _BOOL
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_BOOL;
- }
- | _COMPLEX
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_COMPLEX;
- }
- | _IMAGINARY
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_IMAGINARY;
- }
- | ID_TYPE
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_ID_TYPE;
- $$->u.type_specifier.id_type = yylval.s;
- }
- | FLOATING_POINT LBRAC RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_FLOATING_POINT;
- $$->u.type_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
- }
- | FLOATING_POINT LBRAC ctf_assignment_expression_list RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_FLOATING_POINT;
- $$->u.type_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
- if (set_parent_node($3, $$->u.type_specifier.node))
- reparent_error(scanner, "floating point reparent error");
- }
- | INTEGER LBRAC RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_INTEGER;
- $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
- }
- | INTEGER LBRAC ctf_assignment_expression_list RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_INTEGER;
- $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
- if (set_parent_node($3, $$->u.type_specifier.node))
- reparent_error(scanner, "integer reparent error");
- }
- | STRING
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_STRING;
- $$->u.type_specifier.node = make_node(scanner, NODE_STRING);
- }
- | STRING LBRAC RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_STRING;
- $$->u.type_specifier.node = make_node(scanner, NODE_STRING);
- }
- | STRING LBRAC ctf_assignment_expression_list RBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_STRING;
- $$->u.type_specifier.node = make_node(scanner, NODE_STRING);
- if (set_parent_node($3, $$->u.type_specifier.node))
- reparent_error(scanner, "string reparent error");
- }
- | ENUM enum_type_specifier
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_ENUM;
- $$->u.type_specifier.node = $2;
- }
- | VARIANT variant_type_specifier
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_VARIANT;
- $$->u.type_specifier.node = $2;
- }
- | STRUCT struct_type_specifier
- {
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
- $$->u.type_specifier.type = TYPESPEC_STRUCT;
- $$->u.type_specifier.node = $2;
- }
- ;
-
-struct_type_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 TOK_ALIGN LPAREN unary_expression 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 TOK_ALIGN LPAREN unary_expression 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 TOK_ALIGN LPAREN unary_expression 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:
- LBRAC
- { push_scope(scanner); }
- ;
-
-struct_declaration_end:
- RBRAC
- { pop_scope(scanner); }
- ;
-
-variant_type_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");
- }
- | LT IDENTIFIER 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");
- }
- | LT ID_TYPE 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 LT IDENTIFIER 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 LT IDENTIFIER GT
- {
- $$ = make_node(scanner, NODE_VARIANT);
- $$->u.variant.has_body = 0;
- $$->u.variant.name = $1;
- $$->u.variant.choice = $3;
- }
- | IDENTIFIER LT ID_TYPE 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 LT ID_TYPE 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 LT IDENTIFIER 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 LT IDENTIFIER GT
- {
- $$ = make_node(scanner, NODE_VARIANT);
- $$->u.variant.has_body = 0;
- $$->u.variant.name = $1;
- $$->u.variant.choice = $3;
- }
- | ID_TYPE LT ID_TYPE 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 LT ID_TYPE GT
- {
- $$ = make_node(scanner, NODE_VARIANT);
- $$->u.variant.has_body = 0;
- $$->u.variant.name = $1;
- $$->u.variant.choice = $3;
- }
- ;
-
-variant_declaration_begin:
- LBRAC
- { push_scope(scanner); }
- ;
-
-variant_declaration_end:
- RBRAC
- { pop_scope(scanner); }
- ;
-
-enum_type_specifier:
- LBRAC enumerator_list RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
- }
- | COLON integer_declaration_specifiers LBRAC enumerator_list RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- ($$)->u._enum.container_type = $2;
- _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
- }
- | IDENTIFIER LBRAC enumerator_list 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 COLON integer_declaration_specifiers LBRAC enumerator_list RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- $$->u._enum.enum_id = $1;
- ($$)->u._enum.container_type = $3;
- _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
- }
- | ID_TYPE LBRAC enumerator_list 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 COLON integer_declaration_specifiers LBRAC enumerator_list RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- $$->u._enum.enum_id = $1;
- ($$)->u._enum.container_type = $3;
- _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
- }
- | LBRAC enumerator_list COMMA RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
- }
- | COLON integer_declaration_specifiers LBRAC enumerator_list COMMA RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- ($$)->u._enum.container_type = $2;
- _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
- }
- | IDENTIFIER LBRAC enumerator_list COMMA 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 COLON integer_declaration_specifiers LBRAC enumerator_list COMMA RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- $$->u._enum.enum_id = $1;
- ($$)->u._enum.container_type = $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 LBRAC enumerator_list COMMA 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 COLON integer_declaration_specifiers LBRAC enumerator_list COMMA RBRAC
- {
- $$ = make_node(scanner, NODE_ENUM);
- $$->u._enum.has_body = 1;
- $$->u._enum.enum_id = $1;
- ($$)->u._enum.container_type = $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 SEMICOLON
- {
- struct ctf_node *list;
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- $$ = make_node(scanner, NODE_STRUCT_OR_VARIANT_DECLARATION);
- ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
- _bt_list_splice_tail(&($2)->tmp_head, &($$)->u.struct_or_variant_declaration.type_declarators);
- }
- | declaration_specifiers TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEDEF);
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u._typedef.type_specifier_list = list;
- _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEDEF);
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u._typedef.type_specifier_list = list;
- _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | declaration_specifiers TYPEDEF type_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- $$ = make_node(scanner, NODE_TYPEDEF);
- ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | TYPEALIAS declaration_specifiers abstract_declarator_list TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list SEMICOLON
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEALIAS);
- $$->u.typealias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
- $$->u.typealias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u.typealias.target->u.typealias_target.type_specifier_list = list;
- _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.typealias.target->u.typealias_target.type_declarators);
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u.typealias.alias->u.typealias_alias.type_specifier_list = list;
- _bt_list_splice_tail(&($5)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.typealias.alias->u.typealias_alias.type_declarators);
- }
- ;
-
-alias_declaration_specifiers:
- CONST
- {
- struct ctf_node *node;
-
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- node = make_node(scanner, NODE_TYPE_SPECIFIER);
- node->u.type_specifier.type = TYPESPEC_CONST;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | type_specifier
- {
- struct ctf_node *node;
-
- $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- node = $1;
- bt_list_add_tail(&node->siblings, &($$)->u.type_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.type_specifier.type = TYPESPEC_ID_TYPE;
- node->u.type_specifier.id_type = yylval.s;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | alias_declaration_specifiers CONST
- {
- struct ctf_node *node;
-
- $$ = $1;
- node = make_node(scanner, NODE_TYPE_SPECIFIER);
- node->u.type_specifier.type = TYPESPEC_CONST;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- | alias_declaration_specifiers type_specifier
- {
- $$ = $1;
- bt_list_add_tail(&($2)->siblings, &($$)->u.type_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.type_specifier.type = TYPESPEC_ID_TYPE;
- node->u.type_specifier.id_type = yylval.s;
- bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
- }
- ;
-
-struct_or_variant_declarator_list:
- struct_or_variant_declarator
- { $$ = $1; }
- | struct_or_variant_declarator_list COMMA struct_or_variant_declarator
- {
- $$ = $1;
- bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
- }
- ;
-
-struct_or_variant_declarator:
- declarator
- { $$ = $1; }
- | COLON unary_expression
- { $$ = $2; }
- | declarator COLON unary_expression
- {
- $$ = $1;
- if (set_parent_node($3, $1))
- reparent_error(scanner, "struct_or_variant_declarator");
- }
- ;
-
-enumerator_list:
- enumerator
- { $$ = $1; }
- | enumerator_list 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;
- }
- | STRING_LITERAL
- {
- $$ = make_node(scanner, NODE_ENUMERATOR);
- $$->u.enumerator.id = $1;
- }
- | IDENTIFIER 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 EQUAL unary_expression_or_range
- {
- $$ = make_node(scanner, NODE_ENUMERATOR);
- $$->u.enumerator.id = $1;
- bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
- }
- | keywords EQUAL unary_expression_or_range
- {
- $$ = make_node(scanner, NODE_ENUMERATOR);
- $$->u.enumerator.id = $1;
- bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
- }
- | STRING_LITERAL 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 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.type_declarator.pointers);
- }
- ;
-
-direct_abstract_declarator:
- /* empty */
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_ID;
- /* id is NULL */
- }
- | IDENTIFIER
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_ID;
- $$->u.type_declarator.u.id = $1;
- }
- | LPAREN abstract_declarator RPAREN
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $2;
- }
- | direct_abstract_declarator LSBRAC unary_expression RSBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $1;
- BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
- }
- | direct_abstract_declarator LSBRAC RSBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $1;
- $$->u.type_declarator.u.nested.abstract_array = 1;
- }
- ;
-
-alias_abstract_declarator_list:
- alias_abstract_declarator
- { $$ = $1; }
- | alias_abstract_declarator_list 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.type_declarator.pointers);
- }
- ;
-
-direct_alias_abstract_declarator:
- /* empty */
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_ID;
- /* id is NULL */
- }
- | LPAREN alias_abstract_declarator RPAREN
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $2;
- }
- | direct_alias_abstract_declarator LSBRAC unary_expression RSBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $1;
- BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
- }
- | direct_alias_abstract_declarator LSBRAC RSBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $1;
- $$->u.type_declarator.u.nested.abstract_array = 1;
- }
- ;
-
-declarator:
- direct_declarator
- { $$ = $1; }
- | pointer direct_declarator
- {
- $$ = $2;
- bt_list_splice(&($1)->tmp_head, &($$)->u.type_declarator.pointers);
- }
- ;
-
-direct_declarator:
- IDENTIFIER
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_ID;
- $$->u.type_declarator.u.id = $1;
- }
- | LPAREN declarator RPAREN
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $2;
- }
- | direct_declarator LSBRAC unary_expression RSBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $1;
- BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
- }
- ;
-
-type_declarator:
- direct_type_declarator
- { $$ = $1; }
- | pointer direct_type_declarator
- {
- $$ = $2;
- bt_list_splice(&($1)->tmp_head, &($$)->u.type_declarator.pointers);
- }
- ;
-
-direct_type_declarator:
- IDENTIFIER
- {
- add_type(scanner, $1);
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_ID;
- $$->u.type_declarator.u.id = $1;
- }
- | LPAREN type_declarator RPAREN
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $2;
- }
- | direct_type_declarator LSBRAC unary_expression RSBRAC
- {
- $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
- $$->u.type_declarator.type = TYPEDEC_NESTED;
- $$->u.type_declarator.u.nested.type_declarator = $1;
- BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
- }
- ;
-
-pointer:
- STAR
- {
- $$ = make_node(scanner, NODE_POINTER);
- }
- | STAR pointer
- {
- $$ = make_node(scanner, NODE_POINTER);
- bt_list_splice(&($2)->tmp_head, &($$)->tmp_head);
- }
- | 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 */
- CONST
- | type_qualifier_list CONST
- ;
-
-/* 2.3: CTF-specific declarations */
-
-ctf_assignment_expression_list:
- ctf_assignment_expression SEMICOLON
- { $$ = $1; }
- | ctf_assignment_expression_list ctf_assignment_expression SEMICOLON
- {
- $$ = $1;
- bt_list_add_tail(&($2)->siblings, &($$)->tmp_head);
- }
- ;
-
-ctf_assignment_expression:
- unary_expression 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 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 TYPEDEF declaration_specifiers type_declarator_list
- {
- struct ctf_node *list;
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- $$ = make_node(scanner, NODE_TYPEDEF);
- ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
- _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | TYPEDEF declaration_specifiers type_declarator_list
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEDEF);
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u._typedef.type_specifier_list = list;
- _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | declaration_specifiers TYPEDEF type_declarator_list
- {
- struct ctf_node *list;
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- $$ = make_node(scanner, NODE_TYPEDEF);
- ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
- }
- | TYPEALIAS declaration_specifiers abstract_declarator_list TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list
- {
- struct ctf_node *list;
-
- $$ = make_node(scanner, NODE_TYPEALIAS);
- $$->u.typealias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
- $$->u.typealias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u.typealias.target->u.typealias_target.type_specifier_list = list;
- _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.typealias.target->u.typealias_target.type_declarators);
-
- list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
- $$->u.typealias.alias->u.typealias_alias.type_specifier_list = list;
- _bt_list_splice_tail(&($5)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
- _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.typealias.alias->u.typealias_alias.type_declarators);
- }
- ;
+++ /dev/null
-#ifndef _CTF_SCANNER_SYMBOLS
-#define _CTF_SCANNER_SYMBOLS
-
-/*
- * ctf-scanner-symbols.h
- *
- * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#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 */
+++ /dev/null
-#ifndef _CTF_SCANNER_H
-#define _CTF_SCANNER_H
-
-/*
- * ctf-scanner.h
- *
- * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <stdio.h>
-#include "ctf-ast.h"
-
-#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 *types;
-};
-
-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;
-}
-
-BT_HIDDEN
-int is_type(struct ctf_scanner *scanner, const char *id);
-
-#endif /* _CTF_SCANNER_H */
+++ /dev/null
-/*
- * ctf-visitor-generate-ir.c
- *
- * Common Trace Format metadata visitor (generates CTF IR objects).
- *
- * Based on older ctf-visitor-generate-io-struct.c.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright 2015-2016 - Philippe Proulx <philippe.proulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <assert.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <babeltrace/ctf/metadata.h>
-#include <babeltrace/compat/uuid.h>
-#include <babeltrace/endian.h>
-#include <babeltrace/ref.h>
-#include <babeltrace/ctf/events-internal.h>
-#include <babeltrace/ctf-ir/trace.h>
-#include <babeltrace/ctf-ir/stream-class.h>
-#include <babeltrace/ctf-ir/event.h>
-#include <babeltrace/ctf-ir/event-class.h>
-#include <babeltrace/ctf-ir/field-types.h>
-#include <babeltrace/ctf-ir/field-types-internal.h>
-#include <babeltrace/ctf-ir/clock.h>
-
-#include "ctf-scanner.h"
-#include "ctf-parser.h"
-#include "ctf-ast.h"
-
-/* 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))
-
-/* 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_LOGLEVEL_SET = _BV(4),
- _EVENT_CONTEXT_SET = _BV(5),
- _EVENT_FIELDS_SET = _BV(6),
-};
-
-/* Prefixes of type 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, _type, _member) \
- bt_list_entry((_ptr)->next, _type, _member)
-
-#define _BT_CTF_FIELD_TYPE_INIT(_name) struct bt_ctf_field_type *_name = NULL;
-
-/* Error printing wrappers */
-#define _PERROR(_fmt, ...) \
- do { \
- fprintf(ctx->efd, "[error] %s: " _fmt "\n", \
- __func__, __VA_ARGS__); \
- } while (0)
-
-#define _PWARNING(_fmt, ...) \
- do { \
- fprintf(ctx->efd, "[warning] %s: " _fmt "\n", \
- __func__, __VA_ARGS__); \
- } while (0)
-
-#define _FPERROR(_stream, _fmt, ...) \
- do { \
- fprintf(_stream, "[error] %s: " _fmt "\n", \
- __func__, __VA_ARGS__); \
- } while (0)
-
-#define _FPWARNING(_stream, _fmt, ...) \
- do { \
- fprintf(_stream, "[warning] %s: " _fmt "\n", \
- __func__, __VA_ARGS__); \
- } while (0)
-
-#define _PERROR_DUP_ATTR(_attr, _entity) \
- do { \
- fprintf(ctx->efd, \
- "[error] %s: duplicate attribute \"" \
- _attr "\" in " _entity "\n", __func__); \
- } while (0)
-
-/*
- * 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 type.
- *
- * GQuark -> struct bt_ctf_field_type *
- */
- GHashTable *decl_map;
-
- /* Parent scope; NULL if this is the root declaration scope */
- struct ctx_decl_scope *parent_scope;
-};
-
-/*
- * Visitor context.
- */
-struct ctx {
- /* Trace being filled (weak ref.) */
- struct bt_ctf_trace *trace;
-
- /* Error stream to use during visit */
- FILE *efd;
-
- /* Current declaration scope (top of the stack) */
- struct ctx_decl_scope *current_scope;
-
- /* 1 if trace declaration is visited */
- int is_trace_visited;
-
- /* Trace attributes */
- uint64_t trace_major;
- uint64_t trace_minor;
- unsigned char trace_uuid[BABELTRACE_UUID_LEN];
-
- /*
- * Stream IDs to stream classes.
- *
- * int64_t -> struct bt_ctf_stream_class *
- */
- GHashTable *stream_classes;
-};
-
-/**
- * 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 ctx_decl_scope *par_scope)
-{
- struct ctx_decl_scope *scope;
-
- scope = g_new(struct ctx_decl_scope, 1);
- if (!scope) {
- goto end;
- }
-
- scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, (GDestroyNotify) bt_ctf_field_type_put);
- 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)
-{
- GQuark qname = 0;
-
- assert(name);
-
- /* Prefix character + original string + '\0' */
- char *prname = g_new(char, strlen(name) + 2);
- if (!prname) {
- goto end;
- }
-
- sprintf(prname, "%c%s", prefix, name);
- qname = g_quark_from_string(prname);
- g_free(prname);
-
-end:
- return qname;
-}
-
-/**
- * Looks up a prefixed type alias within a declaration scope.
- *
- * @param scope Declaration scope
- * @param prefix Prefix character
- * @param name Alias name
- * @param level Number of levels to dig (-1 means infinite)
- * @returns Declaration, or NULL if not found
- */
-static
-struct bt_ctf_field_type *ctx_decl_scope_lookup_prefix_alias(
- struct ctx_decl_scope *scope, char prefix,
- const char *name, int levels)
-{
- GQuark qname = 0;
- int cur_levels = 0;
- _BT_CTF_FIELD_TYPE_INIT(decl);
- struct ctx_decl_scope *cur_scope = scope;
-
- assert(scope);
- assert(name);
- qname = get_prefixed_named_quark(prefix, name);
- if (!qname) {
- goto error;
- }
-
- if (levels < 0) {
- levels = INT_MAX;
- }
-
- while (cur_scope && cur_levels < levels) {
- decl = g_hash_table_lookup(cur_scope->decl_map,
- (gconstpointer) (unsigned long) qname);
- if (decl) {
- /* Caller's reference */
- bt_get(decl);
- break;
- }
-
- cur_scope = cur_scope->parent_scope;
- cur_levels++;
- }
-
- return decl;
-
-error:
- return NULL;
-}
-
-/**
- * Looks up a type alias within a declaration scope.
- *
- * @param scope Declaration scope
- * @param name Alias name
- * @param level Number of levels to dig (-1 means infinite)
- * @returns Declaration, or NULL if not found
- */
-static
-struct bt_ctf_field_type *ctx_decl_scope_lookup_alias(
- struct ctx_decl_scope *scope, const char *name, int levels)
-{
- return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS,
- name, levels);
-}
-
-/**
- * Looks up an enumeration within a declaration scope.
- *
- * @param scope Declaration scope
- * @param name Enumeration name
- * @param level Number of levels to dig (-1 means infinite)
- * @returns Declaration, or NULL if not found
- */
-static
-struct bt_ctf_field_type *ctx_decl_scope_lookup_enum(
- struct ctx_decl_scope *scope, const char *name, int levels)
-{
- return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM,
- name, levels);
-}
-
-/**
- * Looks up a structure within a declaration scope.
- *
- * @param scope Declaration scope
- * @param name Structure name
- * @param level Number of levels to dig (-1 means infinite)
- * @returns Declaration, or NULL if not found
- */
-static
-struct bt_ctf_field_type *ctx_decl_scope_lookup_struct(
- struct ctx_decl_scope *scope, const char *name, int levels)
-{
- return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_STRUCT,
- name, levels);
-}
-
-/**
- * Looks up a variant within a declaration scope.
- *
- * @param scope Declaration scope
- * @param name Variant name
- * @param level Number of levels to dig (-1 means infinite)
- * @returns Declaration, or NULL if not found
- */
-static
-struct bt_ctf_field_type *ctx_decl_scope_lookup_variant(
- struct ctx_decl_scope *scope, const char *name, int levels)
-{
- return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_VARIANT,
- name, levels);
-}
-
-/**
- * Registers a prefixed type alias within a declaration scope.
- *
- * @param scope Declaration scope
- * @param prefix Prefix character
- * @param name Alias name (non-NULL)
- * @param decl Declaration to register
- * @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 bt_ctf_field_type *decl)
-{
- int ret = 0;
- GQuark qname = 0;
- _BT_CTF_FIELD_TYPE_INIT(edecl);
-
- assert(scope);
- assert(name);
- assert(decl);
- qname = get_prefixed_named_quark(prefix, name);
- if (!qname) {
- ret = -ENOMEM;
- goto error;
- }
-
- /* Make sure alias does not exist in local scope */
- edecl = ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1);
- if (edecl) {
- BT_PUT(edecl);
- ret = -EEXIST;
- goto error;
- }
-
- g_hash_table_insert(scope->decl_map,
- (gpointer) (unsigned long) qname, decl);
-
- /* Hash table's reference */
- bt_get(decl);
-
- return 0;
-
-error:
- return ret;
-}
-
-/**
- * Registers a type alias within a declaration scope.
- *
- * @param scope Declaration scope
- * @param name Alias name (non-NULL)
- * @param decl Declaration to register
- * @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 bt_ctf_field_type *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 declaration to register
- * @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 bt_ctf_field_type *decl)
-{
- return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM,
- name, decl);
-}
-
-/**
- * Registers a structure declaration within a declaration scope.
- *
- * @param scope Declaration scope
- * @param name Structure name (non-NULL)
- * @param decl Structure declaration to register
- * @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 bt_ctf_field_type *decl)
-{
- return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT,
- name, decl);
-}
-
-/**
- * Registers a variant declaration within a declaration scope.
- *
- * @param scope Declaration scope
- * @param name Variant name (non-NULL)
- * @param decl Variant declaration 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 bt_ctf_field_type *decl)
-{
- return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT,
- name, decl);
-}
-
-/**
- * Creates a new visitor context.
- *
- * @param trace Associated trace
- * @param efd Error stream
- * @returns New visitor context, or NULL on error
- */
-static
-struct ctx *ctx_create(struct bt_ctf_trace *trace, FILE *efd)
-{
- struct ctx *ctx = NULL;
- struct ctx_decl_scope *scope = NULL;
-
- ctx = g_new(struct ctx, 1);
- if (!ctx) {
- goto error;
- }
-
- /* Root declaration scope */
- scope = ctx_decl_scope_create(NULL);
- if (!scope) {
- goto error;
- }
-
- ctx->stream_classes = g_hash_table_new_full(g_direct_hash,
- g_direct_equal, NULL, (GDestroyNotify) bt_put);
- if (!ctx->stream_classes) {
- goto error;
- }
-
- ctx->trace = trace;
- ctx->efd = efd;
- ctx->current_scope = scope;
- ctx->is_trace_visited = FALSE;
-
- return ctx;
-
-error:
- g_free(ctx);
- ctx_decl_scope_destroy(scope);
-
- return NULL;
-}
-
-/**
- * Destroys a visitor context.
- *
- * @param ctx Visitor context to destroy
- */
-static
-void ctx_destroy(struct ctx *ctx)
-{
- struct ctx_decl_scope *scope;
- /*
- * Destroy all scopes, from current one to the root scope.
- */
-
- if (!ctx) {
- goto end;
- }
-
- scope = ctx->current_scope;
-
- while (scope) {
- struct ctx_decl_scope *parent_scope = scope->parent_scope;
-
- ctx_decl_scope_destroy(scope);
- scope = parent_scope;
- }
-
- g_hash_table_destroy(ctx->stream_classes);
- g_free(ctx);
-
-end:
- return;
-}
-
-/**
- * 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 ctx *ctx)
-{
- int ret = 0;
- struct ctx_decl_scope *new_scope;
-
- assert(ctx);
- new_scope = ctx_decl_scope_create(ctx->current_scope);
- if (!new_scope) {
- ret = -ENOMEM;
- goto end;
- }
-
- ctx->current_scope = new_scope;
-
-end:
- return ret;
-}
-
-static
-void ctx_pop_scope(struct ctx *ctx)
-{
- struct ctx_decl_scope *parent_scope = NULL;
-
- 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_type_specifier_list(struct ctx *ctx, struct ctf_node *ts_list,
- struct bt_ctf_field_type **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
-char *concatenate_unary_strings(struct bt_list_head *head)
-{
- int i = 0;
- GString *str;
- struct ctf_node *node;
-
- str = g_string_new(NULL);
-
- 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);
-}
-
-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 bt_list_head *head, uint64_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_link != UNARY_LINK_UNKNOWN || i != 0;
- if (cond) {
- 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_UNSIGNED_CONSTANT &&
- uexpr_type != UNARY_SIGNED_CONSTANT) ||
- uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
- if (cond) {
- ret = -EINVAL;
- goto end;
- }
-
- switch (node->u.unary_expression.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 bt_list_head *head, unsigned char *uuid)
-{
- 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_parse(src_string, uuid);
- if (ret) {
- goto end;
- }
- }
-
-end:
- return ret;
-}
-
-static
-int get_boolean(FILE *efd, struct ctf_node *unary_expr)
-{
- int ret = 0;
-
- if (unary_expr->type != NODE_UNARY_EXPRESSION) {
- _FPERROR(efd, "%s", "expecting unary expression");
- 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") || !strcmp(str, "TRUE")) {
- ret = TRUE;
- } else if (!strcmp(str, "false") || !strcmp(str, "FALSE")) {
- ret = FALSE;
- } else {
- _FPERROR(efd, "unexpected string \"%s\"", str);
- ret = -EINVAL;
- goto end;
- }
- break;
- }
- default:
- _FPERROR(efd, "%s", "unexpected unary expression type");
- ret = -EINVAL;
- goto end;
- }
-
-end:
- return ret;
-}
-
-static
-enum bt_ctf_byte_order byte_order_from_unary_expr(FILE *efd,
- struct ctf_node *unary_expr)
-{
- const char *str;
- enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_UNKNOWN;
-
- if (unary_expr->u.unary_expression.type != UNARY_STRING) {
- _FPERROR(efd, "%s",
- "\"byte_order\" attribute: expecting string");
- goto end;
- }
-
- str = unary_expr->u.unary_expression.u.string;
-
- if (!strcmp(str, "be") || !strcmp(str, "network")) {
- bo = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
- } else if (!strcmp(str, "le")) {
- bo = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
- } else if (!strcmp(str, "native")) {
- bo = BT_CTF_BYTE_ORDER_NATIVE;
- } else {
- _FPERROR(efd, "unexpected \"byte_order\" attribute value \"%s\"; should be \"be\", \"le\", \"network\", or \"native\"",
- str);
- goto end;
- }
-
-end:
- return bo;
-}
-
-static
-enum bt_ctf_byte_order get_real_byte_order(struct ctx *ctx,
- struct ctf_node *uexpr)
-{
- enum bt_ctf_byte_order bo = byte_order_from_unary_expr(ctx->efd, uexpr);
-
- if (bo == BT_CTF_BYTE_ORDER_NATIVE) {
- bo = bt_ctf_trace_get_byte_order(ctx->trace);
- }
-
- return bo;
-}
-
-static
-int is_align_valid(uint64_t align)
-{
- return (align != 0) && !(align & (align - 1));
-}
-
-static
-int get_type_specifier_name(struct ctx *ctx, struct ctf_node *type_specifier,
- GString *str)
-{
- int ret = 0;
-
- if (type_specifier->type != NODE_TYPE_SPECIFIER) {
- ret = -EINVAL;
- goto end;
- }
-
- switch (type_specifier->u.type_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 (type_specifier->u.type_specifier.id_type) {
- g_string_append(str,
- type_specifier->u.type_specifier.id_type);
- }
- break;
- case TYPESPEC_STRUCT:
- {
- struct ctf_node *node = type_specifier->u.type_specifier.node;
-
- if (!node->u._struct.name) {
- _PERROR("%s", "unexpected empty structure 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 = type_specifier->u.type_specifier.node;
-
- if (!node->u.variant.name) {
- _PERROR("%s", "unexpected empty variant 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 = type_specifier->u.type_specifier.node;
-
- if (!node->u._enum.enum_id) {
- _PERROR("%s", "unexpected empty 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:
- _PERROR("%s", "unknown specifier");
- ret = -EINVAL;
- goto end;
- }
-
-end:
- return ret;
-}
-
-static
-int get_type_specifier_list_name(struct ctx *ctx,
- struct ctf_node *type_specifier_list, GString *str)
-{
- int ret;
- struct ctf_node *iter;
- int alias_item_nr = 0;
- struct bt_list_head *head =
- &type_specifier_list->u.type_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_type_specifier_name(ctx, iter, str);
- if (ret) {
- goto end;
- }
- }
-
-end:
- return ret;
-}
-
-static
-GQuark create_typealias_identifier(struct ctx *ctx,
- struct ctf_node *type_specifier_list,
- struct ctf_node *node_type_declarator)
-{
- int ret;
- char *str_c;
- GString *str;
- GQuark qalias = 0;
- struct ctf_node *iter;
- struct bt_list_head *pointers =
- &node_type_declarator->u.type_declarator.pointers;
-
- str = g_string_new("");
- ret = get_type_specifier_list_name(ctx, type_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_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
- GQuark *field_name, struct ctf_node *node_type_declarator,
- struct bt_ctf_field_type **field_decl,
- struct bt_ctf_field_type *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 type declarator node */
- if (node_type_declarator) {
- if (node_type_declarator->u.type_declarator.type ==
- TYPEDEC_UNKNOWN) {
- ret = -EINVAL;
- goto error;
- }
-
- /* TODO: GCC bitfields not supported yet */
- if (node_type_declarator->u.type_declarator.bitfield_len !=
- NULL) {
- _PERROR("%s", "GCC bitfields are not supported as of this version");
- ret = -EPERM;
- goto error;
- }
- }
-
- /* Find the right nested declaration if not provided */
- if (!nested_decl) {
- struct bt_list_head *pointers =
- &node_type_declarator->u.type_declarator.pointers;
-
- if (node_type_declarator && !bt_list_empty(pointers)) {
- GQuark qalias;
- _BT_CTF_FIELD_TYPE_INIT(nested_decl_copy);
-
- /*
- * If we have a pointer declarator, it HAS to
- * be present in the typealiases (else fail).
- */
- qalias = create_typealias_identifier(ctx,
- type_specifier_list, node_type_declarator);
- nested_decl =
- ctx_decl_scope_lookup_alias(ctx->current_scope,
- g_quark_to_string(qalias), -1);
- if (!nested_decl) {
- _PERROR("cannot find typealias \"%s\"",
- g_quark_to_string(qalias));
- ret = -EINVAL;
- goto error;
- }
-
- /* Make a copy of it */
- nested_decl_copy = bt_ctf_field_type_copy(nested_decl);
- BT_PUT(nested_decl);
- if (!nested_decl_copy) {
- _PERROR("%s", "cannot copy nested declaration");
- ret = -EINVAL;
- goto error;
- }
-
- BT_MOVE(nested_decl, nested_decl_copy);
-
- /* Force integer's base to 16 since it's a pointer */
- if (bt_ctf_field_type_is_integer(nested_decl)) {
- bt_ctf_field_type_integer_set_base(nested_decl,
- BT_CTF_INTEGER_BASE_HEXADECIMAL);
- }
- } else {
- ret = visit_type_specifier_list(ctx,
- type_specifier_list, &nested_decl);
- if (ret) {
- assert(!nested_decl);
- goto error;
- }
- }
- }
-
- assert(nested_decl);
-
- if (!node_type_declarator) {
- BT_MOVE(*field_decl, nested_decl);
- goto end;
- }
-
- if (node_type_declarator->u.type_declarator.type == TYPEDEC_ID) {
- if (node_type_declarator->u.type_declarator.u.id) {
- const char *id =
- node_type_declarator->u.type_declarator.u.id;
-
- *field_name = g_quark_from_string(id);
- } else {
- *field_name = 0;
- }
-
- BT_MOVE(*field_decl, nested_decl);
- goto end;
- } else {
- struct ctf_node *first;
- _BT_CTF_FIELD_TYPE_INIT(decl);
- _BT_CTF_FIELD_TYPE_INIT(outer_field_decl);
- struct bt_list_head *length =
- &node_type_declarator->
- u.type_declarator.u.nested.length;
-
- /* Create array/sequence, pass nested_decl as child */
- if (bt_list_empty(length)) {
- _PERROR("%s",
- "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) {
- ret = -EINVAL;
- goto error;
- }
-
- switch (first->u.unary_expression.type) {
- case UNARY_UNSIGNED_CONSTANT:
- {
- size_t len;
- _BT_CTF_FIELD_TYPE_INIT(array_decl);
-
- len = first->u.unary_expression.u.unsigned_constant;
- array_decl = bt_ctf_field_type_array_create(nested_decl,
- len);
- BT_PUT(nested_decl);
- if (!array_decl) {
- _PERROR("%s",
- "cannot create array declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- BT_MOVE(decl, array_decl);
- break;
- }
- case UNARY_STRING:
- {
- /* Lookup unsigned integer definition, create seq. */
- _BT_CTF_FIELD_TYPE_INIT(seq_decl);
- char *length_name = concatenate_unary_strings(length);
-
- if (!length_name) {
- ret = -EINVAL;
- goto error;
- }
-
- seq_decl = bt_ctf_field_type_sequence_create(
- nested_decl, length_name);
- g_free(length_name);
- BT_PUT(nested_decl);
- if (!seq_decl) {
- _PERROR("%s",
- "cannot create sequence declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- BT_MOVE(decl, seq_decl);
- break;
- }
- default:
- ret = -EINVAL;
- goto error;
- }
-
- assert(!nested_decl);
- assert(decl);
- 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_type_declarator(ctx, type_specifier_list,
- field_name,
- node_type_declarator->
- u.type_declarator.u.nested.type_declarator,
- &outer_field_decl, decl);
- decl = NULL;
- if (ret) {
- assert(!outer_field_decl);
- ret = -EINVAL;
- goto error;
- }
-
- assert(outer_field_decl);
- BT_MOVE(*field_decl, outer_field_decl);
- }
-
-end:
- BT_PUT(nested_decl);
- assert(*field_decl);
-
- return 0;
-
-error:
- BT_PUT(nested_decl);
- BT_PUT(*field_decl);
-
- return ret;
-}
-
-static
-int visit_struct_decl_field(struct ctx *ctx,
- struct bt_ctf_field_type *struct_decl,
- struct ctf_node *type_specifier_list,
- struct bt_list_head *type_declarators)
-{
- int ret = 0;
- struct ctf_node *iter;
- _BT_CTF_FIELD_TYPE_INIT(field_decl);
-
- bt_list_for_each_entry(iter, type_declarators, siblings) {
- field_decl = NULL;
- GQuark qfield_name;
- const char *field_name;
- _BT_CTF_FIELD_TYPE_INIT(efield_decl);
-
- ret = visit_type_declarator(ctx, type_specifier_list,
- &qfield_name, iter, &field_decl, NULL);
- if (ret) {
- assert(!field_decl);
- _PERROR("%s", "unable to find structure field declaration type");
- goto error;
- }
-
- assert(field_decl);
- field_name = g_quark_to_string(qfield_name);
-
- /* Check if field with same name already exists */
- efield_decl =
- bt_ctf_field_type_structure_get_field_type_by_name(
- struct_decl, field_name);
- if (efield_decl) {
- BT_PUT(efield_decl);
- _PERROR("duplicate field \"%s\" in structure",
- field_name);
- ret = -EINVAL;
- goto error;
- }
-
- /* Add field to structure */
- ret = bt_ctf_field_type_structure_add_field(struct_decl,
- field_decl, field_name);
- BT_PUT(field_decl);
- if (ret) {
- _PERROR("cannot add field \"%s\" to structure",
- g_quark_to_string(qfield_name));
- goto error;
- }
- }
-
- return 0;
-
-error:
- BT_PUT(field_decl);
-
- return ret;
-}
-
-static
-int visit_variant_decl_field(struct ctx *ctx,
- struct bt_ctf_field_type *variant_decl,
- struct ctf_node *type_specifier_list,
- struct bt_list_head *type_declarators)
-{
- int ret = 0;
- struct ctf_node *iter;
- _BT_CTF_FIELD_TYPE_INIT(field_decl);
-
- bt_list_for_each_entry(iter, type_declarators, siblings) {
- field_decl = NULL;
- GQuark qfield_name;
- const char *field_name;
- _BT_CTF_FIELD_TYPE_INIT(efield_decl);
-
- ret = visit_type_declarator(ctx, type_specifier_list,
- &qfield_name, iter, &field_decl, NULL);
- if (ret) {
- assert(!field_decl);
- _PERROR("%s",
- "unable to find variant field declaration type");
- goto error;
- }
-
- assert(field_decl);
- field_name = g_quark_to_string(qfield_name);
-
- /* Check if field with same name already exists */
- efield_decl =
- bt_ctf_field_type_variant_get_field_type_by_name(
- variant_decl, field_name);
- if (efield_decl) {
- BT_PUT(efield_decl);
- _PERROR("duplicate field \"%s\" in variant",
- field_name);
- ret = -EINVAL;
- goto error;
- }
-
- /* Add field to structure */
- ret = bt_ctf_field_type_variant_add_field(variant_decl,
- field_decl, field_name);
- BT_PUT(field_decl);
- if (ret) {
- _PERROR("cannot add field \"%s\" to variant",
- g_quark_to_string(qfield_name));
- goto error;
- }
- }
-
- return 0;
-
-error:
- BT_PUT(field_decl);
-
- return ret;
-}
-
-static
-int visit_typedef(struct ctx *ctx, struct ctf_node *type_specifier_list,
- struct bt_list_head *type_declarators)
-{
- int ret = 0;
- GQuark qidentifier;
- struct ctf_node *iter;
- _BT_CTF_FIELD_TYPE_INIT(type_decl);
-
- bt_list_for_each_entry(iter, type_declarators, siblings) {
- ret = visit_type_declarator(ctx, type_specifier_list,
- &qidentifier, iter, &type_decl, NULL);
- if (ret) {
- _PERROR("%s", "problem creating type declaration");
- ret = -EINVAL;
- goto end;
- }
-
- /* Do not allow typedef and typealias of untagged variants */
- if (bt_ctf_field_type_is_variant(type_decl)) {
- if (bt_ctf_field_type_variant_get_tag_name(type_decl)) {
- _PERROR("%s", "typedef of untagged variant is not allowed");
- ret = -EPERM;
- goto end;
- }
- }
-
- ret = ctx_decl_scope_register_alias(ctx->current_scope,
- g_quark_to_string(qidentifier), type_decl);
- if (ret) {
- _PERROR("cannot register typedef \"%s\"",
- g_quark_to_string(qidentifier));
- goto end;
- }
- }
-
-end:
- BT_PUT(type_decl);
-
- return ret;
-}
-
-static
-int visit_typealias(struct ctx *ctx, struct ctf_node *target,
- struct ctf_node *alias)
-{
- int ret = 0;
- GQuark qalias;
- struct ctf_node *node;
- GQuark qdummy_field_name;
- _BT_CTF_FIELD_TYPE_INIT(type_decl);
-
- /* Create target type declaration */
- if (bt_list_empty(&target->u.typealias_target.type_declarators)) {
- node = NULL;
- } else {
- node = _BT_LIST_FIRST_ENTRY(
- &target->u.typealias_target.type_declarators,
- struct ctf_node, siblings);
- }
-
- ret = visit_type_declarator(ctx,
- target->u.typealias_target.type_specifier_list,
- &qdummy_field_name, node, &type_decl, NULL);
- if (ret) {
- assert(!type_decl);
- _PERROR("%s", "problem creating type declaration");
- goto end;
- }
-
- /* Do not allow typedef and typealias of untagged variants */
- if (bt_ctf_field_type_is_variant(type_decl)) {
- if (bt_ctf_field_type_variant_get_tag_name(type_decl)) {
- _PERROR("%s",
- "typealias of untagged variant 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) {
- _PERROR("%s", "expecting empty identifier");
- ret = -EINVAL;
- goto end;
- }
-
- /* Create alias identifier */
- node = _BT_LIST_FIRST_ENTRY(&alias->u.typealias_alias.type_declarators,
- struct ctf_node, siblings);
- qalias = create_typealias_identifier(ctx,
- alias->u.typealias_alias.type_specifier_list, node);
- ret = ctx_decl_scope_register_alias(ctx->current_scope,
- g_quark_to_string(qalias), type_decl);
- if (ret) {
- _PERROR("cannot register typealias \"%s\"",
- g_quark_to_string(qalias));
- goto end;
- }
-
-end:
- BT_PUT(type_decl);
-
- return ret;
-}
-
-static
-int visit_struct_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
- struct bt_ctf_field_type *struct_decl)
-{
- int ret = 0;
-
- switch (entry_node->type) {
- case NODE_TYPEDEF:
- ret = visit_typedef(ctx,
- entry_node->u._typedef.type_specifier_list,
- &entry_node->u._typedef.type_declarators);
- if (ret) {
- _PERROR("%s",
- "cannot add typedef in \"struct\" declaration");
- goto end;
- }
- break;
- case NODE_TYPEALIAS:
- ret = visit_typealias(ctx, entry_node->u.typealias.target,
- entry_node->u.typealias.alias);
- if (ret) {
- _PERROR("%s",
- "cannot add typealias in \"struct\" declaration");
- 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.
- type_specifier_list,
- &entry_node->u.struct_or_variant_declaration.
- type_declarators);
- if (ret) {
- goto end;
- }
- break;
- default:
- _PERROR("unexpected node type: %d", (int) entry_node->type);
- ret = -EINVAL;
- goto end;
- }
-
-end:
- return ret;
-}
-
-static
-int visit_variant_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
- struct bt_ctf_field_type *variant_decl)
-{
- int ret = 0;
-
- switch (entry_node->type) {
- case NODE_TYPEDEF:
- ret = visit_typedef(ctx,
- entry_node->u._typedef.type_specifier_list,
- &entry_node->u._typedef.type_declarators);
- if (ret) {
- _PERROR("%s",
- "cannot add typedef in \"variant\" declaration");
- goto end;
- }
- break;
- case NODE_TYPEALIAS:
- ret = visit_typealias(ctx, entry_node->u.typealias.target,
- entry_node->u.typealias.alias);
- if (ret) {
- _PERROR("%s",
- "cannot add typealias in \"variant\" declaration");
- 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.
- type_specifier_list,
- &entry_node->u.struct_or_variant_declaration.
- type_declarators);
- if (ret) {
- goto end;
- }
- break;
- default:
- _PERROR("unexpected node type: %d", (int) entry_node->type);
- ret = -EINVAL;
- goto end;
- }
-
-end:
- return ret;
-}
-
-static
-int visit_struct_decl(struct ctx *ctx, const char *name,
- struct bt_list_head *decl_list, int has_body,
- struct bt_list_head *min_align,
- struct bt_ctf_field_type **struct_decl)
-{
- int ret = 0;
-
- *struct_decl = NULL;
-
- /* For named struct (without body), lookup in declaration scope */
- if (!has_body) {
- _BT_CTF_FIELD_TYPE_INIT(struct_decl_copy);
-
- if (!name) {
- ret = -EPERM;
- goto error;
- }
-
- *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope,
- name, -1);
- if (!*struct_decl) {
- _PERROR("cannot find \"struct %s\"", name);
- ret = -EINVAL;
- goto error;
- }
-
- /* Make a copy of it */
- struct_decl_copy = bt_ctf_field_type_copy(*struct_decl);
- if (!struct_decl_copy) {
- _PERROR("%s",
- "cannot create copy of structure declaration");
- ret = -EINVAL;
- goto error;
- }
-
- BT_MOVE(*struct_decl, struct_decl_copy);
- } else {
- struct ctf_node *entry_node;
- uint64_t min_align_value = 0;
-
- if (name) {
- _BT_CTF_FIELD_TYPE_INIT(estruct_decl);
-
- estruct_decl = ctx_decl_scope_lookup_struct(
- ctx->current_scope, name, 1);
- if (estruct_decl) {
- BT_PUT(estruct_decl);
- _PERROR("\"struct %s\" already declared in local scope",
- name);
- ret = -EINVAL;
- goto error;
- }
- }
-
- if (!bt_list_empty(min_align)) {
- ret = get_unary_unsigned(min_align, &min_align_value);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for structure declaration's \"align\" attribute");
- goto error;
- }
- }
-
- *struct_decl = bt_ctf_field_type_structure_create();
- if (!*struct_decl) {
- _PERROR("%s", "cannot create structure declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = ctx_push_scope(ctx);
- if (ret) {
- _PERROR("%s", "cannot push scope");
- goto error;
- }
-
- bt_list_for_each_entry(entry_node, decl_list, siblings) {
- ret = visit_struct_decl_entry(ctx, entry_node,
- *struct_decl);
- if (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) {
- _PERROR("cannot register \"struct %s\" in declaration scope",
- name);
- goto error;
- }
- }
- }
-
- return 0;
-
-error:
- BT_PUT(*struct_decl);
-
- return ret;
-}
-
-static
-int visit_variant_decl(struct ctx *ctx, const char *name,
- const char *tag, struct bt_list_head *decl_list,
- int has_body, struct bt_ctf_field_type **variant_decl)
-{
- int ret = 0;
- _BT_CTF_FIELD_TYPE_INIT(untagged_variant_decl);
-
- *variant_decl = NULL;
-
- /* For named variant (without body), lookup in declaration scope */
- if (!has_body) {
- _BT_CTF_FIELD_TYPE_INIT(variant_decl_copy);
-
- if (!name) {
- ret = -EPERM;
- goto error;
- }
-
- untagged_variant_decl =
- ctx_decl_scope_lookup_variant(ctx->current_scope,
- name, -1);
- if (!untagged_variant_decl) {
- _PERROR("cannot find \"variant %s\"", name);
- ret = -EINVAL;
- goto error;
- }
-
- /* Make a copy of it */
- variant_decl_copy = bt_ctf_field_type_copy(
- untagged_variant_decl);
- if (!variant_decl_copy) {
- _PERROR("%s",
- "cannot create copy of structure declaration");
- ret = -EINVAL;
- goto error;
- }
-
- BT_MOVE(untagged_variant_decl, variant_decl_copy);
- } else {
- struct ctf_node *entry_node;
-
- if (name) {
- struct bt_ctf_field_type *evariant_decl =
- ctx_decl_scope_lookup_struct(ctx->current_scope,
- name, 1);
-
- if (evariant_decl) {
- BT_PUT(evariant_decl);
- _PERROR("\"variant %s\" already declared in local scope",
- name);
- ret = -EINVAL;
- goto error;
- }
- }
-
- untagged_variant_decl = bt_ctf_field_type_variant_create(NULL,
- NULL);
- if (!untagged_variant_decl) {
- _PERROR("%s", "cannot create variant declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = ctx_push_scope(ctx);
- if (ret) {
- _PERROR("%s", "cannot push scope");
- 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) {
- 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) {
- _PERROR("cannot register \"variant %s\" in declaration scope",
- name);
- goto error;
- }
- }
- }
-
- /*
- * If tagged, create tagged variant and return; otherwise
- * return untagged variant.
- */
- if (!tag) {
- BT_MOVE(*variant_decl, untagged_variant_decl);
- } else {
- /*
- * At this point, we have a fresh untagged variant; nobody
- * else owns it. Set its tag now.
- */
- ret = bt_ctf_field_type_variant_set_tag_name(
- untagged_variant_decl, tag);
- if (ret) {
- goto error;
- }
-
- BT_MOVE(*variant_decl, untagged_variant_decl);
- }
-
- assert(!untagged_variant_decl);
- assert(*variant_decl);
-
- return 0;
-
-error:
- BT_PUT(untagged_variant_decl);
- BT_PUT(*variant_decl);
-
- return ret;
-}
-
-static
-int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
- struct bt_ctf_field_type *enum_decl, int64_t *last, int is_signed)
-{
- int ret = 0;
- int nr_vals = 0;
- struct ctf_node *iter;
- int64_t start = 0, end = 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) {
- int64_t *target;
-
- if (iter->type != NODE_UNARY_EXPRESSION) {
- _PERROR("wrong unary expression for enumeration label \"%s\"",
- 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 = iter->u.unary_expression.u.signed_constant;
- break;
- case UNARY_UNSIGNED_CONSTANT:
- *target = (int64_t)
- iter->u.unary_expression.u.unsigned_constant;
- break;
- default:
- _PERROR("invalid enumeration entry: \"%s\"",
- label);
- ret = -EINVAL;
- goto error;
- }
-
- if (nr_vals > 1) {
- _PERROR("invalid enumeration entry: \"%s\"",
- label);
- ret = -EINVAL;
- goto error;
- }
-
- nr_vals++;
- }
-
- if (nr_vals == 0) {
- start = *last;
- }
-
- if (nr_vals <= 1) {
- end = start;
- }
-
- *last = end + 1;
-
- if (is_signed) {
- ret = bt_ctf_field_type_enumeration_add_mapping(enum_decl, label,
- start, end);
- } else {
- ret = bt_ctf_field_type_enumeration_add_mapping_unsigned(enum_decl,
- label, (uint64_t) start, (uint64_t) end);
- }
- if (ret) {
- _PERROR("cannot add mapping to enumeration for label \"%s\"",
- label);
- goto error;
- }
-
- return 0;
-
-error:
- return ret;
-}
-
-static
-int visit_enum_decl(struct ctx *ctx, const char *name,
- struct ctf_node *container_type,
- struct bt_list_head *enumerator_list,
- int has_body,
- struct bt_ctf_field_type **enum_decl)
-{
- int ret = 0;
- GQuark qdummy_id;
- _BT_CTF_FIELD_TYPE_INIT(integer_decl);
-
- *enum_decl = NULL;
-
- /* For named enum (without body), lookup in declaration scope */
- if (!has_body) {
- _BT_CTF_FIELD_TYPE_INIT(enum_decl_copy);
-
- if (!name) {
- ret = -EPERM;
- goto error;
- }
-
- *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope,
- name, -1);
- if (!*enum_decl) {
- _PERROR("cannot find \"enum %s\"", name);
- ret = -EINVAL;
- goto error;
- }
-
- /* Make a copy of it */
- enum_decl_copy = bt_ctf_field_type_copy(*enum_decl);
- if (!enum_decl_copy) {
- _PERROR("%s",
- "cannot create copy of enumeration declaration");
- ret = -EINVAL;
- goto error;
- }
-
- BT_PUT(*enum_decl);
- BT_MOVE(*enum_decl, enum_decl_copy);
- } else {
- struct ctf_node *iter;
- int64_t last_value = 0;
-
- if (name) {
- _BT_CTF_FIELD_TYPE_INIT(eenum_decl);
-
- eenum_decl = ctx_decl_scope_lookup_enum(
- ctx->current_scope, name, 1);
- if (eenum_decl) {
- BT_PUT(eenum_decl);
- _PERROR("\"enum %s\" already declared in local scope",
- name);
- ret = -EINVAL;
- goto error;
- }
- }
-
- if (!container_type) {
- integer_decl = ctx_decl_scope_lookup_alias(
- ctx->current_scope, "int", -1);
- if (!integer_decl) {
- _PERROR("%s", "cannot find \"int\" type for enumeration");
- ret = -EINVAL;
- goto error;
- }
- } else {
- ret = visit_type_declarator(ctx, container_type,
- &qdummy_id, NULL, &integer_decl, NULL);
- if (ret) {
- assert(!integer_decl);
- ret = -EINVAL;
- goto error;
- }
- }
-
- assert(integer_decl);
-
- if (!bt_ctf_field_type_is_integer(integer_decl)) {
- _PERROR("%s", "container type for enumeration is not an integer");
- ret = -EINVAL;
- goto error;
- }
-
- *enum_decl = bt_ctf_field_type_enumeration_create(integer_decl);
- if (!*enum_decl) {
- _PERROR("%s", "cannot create enumeration declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- bt_list_for_each_entry(iter, enumerator_list, siblings) {
- ret = visit_enum_decl_entry(ctx, iter, *enum_decl,
- &last_value,
- bt_ctf_field_type_integer_get_signed(integer_decl));
- if (ret) {
- goto error;
- }
- }
-
- if (name) {
- ret = ctx_decl_scope_register_enum(ctx->current_scope,
- name, *enum_decl);
- if (ret) {
- goto error;
- }
- }
- }
-
- BT_PUT(integer_decl);
-
- return 0;
-
-error:
- BT_PUT(integer_decl);
- BT_PUT(*enum_decl);
-
- return ret;
-}
-
-static
-int visit_type_specifier(struct ctx *ctx,
- struct ctf_node *type_specifier_list,
- struct bt_ctf_field_type **decl)
-{
- int ret = 0;
- GString *str = NULL;
- _BT_CTF_FIELD_TYPE_INIT(decl_copy);
-
- *decl = NULL;
- str = g_string_new("");
- ret = get_type_specifier_list_name(ctx, type_specifier_list, str);
- if (ret) {
- goto error;
- }
-
- *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1);
- if (!*decl) {
- _PERROR("cannot find type alias \"%s\"", str->str);
- ret = -EINVAL;
- goto error;
- }
-
- /* Make a copy of the type declaration */
- decl_copy = bt_ctf_field_type_copy(*decl);
- if (!decl_copy) {
- _PERROR("%s", "cannot create copy of type declaration");
- ret = -EINVAL;
- goto error;
- }
-
- BT_MOVE(*decl, decl_copy);
- (void) g_string_free(str, TRUE);
- str = NULL;
-
- return 0;
-
-error:
- if (str) {
- (void) g_string_free(str, TRUE);
- }
-
- BT_PUT(*decl);
-
- return ret;
-}
-
-static
-int visit_integer_decl(struct ctx *ctx,
- struct bt_list_head *expressions,
- struct bt_ctf_field_type **integer_decl)
-{
- int set = 0;
- int ret = 0;
- int signedness = 0;
- struct ctf_node *expression;
- uint64_t alignment = 0, size = 0;
- struct bt_ctf_clock *mapped_clock = NULL;
- enum bt_ctf_string_encoding encoding = BT_CTF_STRING_ENCODING_NONE;
- enum bt_ctf_integer_base base = BT_CTF_INTEGER_BASE_DECIMAL;
- enum bt_ctf_byte_order byte_order =
- bt_ctf_trace_get_byte_order(ctx->trace);
-
- *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) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left->u.unary_expression.u.string, "signed")) {
- if (_IS_SET(&set, _INTEGER_SIGNED_SET)) {
- _PERROR_DUP_ATTR("signed",
- "integer declaration");
- ret = -EPERM;
- goto error;
- }
-
- signedness = get_boolean(ctx->efd, right);
- if (signedness < 0) {
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _INTEGER_SIGNED_SET);
- } else if (!strcmp(left->u.unary_expression.u.string,
- "byte_order")) {
- if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) {
- _PERROR_DUP_ATTR("byte_order",
- "integer declaration");
- ret = -EPERM;
- goto error;
- }
-
- byte_order = get_real_byte_order(ctx, right);
- if (byte_order == BT_CTF_BYTE_ORDER_UNKNOWN) {
- _PERROR("%s", "invalid \"byte_order\" attribute in integer declaration");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _INTEGER_BYTE_ORDER_SET);
- } else if (!strcmp(left->u.unary_expression.u.string, "size")) {
- if (_IS_SET(&set, _INTEGER_SIZE_SET)) {
- _PERROR_DUP_ATTR("size",
- "integer declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type !=
- UNARY_UNSIGNED_CONSTANT) {
- _PERROR("%s", "invalid \"size\" attribute in integer declaration: expecting unsigned constant");
- ret = -EINVAL;
- goto error;
- }
-
- size = right->u.unary_expression.u.unsigned_constant;
- if (size == 0) {
- _PERROR("%s", "invalid \"size\" attribute in integer declaration: expecting positive constant");
- ret = -EINVAL;
- goto error;
- } else if (size > 64) {
- _PERROR("%s", "invalid \"size\" attribute in integer declaration: integers over 64-bit are not supported as of this version");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _INTEGER_SIZE_SET);
- } else if (!strcmp(left->u.unary_expression.u.string,
- "align")) {
- if (_IS_SET(&set, _INTEGER_ALIGN_SET)) {
- _PERROR_DUP_ATTR("align",
- "integer declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type !=
- UNARY_UNSIGNED_CONSTANT) {
- _PERROR("%s", "invalid \"align\" attribute in integer declaration: expecting unsigned constant");
- ret = -EINVAL;
- goto error;
- }
-
- alignment =
- right->u.unary_expression.u.unsigned_constant;
- if (!is_align_valid(alignment)) {
- _PERROR("%s", "invalid \"align\" attribute in integer declaration: expecting power of two");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _INTEGER_ALIGN_SET);
- } else if (!strcmp(left->u.unary_expression.u.string, "base")) {
- if (_IS_SET(&set, _INTEGER_BASE_SET)) {
- _PERROR_DUP_ATTR("base", "integer declaration");
- 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_CTF_INTEGER_BASE_BINARY;
- break;
- case 8:
- base = BT_CTF_INTEGER_BASE_OCTAL;
- break;
- case 10:
- base = BT_CTF_INTEGER_BASE_DECIMAL;
- break;
- case 16:
- base = BT_CTF_INTEGER_BASE_HEXADECIMAL;
- break;
- default:
- _PERROR("invalid \"base\" attribute in integer declaration: %" PRIu64,
- right->u.unary_expression.u.unsigned_constant);
- ret = -EINVAL;
- goto error;
- }
- break;
- }
- case UNARY_STRING:
- {
- char *s_right = concatenate_unary_strings(
- &expression->u.ctf_expression.right);
- if (!s_right) {
- _PERROR("%s", "unexpected unary expression for integer declaration's \"base\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(s_right, "decimal") ||
- !strcmp(s_right, "dec") ||
- !strcmp(s_right, "d") ||
- !strcmp(s_right, "i") ||
- !strcmp(s_right, "u")) {
- base = BT_CTF_INTEGER_BASE_DECIMAL;
- } else if (!strcmp(s_right, "hexadecimal") ||
- !strcmp(s_right, "hex") ||
- !strcmp(s_right, "x") ||
- !strcmp(s_right, "X") ||
- !strcmp(s_right, "p")) {
- base = BT_CTF_INTEGER_BASE_HEXADECIMAL;
- } else if (!strcmp(s_right, "octal") ||
- !strcmp(s_right, "oct") ||
- !strcmp(s_right, "o")) {
- base = BT_CTF_INTEGER_BASE_OCTAL;
- } else if (!strcmp(s_right, "binary") ||
- !strcmp(s_right, "b")) {
- base = BT_CTF_INTEGER_BASE_BINARY;
- } else {
- _PERROR("unexpected unary expression for integer declaration's \"base\" attribute: \"%s\"",
- s_right);
- g_free(s_right);
- ret = -EINVAL;
- goto error;
- }
-
- g_free(s_right);
- break;
- }
- default:
- _PERROR("%s", "invalid \"base\" attribute in integer declaration: expecting unsigned constant or unary string");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _INTEGER_BASE_SET);
- } else if (!strcmp(left->u.unary_expression.u.string,
- "encoding")) {
- char *s_right;
-
- if (_IS_SET(&set, _INTEGER_ENCODING_SET)) {
- _PERROR_DUP_ATTR("encoding",
- "integer declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type != UNARY_STRING) {
- _PERROR("%s", "invalid \"encoding\" attribute in integer declaration: expecting unary string");
- ret = -EINVAL;
- goto error;
- }
-
- s_right = concatenate_unary_strings(
- &expression->u.ctf_expression.right);
- if (!s_right) {
- _PERROR("%s", "unexpected unary expression for integer declaration's \"encoding\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(s_right, "UTF8") ||
- !strcmp(s_right, "utf8") ||
- !strcmp(s_right, "utf-8") ||
- !strcmp(s_right, "UTF-8")) {
- encoding = BT_CTF_STRING_ENCODING_UTF8;
- } else if (!strcmp(s_right, "ASCII") ||
- !strcmp(s_right, "ascii")) {
- encoding = BT_CTF_STRING_ENCODING_ASCII;
- } else if (!strcmp(s_right, "none")) {
- encoding = BT_CTF_STRING_ENCODING_NONE;
- } else {
- _PERROR("invalid \"encoding\" attribute in integer declaration: unknown 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")) {
- const char *clock_name;
-
- if (_IS_SET(&set, _INTEGER_MAP_SET)) {
- _PERROR_DUP_ATTR("map", "integer declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type != UNARY_STRING) {
- _PERROR("%s", "invalid \"map\" attribute in integer declaration: 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 = concatenate_unary_strings(
- &expression->u.ctf_expression.right);
-
- if (!s_right) {
- _PERROR("%s", "unexpected unary expression for integer declaration's \"map\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- _PWARNING("invalid \"map\" attribute in integer declaration: unknown clock: \"%s\"",
- s_right);
- _SET(&set, _INTEGER_MAP_SET);
- g_free(s_right);
- continue;
- }
-
- mapped_clock = bt_ctf_trace_get_clock_by_name(
- ctx->trace, clock_name);
- if (!mapped_clock) {
- _PERROR("invalid \"map\" attribute in integer declaration: cannot find clock \"%s\"",
- clock_name);
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _INTEGER_MAP_SET);
- } else {
- _PWARNING("unknown attribute \"%s\" in integer declaration",
- left->u.unary_expression.u.string);
- }
- }
-
- if (!_IS_SET(&set, _INTEGER_SIZE_SET)) {
- _PERROR("%s",
- "missing \"size\" attribute in integer declaration");
- 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 = bt_ctf_field_type_integer_create((unsigned int) size);
- if (!*integer_decl) {
- _PERROR("%s", "cannot create integer declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_field_type_integer_set_signed(*integer_decl, signedness);
- ret |= bt_ctf_field_type_integer_set_base(*integer_decl, base);
- ret |= bt_ctf_field_type_integer_set_encoding(*integer_decl, encoding);
- ret |= bt_ctf_field_type_set_alignment(*integer_decl,
- (unsigned int) alignment);
- ret |= bt_ctf_field_type_set_byte_order(*integer_decl, byte_order);
-
- if (mapped_clock) {
- /* Move clock */
- ret |= bt_ctf_field_type_integer_set_mapped_clock(
- *integer_decl, mapped_clock);
- bt_put(mapped_clock);
- mapped_clock = NULL;
- }
-
- if (ret) {
- _PERROR("%s", "cannot configure integer declaration");
- ret = -EINVAL;
- goto error;
- }
-
- return 0;
-
-error:
- if (mapped_clock) {
- bt_put(mapped_clock);
- }
-
- BT_PUT(*integer_decl);
-
- return ret;
-}
-
-static
-int visit_floating_point_number_decl(struct ctx *ctx,
- struct bt_list_head *expressions,
- struct bt_ctf_field_type **float_decl)
-{
- int set = 0;
- int ret = 0;
- struct ctf_node *expression;
- uint64_t alignment = 1, exp_dig = 0, mant_dig = 0;
- enum bt_ctf_byte_order byte_order =
- bt_ctf_trace_get_byte_order(ctx->trace);
-
- *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) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left->u.unary_expression.u.string, "byte_order")) {
- if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) {
- _PERROR_DUP_ATTR("byte_order",
- "floating point number declaration");
- ret = -EPERM;
- goto error;
- }
-
- byte_order = get_real_byte_order(ctx, right);
- if (byte_order == BT_CTF_BYTE_ORDER_UNKNOWN) {
- _PERROR("%s", "invalid \"byte_order\" attribute in floating point number declaration");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _FLOAT_BYTE_ORDER_SET);
- } else if (!strcmp(left->u.unary_expression.u.string,
- "exp_dig")) {
- if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
- _PERROR_DUP_ATTR("exp_dig",
- "floating point number declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type !=
- UNARY_UNSIGNED_CONSTANT) {
- _PERROR("%s", "invalid \"exp_dig\" attribute in floating point number declaration: expecting unsigned constant");
- 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")) {
- if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
- _PERROR_DUP_ATTR("mant_dig",
- "floating point number declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type !=
- UNARY_UNSIGNED_CONSTANT) {
- _PERROR("%s", "invalid \"mant_dig\" attribute in floating point number declaration: expecting unsigned constant");
- 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")) {
- if (_IS_SET(&set, _FLOAT_ALIGN_SET)) {
- _PERROR_DUP_ATTR("align",
- "floating point number declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type !=
- UNARY_UNSIGNED_CONSTANT) {
- _PERROR("%s", "invalid \"align\" attribute in floating point number declaration: expecting unsigned constant");
- ret = -EINVAL;
- goto error;
- }
-
- alignment = right->u.unary_expression.u.
- unsigned_constant;
-
- if (!is_align_valid(alignment)) {
- _PERROR("%s", "invalid \"align\" attribute in floating point number declaration: expecting power of two");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(&set, _FLOAT_ALIGN_SET);
- } else {
- _PWARNING("unknown attribute \"%s\" in floating point number declaration",
- left->u.unary_expression.u.string);
- }
- }
-
- if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
- _PERROR("%s", "missing \"mant_dig\" attribute in floating point number declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
- _PERROR("%s", "missing \"exp_dig\" attribute in floating point number declaration");
- 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 = bt_ctf_field_type_floating_point_create();
- if (!*float_decl) {
- _PERROR("%s",
- "cannot create floating point number declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_field_type_floating_point_set_exponent_digits(
- *float_decl, exp_dig);
- ret |= bt_ctf_field_type_floating_point_set_mantissa_digits(
- *float_decl, mant_dig);
- ret |= bt_ctf_field_type_set_byte_order(*float_decl, byte_order);
- ret |= bt_ctf_field_type_set_alignment(*float_decl, alignment);
- if (ret) {
- _PERROR("%s",
- "cannot configure floating point number declaration");
- ret = -EINVAL;
- goto error;
- }
-
- return 0;
-
-error:
- BT_PUT(*float_decl);
-
- return ret;
-}
-
-static
-int visit_string_decl(struct ctx *ctx,
- struct bt_list_head *expressions,
- struct bt_ctf_field_type **string_decl)
-{
- int set = 0;
- int ret = 0;
- struct ctf_node *expression;
- enum bt_ctf_string_encoding encoding = BT_CTF_STRING_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) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
- char *s_right;
-
- if (_IS_SET(&set, _STRING_ENCODING_SET)) {
- _PERROR_DUP_ATTR("encoding",
- "string declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (right->u.unary_expression.type != UNARY_STRING) {
- _PERROR("%s", "invalid \"encoding\" attribute in string declaration: expecting unary string");
- ret = -EINVAL;
- goto error;
- }
-
- s_right = concatenate_unary_strings(
- &expression->u.ctf_expression.right);
- if (!s_right) {
- _PERROR("%s", "unexpected unary expression for string declaration's \"encoding\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(s_right, "UTF8") ||
- !strcmp(s_right, "utf8") ||
- !strcmp(s_right, "utf-8") ||
- !strcmp(s_right, "UTF-8")) {
- encoding = BT_CTF_STRING_ENCODING_UTF8;
- } else if (!strcmp(s_right, "ASCII") ||
- !strcmp(s_right, "ascii")) {
- encoding = BT_CTF_STRING_ENCODING_ASCII;
- } else if (!strcmp(s_right, "none")) {
- encoding = BT_CTF_STRING_ENCODING_NONE;
- } else {
- _PERROR("invalid \"encoding\" attribute in string declaration: unknown encoding \"%s\"",
- s_right);
- g_free(s_right);
- ret = -EINVAL;
- goto error;
- }
-
- g_free(s_right);
- _SET(&set, _STRING_ENCODING_SET);
- } else {
- _PWARNING("unknown attribute \"%s\" in string declaration",
- left->u.unary_expression.u.string);
- }
- }
-
- *string_decl = bt_ctf_field_type_string_create();
- if (!*string_decl) {
- _PERROR("%s", "cannot create string declaration");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_field_type_string_set_encoding(*string_decl, encoding);
- if (ret) {
- _PERROR("%s", "cannot configure string declaration");
- ret = -EINVAL;
- goto error;
- }
-
- return 0;
-
-error:
- BT_PUT(*string_decl);
-
- return ret;
-}
-
-static
-int visit_type_specifier_list(struct ctx *ctx,
- struct ctf_node *ts_list,
- struct bt_ctf_field_type **decl)
-{
- int ret = 0;
- struct ctf_node *first, *node;
-
- *decl = NULL;
-
- if (ts_list->type != NODE_TYPE_SPECIFIER_LIST) {
- ret = -EINVAL;
- goto error;
- }
-
- first = _BT_LIST_FIRST_ENTRY(&ts_list->u.type_specifier_list.head,
- struct ctf_node, siblings);
- if (first->type != NODE_TYPE_SPECIFIER) {
- ret = -EINVAL;
- goto error;
- }
-
- node = first->u.type_specifier.node;
-
- switch (first->u.type_specifier.type) {
- case TYPESPEC_INTEGER:
- ret = visit_integer_decl(ctx, &node->u.integer.expressions,
- decl);
- if (ret) {
- assert(!*decl);
- goto error;
- }
- break;
- case TYPESPEC_FLOATING_POINT:
- ret = visit_floating_point_number_decl(ctx,
- &node->u.floating_point.expressions, decl);
- if (ret) {
- assert(!*decl);
- goto error;
- }
- break;
- case TYPESPEC_STRING:
- ret = visit_string_decl(ctx,
- &node->u.string.expressions, decl);
- if (ret) {
- assert(!*decl);
- goto error;
- }
- break;
- case TYPESPEC_STRUCT:
- ret = visit_struct_decl(ctx, node->u._struct.name,
- &node->u._struct.declaration_list,
- node->u._struct.has_body,
- &node->u._struct.min_align, decl);
- if (ret) {
- assert(!*decl);
- goto error;
- }
- break;
- case TYPESPEC_VARIANT:
- ret = visit_variant_decl(ctx, node->u.variant.name,
- node->u.variant.choice,
- &node->u.variant.declaration_list,
- node->u.variant.has_body, decl);
- if (ret) {
- assert(!*decl);
- goto error;
- }
- break;
- case TYPESPEC_ENUM:
- ret = visit_enum_decl(ctx, node->u._enum.enum_id,
- node->u._enum.container_type,
- &node->u._enum.enumerator_list,
- node->u._enum.has_body, decl);
- if (ret) {
- assert(!*decl);
- goto error;
- }
- 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_type_specifier(ctx, ts_list, decl);
- if (ret) {
- assert(!*decl);
- goto error;
- }
- break;
- default:
- _PERROR("unexpected node type: %d",
- (int) first->u.type_specifier.type);
- ret = -EINVAL;
- goto error;
- }
-
- assert(*decl);
-
- return 0;
-
-error:
- BT_PUT(*decl);
-
- return ret;
-}
-
-static
-int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
- struct bt_ctf_event_class *event_class, int64_t *stream_id,
- int *set)
-{
- int ret = 0;
- char *left = NULL;
- _BT_CTF_FIELD_TYPE_INIT(decl);
-
- switch (node->type) {
- case NODE_TYPEDEF:
- ret = visit_typedef(ctx, node->u._typedef.type_specifier_list,
- &node->u._typedef.type_declarators);
- if (ret) {
- _PERROR("%s",
- "cannot add typedef in \"event\" declaration");
- goto error;
- }
- break;
- case NODE_TYPEALIAS:
- ret = visit_typealias(ctx, node->u.typealias.target,
- node->u.typealias.alias);
- if (ret) {
- _PERROR("%s", "cannot add typealias in \"event\" declaration");
- goto error;
- }
- break;
- case NODE_CTF_EXPRESSION:
- {
- left = concatenate_unary_strings(&node->u.ctf_expression.left);
- if (!left) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left, "name")) {
- /* This is already known at this stage */
- if (_IS_SET(set, _EVENT_NAME_SET)) {
- _PERROR_DUP_ATTR("name", "event declaration");
- ret = -EPERM;
- goto error;
- }
-
- _SET(set, _EVENT_NAME_SET);
- } else if (!strcmp(left, "id")) {
- int64_t id;
-
- if (_IS_SET(set, _EVENT_ID_SET)) {
- _PERROR_DUP_ATTR("id", "event declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(&node->u.ctf_expression.right,
- (uint64_t *) &id);
- if (ret || id < 0) {
- _PERROR("%s", "unexpected unary expression for event declaration's \"id\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_event_class_set_id(event_class, id);
- if (ret) {
- _PERROR("%s",
- "cannot set event declaration's ID");
- goto error;
- }
-
- _SET(set, _EVENT_ID_SET);
- } else if (!strcmp(left, "stream_id")) {
- if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
- _PERROR_DUP_ATTR("stream_id",
- "event declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(&node->u.ctf_expression.right,
- (uint64_t *) stream_id);
- if (ret || *stream_id < 0) {
- _PERROR("%s", "unexpected unary expression for event declaration's \"stream_id\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(set, _EVENT_STREAM_ID_SET);
- } else if (!strcmp(left, "context")) {
- if (_IS_SET(set, _EVENT_CONTEXT_SET)) {
- _PERROR("%s", "duplicate \"context\" entry in event declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = visit_type_specifier_list(ctx,
- _BT_LIST_FIRST_ENTRY(
- &node->u.ctf_expression.right,
- struct ctf_node, siblings),
- &decl);
- if (ret) {
- _PERROR("%s", "cannot create event context declaration");
- goto error;
- }
-
- assert(decl);
- ret = bt_ctf_event_class_set_context_type(
- event_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set event's context declaration");
- goto error;
- }
-
- _SET(set, _EVENT_CONTEXT_SET);
- } else if (!strcmp(left, "fields")) {
- if (_IS_SET(set, _EVENT_FIELDS_SET)) {
- _PERROR("%s", "duplicate \"fields\" entry in event declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = visit_type_specifier_list(ctx,
- _BT_LIST_FIRST_ENTRY(
- &node->u.ctf_expression.right,
- struct ctf_node, siblings),
- &decl);
- if (ret) {
- _PERROR("%s", "cannot create event payload declaration");
- goto error;
- }
-
- assert(decl);
- ret = bt_ctf_event_class_set_payload_type(
- event_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set event's payload declaration");
- goto error;
- }
-
- _SET(set, _EVENT_FIELDS_SET);
- } else if (!strcmp(left, "loglevel")) {
- uint64_t loglevel;
-
- if (_IS_SET(set, _EVENT_LOGLEVEL_SET)) {
- _PERROR_DUP_ATTR("loglevel",
- "event declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(&node->u.ctf_expression.right,
- &loglevel);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for event declaration's \"loglevel\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- // TODO: FIXME: set log level here
-
- _SET(set, _EVENT_LOGLEVEL_SET);
- } else if (!strcmp(left, "model.emf.uri")) {
- char *right;
-
- if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) {
- _PERROR_DUP_ATTR("model.emf.uri",
- "event declaration");
- ret = -EPERM;
- goto error;
- }
-
- right = concatenate_unary_strings(
- &node->u.ctf_expression.right);
- if (!right) {
- _PERROR("%s", "unexpected unary expression for event declaration's \"model.emf.uri\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- // TODO: FIXME: set model EMF URI here
-
- g_free(right);
- _SET(set, _EVENT_MODEL_EMF_URI_SET);
- } else {
- _PWARNING("unknown attribute \"%s\" in event declaration",
- left);
- }
-
- g_free(left);
- left = NULL;
- break;
- }
- default:
- ret = -EPERM;
- goto error;
- }
-
- return 0;
-
-error:
- if (left) {
- g_free(left);
- }
-
- BT_PUT(decl);
-
- return ret;
-}
-
-static
-char *get_event_decl_name(struct ctx *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 = concatenate_unary_strings(&iter->u.ctf_expression.left);
- if (!left) {
- goto error;
- }
-
- if (!strcmp(left, "name")) {
- name = concatenate_unary_strings(
- &iter->u.ctf_expression.right);
- if (!name) {
- _PERROR("%s", "unexpected unary expression for event declaration's \"name\" attribute");
- goto error;
- }
- }
-
- g_free(left);
- left = NULL;
-
- if (name) {
- break;
- }
- }
-
- return name;
-
-error:
- g_free(left);
-
- return NULL;
-}
-
-static
-int reset_event_decl_types(struct ctx *ctx,
- struct bt_ctf_event_class *event_class)
-{
- int ret = 0;
- _BT_CTF_FIELD_TYPE_INIT(decl);
-
- /* Event context */
- decl = bt_ctf_field_type_structure_create();
- if (!decl) {
- _PERROR("%s", "cannot create initial, empty event context structure");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_event_class_set_context_type(event_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set initial, empty event context structure");
- goto error;
- }
-
- /* Event payload */
- decl = bt_ctf_field_type_structure_create();
- if (!decl) {
- _PERROR("%s", "cannot create initial, empty event payload structure");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_event_class_set_payload_type(event_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set initial, empty event payload structure");
- goto error;
- }
-
- return 0;
-
-error:
- BT_PUT(decl);
-
- return ret;
-}
-
-static
-int reset_stream_decl_types(struct ctx *ctx,
- struct bt_ctf_stream_class *stream_class)
-{
- int ret = 0;
- _BT_CTF_FIELD_TYPE_INIT(decl);
-
- /* Packet context */
- decl = bt_ctf_field_type_structure_create();
- if (!decl) {
- _PERROR("%s", "cannot create initial, empty packet context structure");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_stream_class_set_packet_context_type(stream_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set initial, empty packet context structure");
- goto error;
- }
-
- /* Event header */
- decl = bt_ctf_field_type_structure_create();
- if (!decl) {
- _PERROR("%s", "cannot create initial, empty event header structure");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_stream_class_set_event_header_type(stream_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set initial, empty event header structure");
- goto error;
- }
-
- /* Event context */
- decl = bt_ctf_field_type_structure_create();
- if (!decl) {
- _PERROR("%s", "cannot create initial, empty stream event context structure");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_stream_class_set_event_context_type(stream_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set initial, empty stream event context structure");
- goto error;
- }
-
- return 0;
-
-error:
- BT_PUT(decl);
-
- return ret;
-}
-
-static
-struct bt_ctf_stream_class *create_reset_stream_class(struct ctx *ctx)
-{
- int ret;
- struct bt_ctf_stream_class *stream_class;
-
- stream_class = bt_ctf_stream_class_create(NULL);
- if (!stream_class) {
- _PERROR("%s", "cannot create stream class");
- goto error;
- }
-
- /*
- * Set packet context, event header, and event context to empty
- * structures to override the default ones.
- */
- ret = reset_stream_decl_types(ctx, stream_class);
- if (ret) {
- goto error;
- }
-
- return stream_class;
-
-error:
- BT_PUT(stream_class);
-
- return NULL;
-}
-
-static
-int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
-{
- int ret = 0;
- int set = 0;
- int64_t event_id;
- struct ctf_node *iter;
- int64_t stream_id = -1;
- char *event_name = NULL;
- struct bt_ctf_event_class *event_class = NULL;
- struct bt_ctf_event_class *eevent_class;
- struct bt_ctf_stream_class *stream_class;
- struct bt_list_head *decl_list = &node->u.event.declaration_list;
-
- if (node->visited) {
- goto end;
- }
-
- node->visited = TRUE;
- event_name = get_event_decl_name(ctx, node);
- if (!event_name) {
- _PERROR("%s",
- "missing \"name\" attribute in event declaration");
- ret = -EPERM;
- goto error;
- }
-
- event_class = bt_ctf_event_class_create(event_name);
-
- /*
- * Set context and fields to empty structures to override the
- * default ones.
- */
- ret = reset_event_decl_types(ctx, event_class);
- if (ret) {
- goto error;
- }
-
-
- ret = ctx_push_scope(ctx);
- if (ret) {
- _PERROR("%s", "cannot push scope");
- goto error;
- }
-
- bt_list_for_each_entry(iter, decl_list, siblings) {
- ret = visit_event_decl_entry(ctx, iter, event_class,
- &stream_id, &set);
- if (ret) {
- goto error;
- }
- }
-
- if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) {
- GList *keys = NULL;
- struct bt_ctf_stream_class *new_stream_class;
-
- /* Allow missing stream_id if there is only a single stream */
- switch (g_hash_table_size(ctx->stream_classes)) {
- case 0:
- /* Create stream if there's none */
- new_stream_class = create_reset_stream_class(ctx);
- if (!new_stream_class) {
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_stream_class_set_id(new_stream_class, 0);
- if (ret) {
- _PERROR("%s", "cannot set stream's ID");
- BT_PUT(new_stream_class);
- goto error;
- }
-
- stream_id = 0;
-
- /* Move reference to visitor's context */
- g_hash_table_insert(ctx->stream_classes,
- (gpointer) stream_id, new_stream_class);
- new_stream_class = NULL;
-
- break;
- case 1:
- /* Single stream: get its ID */
- keys = g_hash_table_get_keys(ctx->stream_classes);
- stream_id = (int64_t) keys->data;
- g_list_free(keys);
- keys = NULL;
- break;
- default:
- _PERROR("%s", "missing \"stream_id\" attribute in event declaration");
- ret = -EPERM;
- goto error;
- }
- }
-
-
-
- assert(stream_id >= 0);
-
- /* We have the stream ID now; borrow the stream class if found */
- stream_class = g_hash_table_lookup(ctx->stream_classes,
- (gpointer) stream_id);
- if (!stream_class) {
- _PERROR("cannot find stream class with ID %" PRId64,
- stream_id);
- ret = -EINVAL;
- goto error;
- }
-
- if (!_IS_SET(&set, _EVENT_ID_SET)) {
- /* Allow only one event without ID per stream */
- if (bt_ctf_stream_class_get_event_class_count(stream_class) !=
- 0) {
- _PERROR("%s",
- "missing \"id\" field in event declaration");
- ret = -EPERM;
- goto error;
- }
-
- /* Automatic ID */
- ret = bt_ctf_event_class_set_id(event_class, 0);
- if (ret) {
- _PERROR("%s", "cannot set event's ID");
- goto error;
- }
- }
-
- event_id = bt_ctf_event_class_get_id(event_class);
- if (event_id < 0) {
- _PERROR("%s", "cannot get event's ID");
- ret = -EINVAL;
- goto error;
- }
-
- eevent_class = bt_ctf_stream_class_get_event_class_by_id(stream_class,
- event_id);
- if (eevent_class) {
- BT_PUT(eevent_class);
- _PERROR("%s", "duplicate event with ID %" PRId64 " in same stream");
- ret = -EEXIST;
- goto error;
- }
-
- eevent_class = bt_ctf_stream_class_get_event_class_by_name(stream_class,
- event_name);
- if (eevent_class) {
- BT_PUT(eevent_class);
- eevent_class = NULL;
- _PERROR("%s",
- "duplicate event with name \"%s\" in same stream");
- ret = -EEXIST;
- goto error;
- }
-
- g_free(event_name);
- ret = bt_ctf_stream_class_add_event_class(stream_class, event_class);
- BT_PUT(event_class);
- event_class = NULL;
-
- if (ret) {
- _PERROR("%s", "cannot add event class to stream class");
- goto error;
- }
-
-end:
- return 0;
-
-error:
- g_free(event_name);
- BT_PUT(event_class);
-
- /* stream_class is borrowed; it still belongs to the hash table */
-
- return ret;
-}
-
-static
-int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
- struct bt_ctf_stream_class *stream_class, int *set)
-{
- int ret = 0;
- char *left = NULL;
- _BT_CTF_FIELD_TYPE_INIT(decl);
-
- switch (node->type) {
- case NODE_TYPEDEF:
- ret = visit_typedef(ctx, node->u._typedef.type_specifier_list,
- &node->u._typedef.type_declarators);
- if (ret) {
- _PERROR("%s",
- "cannot add typedef in \"stream\" declaration");
- goto error;
- }
- break;
- case NODE_TYPEALIAS:
- ret = visit_typealias(ctx, node->u.typealias.target,
- node->u.typealias.alias);
- if (ret) {
- _PERROR("%s", "cannot add typealias in \"stream\" declaration");
- goto error;
- }
- break;
- case NODE_CTF_EXPRESSION:
- {
- left = concatenate_unary_strings(&node->u.ctf_expression.left);
- if (!left) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left, "id")) {
- int64_t id;
- gpointer ptr;
-
- if (_IS_SET(set, _STREAM_ID_SET)) {
- _PERROR_DUP_ATTR("id", "stream declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(&node->u.ctf_expression.right,
- (uint64_t *) &id);
- if (ret || id < 0) {
- _PERROR("%s", "unexpected unary expression for stream declaration's \"id\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ptr = g_hash_table_lookup(ctx->stream_classes,
- (gpointer) id);
- if (ptr) {
- _PERROR("duplicate stream with ID %" PRId64,
- id);
- ret = -EEXIST;
- goto error;
- }
-
- ret = bt_ctf_stream_class_set_id(stream_class, id);
- if (ret) {
- _PERROR("%s",
- "cannot set stream declaration's ID");
- goto error;
- }
-
- _SET(set, _STREAM_ID_SET);
- } else if (!strcmp(left, "event.header")) {
- if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
- _PERROR("%s", "duplicate \"event.header\" entry in stream declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = visit_type_specifier_list(ctx,
- _BT_LIST_FIRST_ENTRY(
- &node->u.ctf_expression.right,
- struct ctf_node, siblings),
- &decl);
- if (ret) {
- _PERROR("%s", "cannot create event header declaration");
- goto error;
- }
-
- assert(decl);
-
- ret = bt_ctf_stream_class_set_event_header_type(
- stream_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set stream's event header declaration");
- goto error;
- }
-
- _SET(set, _STREAM_EVENT_HEADER_SET);
- } else if (!strcmp(left, "event.context")) {
- if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
- _PERROR("%s", "duplicate \"event.context\" entry in stream declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = visit_type_specifier_list(ctx,
- _BT_LIST_FIRST_ENTRY(
- &node->u.ctf_expression.right,
- struct ctf_node, siblings),
- &decl);
- if (ret) {
- _PERROR("%s", "cannot create stream event context declaration");
- goto error;
- }
-
- assert(decl);
-
- ret = bt_ctf_stream_class_set_event_context_type(
- stream_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set stream's event context declaration");
- goto error;
- }
-
- _SET(set, _STREAM_EVENT_CONTEXT_SET);
- } else if (!strcmp(left, "packet.context")) {
- if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
- _PERROR("%s", "duplicate \"packet.context\" entry in stream declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = visit_type_specifier_list(ctx,
- _BT_LIST_FIRST_ENTRY(
- &node->u.ctf_expression.right,
- struct ctf_node, siblings),
- &decl);
- if (ret) {
- _PERROR("%s", "cannot create packet context declaration");
- goto error;
- }
-
- assert(decl);
-
- ret = bt_ctf_stream_class_set_packet_context_type(
- stream_class, decl);
- BT_PUT(decl);
- if (ret) {
- _PERROR("%s", "cannot set stream's packet context declaration");
- goto error;
- }
-
- _SET(set, _STREAM_PACKET_CONTEXT_SET);
- } else {
- _PWARNING("unknown attribute \"%s\" in stream declaration",
- left);
- }
-
- g_free(left);
- left = NULL;
- break;
- }
-
- default:
- ret = -EPERM;
- goto error;
- }
-
- return 0;
-
-error:
- g_free(left);
- BT_PUT(decl);
-
- return ret;
-}
-
-static
-int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
-{
- int64_t id;
- int set = 0;
- int ret = 0;
- struct ctf_node *iter;
- struct bt_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 = create_reset_stream_class(ctx);
- if (!stream_class) {
- ret = -EINVAL;
- goto error;
- }
-
- ret = ctx_push_scope(ctx);
- if (ret) {
- _PERROR("%s", "cannot push scope");
- goto error;
- }
-
- bt_list_for_each_entry(iter, decl_list, siblings) {
- ret = visit_stream_decl_entry(ctx, iter, stream_class, &set);
- if (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 */
- _BT_CTF_FIELD_TYPE_INIT(stream_id_decl);
- _BT_CTF_FIELD_TYPE_INIT(packet_header_decl);
-
- packet_header_decl =
- bt_ctf_trace_get_packet_header_type(ctx->trace);
- if (!packet_header_decl) {
- _PERROR("%s",
- "cannot get trace packet header declaration");
- goto error;
- }
-
- stream_id_decl =
- bt_ctf_field_type_structure_get_field_type_by_name(
- packet_header_decl, "stream_id");
- BT_PUT(packet_header_decl);
- if (!stream_id_decl) {
- _PERROR("%s", "missing \"stream_id\" field in packet header declaration, but \"id\" attribute is declared for stream");
- goto error;
- }
-
- if (!bt_ctf_field_type_is_integer(stream_id_decl)) {
- BT_PUT(stream_id_decl);
- _PERROR("%s", "\"stream_id\" field in packet header declaration is not an integer");
- goto error;
- }
-
- BT_PUT(stream_id_decl);
- } else {
- /* Allow only _one_ ID-less stream */
- if (g_hash_table_size(ctx->stream_classes) != 0) {
- _PERROR("%s",
- "missing \"id\" field in stream declaration");
- ret = -EPERM;
- goto error;
- }
-
- /* Automatic ID: 0 */
- ret = bt_ctf_stream_class_set_id(stream_class, 0);
- }
-
- id = bt_ctf_stream_class_get_id(stream_class);
- if (id < 0) {
- _PERROR("wrong stream ID: %" PRId64, id);
- ret = -EINVAL;
- goto error;
- }
-
- /* Move reference to visitor's context */
- g_hash_table_insert(ctx->stream_classes, (gpointer) (int64_t) id,
- stream_class);
- stream_class = NULL;
-
-end:
- return 0;
-
-error:
- BT_PUT(stream_class);
-
- return ret;
-}
-
-static
-int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
-{
- int ret = 0;
- char *left = NULL;
- _BT_CTF_FIELD_TYPE_INIT(packet_header_decl);
-
- switch (node->type) {
- case NODE_TYPEDEF:
- ret = visit_typedef(ctx, node->u._typedef.type_specifier_list,
- &node->u._typedef.type_declarators);
- if (ret) {
- _PERROR("%s",
- "cannot add typedef in \"trace\" declaration");
- goto error;
- }
- break;
- case NODE_TYPEALIAS:
- ret = visit_typealias(ctx, node->u.typealias.target,
- node->u.typealias.alias);
- if (ret) {
- _PERROR("%s",
- "cannot add typealias in \"trace\" declaration");
- goto error;
- }
- break;
- case NODE_CTF_EXPRESSION:
- {
- left = concatenate_unary_strings(&node->u.ctf_expression.left);
- if (!left) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left, "major")) {
- if (_IS_SET(set, _TRACE_MAJOR_SET)) {
- _PERROR_DUP_ATTR("major", "trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(&node->u.ctf_expression.right,
- &ctx->trace_major);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for trace's \"major\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(set, _TRACE_MAJOR_SET);
- } else if (!strcmp(left, "minor")) {
- if (_IS_SET(set, _TRACE_MINOR_SET)) {
- _PERROR_DUP_ATTR("minor", "trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(&node->u.ctf_expression.right,
- &ctx->trace_minor);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for trace's \"minor\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- _SET(set, _TRACE_MINOR_SET);
- } else if (!strcmp(left, "uuid")) {
- if (_IS_SET(set, _TRACE_UUID_SET)) {
- _PERROR_DUP_ATTR("uuid", "trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_uuid(&node->u.ctf_expression.right,
- ctx->trace_uuid);
- if (ret) {
- _PERROR("%s",
- "invalid trace declaration's UUID");
- goto error;
- }
-
- _SET(set, _TRACE_UUID_SET);
- } else if (!strcmp(left, "byte_order")) {
- /* Native byte order is already known at this stage */
- if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
- _PERROR_DUP_ATTR("byte_order",
- "trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- _SET(set, _TRACE_BYTE_ORDER_SET);
- } else if (!strcmp(left, "packet.header")) {
- if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
- _PERROR("%s", "duplicate \"packet.header\" entry in trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = visit_type_specifier_list(ctx,
- _BT_LIST_FIRST_ENTRY(
- &node->u.ctf_expression.right,
- struct ctf_node, siblings),
- &packet_header_decl);
- if (ret) {
- _PERROR("%s", "cannot create packet header declaration");
- goto error;
- }
-
- assert(packet_header_decl);
- ret = bt_ctf_trace_set_packet_header_type(ctx->trace,
- packet_header_decl);
- BT_PUT(packet_header_decl);
- if (ret) {
- _PERROR("%s", "cannot set trace declaration's packet header declaration");
- goto error;
- }
-
- _SET(set, _TRACE_PACKET_HEADER_SET);
- } else {
- _PWARNING("%s", "unknown attribute \"%s\" in trace declaration");
- }
-
- g_free(left);
- left = NULL;
- break;
- }
- default:
- _PERROR("%s", "unknown expression in trace declaration");
- ret = -EINVAL;
- goto error;
- }
-
- return 0;
-
-error:
- g_free(left);
- BT_PUT(packet_header_decl);
-
- return ret;
-}
-
-static
-int visit_trace_decl(struct ctx *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) {
- _PERROR("%s", "duplicate \"trace\" block");
- ret = -EEXIST;
- goto error;
- }
-
- ret = ctx_push_scope(ctx);
- if (ret) {
- _PERROR("%s", "cannot push scope");
- goto error;
- }
-
- bt_list_for_each_entry(iter, decl_list, siblings) {
- ret = visit_trace_decl_entry(ctx, iter, &set);
- if (ret) {
- ctx_pop_scope(ctx);
- goto error;
- }
- }
-
- ctx_pop_scope(ctx);
-
- if (!_IS_SET(&set, _TRACE_MAJOR_SET)) {
- _PERROR("%s",
- "missing \"major\" attribute in trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (!_IS_SET(&set, _TRACE_MINOR_SET)) {
- _PERROR("%s",
- "missing \"minor\" attribute in trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
- _PERROR("%s", "missing \"byte_order\" attribute in trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- ctx->is_trace_visited = TRUE;
-
-end:
- return 0;
-
-error:
- return ret;
-}
-
-static
-int visit_env(struct ctx *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) {
- _PERROR("%s", "wrong expression in environment entry");
- ret = -EPERM;
- goto error;
- }
-
- left = concatenate_unary_strings(
- &entry_node->u.ctf_expression.left);
- if (!left) {
- _PERROR("%s", "cannot get environment entry name");
- ret = -EINVAL;
- goto error;
- }
-
- if (is_unary_string(right_head)) {
- char *right = concatenate_unary_strings(right_head);
-
- if (!right) {
- _PERROR("unexpected unary expression for environment entry's value (\"%s\")",
- left);
- ret = -EINVAL;
- goto error;
- }
-
- printf_verbose("env.%s = \"%s\"\n", left, right);
- ret = bt_ctf_trace_set_environment_field_string(
- ctx->trace, left, right);
- g_free(right);
-
- if (ret) {
- _PERROR("environment: cannot add entry \"%s\" to trace",
- left);
- goto error;
- }
- } 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(right_head,
- (uint64_t *) &v);
- } else {
- ret = get_unary_signed(right_head, &v);
- }
- if (ret) {
- _PERROR("unexpected unary expression for environment entry's value (\"%s\")",
- left);
- ret = -EINVAL;
- goto error;
- }
-
- printf_verbose("env.%s = %" PRId64 "\n", left, v);
- ret = bt_ctf_trace_set_environment_field_integer(
- ctx->trace, left, v);
- if (ret) {
- _PERROR("environment: cannot add entry \"%s\" to trace",
- left);
- goto error;
- }
- } else {
- printf_verbose("%s: environment entry \"%s\" has unknown type\n",
- __func__, left);
- }
-
- g_free(left);
- left = NULL;
- }
-
-end:
- return 0;
-
-error:
- g_free(left);
-
- return ret;
-}
-
-static
-int set_trace_byte_order(struct ctx *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 = concatenate_unary_strings(
- &node->u.ctf_expression.left);
- if (!left) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left, "byte_order")) {
- enum bt_ctf_byte_order bo;
-
- if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
- _PERROR_DUP_ATTR("byte_order",
- "trace declaration");
- 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->efd,
- right_node);
- if (bo == BT_CTF_BYTE_ORDER_UNKNOWN) {
- _PERROR("%s", "unknown \"byte_order\" attribute in trace declaration");
- ret = -EINVAL;
- goto error;
- } else if (bo == BT_CTF_BYTE_ORDER_NATIVE) {
- _PERROR("%s", "\"byte_order\" attribute cannot be set to \"native\" in trace declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = bt_ctf_trace_set_byte_order(
- ctx->trace, bo);
- if (ret) {
- _PERROR("cannot set trace's byte order (%d)",
- ret);
- goto error;
- }
- }
-
- g_free(left);
- left = NULL;
- }
- }
-
- if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
- _PERROR("%s", "missing \"byte_order\" attribute in trace declaration");
- ret = -EINVAL;
- goto error;
- }
-
- return 0;
-
-error:
- g_free(left);
-
- return ret;
-}
-
-static
-int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
- struct bt_ctf_clock *clock, int *set)
-{
- int ret = 0;
- char *left = NULL;
-
- if (entry_node->type != NODE_CTF_EXPRESSION) {
- ret = -EPERM;
- goto error;
- }
-
- left = concatenate_unary_strings(&entry_node->u.ctf_expression.left);
- if (!left) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!strcmp(left, "name")) {
- char *right;
-
- if (_IS_SET(set, _CLOCK_NAME_SET)) {
- _PERROR_DUP_ATTR("name", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- right = concatenate_unary_strings(
- &entry_node->u.ctf_expression.right);
- if (!right) {
- _PERROR("%s", "unexpected unary expression for clock declaration's \"name\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_clock_set_name(clock, right);
- if (ret) {
- _PERROR("%s", "cannot set clock's name");
- g_free(right);
- goto error;
- }
-
- g_free(right);
- _SET(set, _CLOCK_NAME_SET);
- } else if (!strcmp(left, "uuid")) {
- unsigned char uuid[BABELTRACE_UUID_LEN];
-
- if (_IS_SET(set, _CLOCK_UUID_SET)) {
- _PERROR_DUP_ATTR("uuid", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_uuid(&entry_node->u.ctf_expression.right, uuid);
- if (ret) {
- _PERROR("%s", "invalid clock UUID");
- goto error;
- }
-
- ret = bt_ctf_clock_set_uuid(clock, uuid);
- if (ret) {
- _PERROR("%s", "cannot set clock's UUID");
- goto error;
- }
-
- _SET(set, _CLOCK_UUID_SET);
- } else if (!strcmp(left, "description")) {
- char *right;
-
- if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
- _PERROR_DUP_ATTR("description", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- right = concatenate_unary_strings(
- &entry_node->u.ctf_expression.right);
- if (!right) {
- _PERROR("%s", "unexpected unary expression for clock's \"description\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_clock_set_description(clock, right);
- if (ret) {
- _PERROR("%s", "cannot set clock's description");
- g_free(right);
- goto error;
- }
-
- g_free(right);
- _SET(set, _CLOCK_DESCRIPTION_SET);
- } else if (!strcmp(left, "freq")) {
- uint64_t freq;
-
- if (_IS_SET(set, _CLOCK_FREQ_SET)) {
- _PERROR_DUP_ATTR("freq", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(
- &entry_node->u.ctf_expression.right, &freq);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for clock declaration's \"freq\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_clock_set_frequency(clock, freq);
- if (ret) {
- _PERROR("%s", "cannot set clock's frequency");
- goto error;
- }
-
- _SET(set, _CLOCK_FREQ_SET);
- } else if (!strcmp(left, "precision")) {
- uint64_t precision;
-
- if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
- _PERROR_DUP_ATTR("precision", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(
- &entry_node->u.ctf_expression.right, &precision);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for clock declaration's \"precision\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_clock_set_precision(clock, precision);
- if (ret) {
- _PERROR("%s", "cannot set clock's precision");
- goto error;
- }
-
- _SET(set, _CLOCK_PRECISION_SET);
- } else if (!strcmp(left, "offset_s")) {
- uint64_t offset_s;
-
- if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
- _PERROR_DUP_ATTR("offset_s", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(
- &entry_node->u.ctf_expression.right, &offset_s);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for clock declaration's \"offset_s\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_clock_set_offset_s(clock, offset_s);
- if (ret) {
- _PERROR("%s", "cannot set clock's offset in seconds");
- goto error;
- }
-
- _SET(set, _CLOCK_OFFSET_S_SET);
- } else if (!strcmp(left, "offset")) {
- uint64_t offset;
-
- if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
- _PERROR_DUP_ATTR("offset", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- ret = get_unary_unsigned(
- &entry_node->u.ctf_expression.right, &offset);
- if (ret) {
- _PERROR("%s", "unexpected unary expression for clock declaration's \"offset\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_clock_set_offset(clock, offset);
- if (ret) {
- _PERROR("%s", "cannot set clock's offset in cycles");
- goto error;
- }
-
- _SET(set, _CLOCK_OFFSET_SET);
- } else if (!strcmp(left, "absolute")) {
- struct ctf_node *right;
-
- if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
- _PERROR_DUP_ATTR("absolute", "clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- right = _BT_LIST_FIRST_ENTRY(
- &entry_node->u.ctf_expression.right,
- struct ctf_node, siblings);
- ret = get_boolean(ctx->efd, right);
- if (ret < 0) {
- _PERROR("%s", "unexpected unary expression for clock declaration's \"absolute\" attribute");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_clock_set_is_absolute(clock, ret);
- if (ret) {
- _PERROR("%s", "cannot set clock's absolute option");
- goto error;
- }
-
- _SET(set, _CLOCK_ABSOLUTE_SET);
- } else {
- _PWARNING("unknown attribute \"%s\" in clock declaration",
- left);
- }
-
- g_free(left);
- left = NULL;
-
- return 0;
-
-error:
- g_free(left);
-
- return ret;
-}
-
-static
-int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
-{
- int ret = 0;
- int set = 0;
- struct bt_ctf_clock *clock;
- struct ctf_node *entry_node;
- struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list;
-
- if (clock_node->visited) {
- return 0;
- }
-
- clock_node->visited = TRUE;
- clock = bt_ctf_clock_create(NULL);
- if (!clock) {
- _PERROR("%s", "cannot create clock");
- ret = -ENOMEM;
- goto error;
- }
-
- bt_list_for_each_entry(entry_node, decl_list, siblings) {
- ret = visit_clock_decl_entry(ctx, entry_node, clock, &set);
- if (ret) {
- goto error;
- }
- }
-
- if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
- _PERROR("%s",
- "missing \"name\" attribute in clock declaration");
- ret = -EPERM;
- goto error;
- }
-
- if (bt_ctf_trace_get_clock_count(ctx->trace) != 0) {
- _PERROR("%s", "only CTF traces with a single clock declaration are supported as of this version");
- ret = -EINVAL;
- goto error;
- }
-
- ret = bt_ctf_trace_add_clock(ctx->trace, clock);
- if (ret) {
- _PERROR("%s", "cannot add clock to trace");
- goto error;
- }
-
-error:
- BT_PUT(clock);
-
- return ret;
-}
-
-static
-int visit_root_decl(struct ctx *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_typedef(ctx,
- root_decl_node->u._typedef.type_specifier_list,
- &root_decl_node->u._typedef.type_declarators);
- if (ret) {
- _PERROR("%s", "cannot add typedef in root scope");
- goto end;
- }
- break;
- case NODE_TYPEALIAS:
- ret = visit_typealias(ctx, root_decl_node->u.typealias.target,
- root_decl_node->u.typealias.alias);
- if (ret) {
- _PERROR("%s", "cannot add typealias in root scope");
- goto end;
- }
- break;
- case NODE_TYPE_SPECIFIER_LIST:
- {
- _BT_CTF_FIELD_TYPE_INIT(decl);
-
- /*
- * Just add the type specifier to the root
- * declaration scope. Put local reference.
- */
- ret = visit_type_specifier_list(ctx, root_decl_node, &decl);
- if (ret) {
- assert(!decl);
- goto end;
- }
-
- BT_PUT(decl);
- break;
- }
- default:
- ret = -EPERM;
- goto end;
- }
-
-end:
- return ret;
-}
-
-static
-int add_stream_classes_to_trace(struct ctx *ctx)
-{
- int ret;
- GHashTableIter iter;
- gpointer key, stream_class;
-
- g_hash_table_iter_init(&iter, ctx->stream_classes);
-
- while (g_hash_table_iter_next(&iter, &key, &stream_class)) {
- ret = bt_ctf_trace_add_stream_class(ctx->trace,
- stream_class);
- if (ret) {
- int64_t id = bt_ctf_stream_class_get_id(stream_class);
- _PERROR("cannot add stream class %" PRId64 " to trace",
- id);
- goto end;
- }
- }
-
-end:
- return ret;
-}
-
-int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
- struct bt_ctf_trace **trace)
-{
- int ret = 0;
- struct ctx *ctx = NULL;
- _BT_CTF_FIELD_TYPE_INIT(packet_header_decl);
-
- printf_verbose("CTF visitor: AST -> CTF IR...\n");
-
- *trace = bt_ctf_trace_create();
- if (!*trace) {
- _FPERROR(efd, "%s", "cannot create trace");
- ret = -ENOMEM;
- goto error;
- }
-
- /* Set packet header to an empty struct tu override the default one */
- packet_header_decl = bt_ctf_field_type_structure_create();
-
- if (!packet_header_decl) {
- _FPERROR(efd,
- "%s",
- "cannot create initial, empty packet header structure");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = bt_ctf_trace_set_packet_header_type(*trace, packet_header_decl);
- BT_PUT(packet_header_decl);
- if (ret) {
- _FPERROR(efd,
- "%s",
- "cannot set initial, empty packet header structure");
- goto error;
- }
-
- ctx = ctx_create(*trace, efd);
- if (!ctx) {
- _FPERROR(efd, "%s", "cannot create visitor context");
- ret = -ENOMEM;
- goto error;
- }
-
- switch (node->type) {
- case NODE_ROOT:
- {
- struct ctf_node *iter;
- int got_trace_decl = FALSE;
- int found_callsite = FALSE;
-
- /*
- * Find trace declaration's byte order first (for early
- * type aliases).
- */
- bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
- if (got_trace_decl) {
- _PERROR("%s", "duplicate trace declaration");
- goto error;
- }
-
- ret = set_trace_byte_order(ctx, iter);
- if (ret) {
- _PERROR("cannot set trace's byte order (%d)",
- ret);
- goto error;
- }
-
- got_trace_decl = TRUE;
- }
-
- if (!got_trace_decl) {
- _PERROR("no trace declaration found (%d)", ret);
- ret = -EPERM;
- goto error;
- }
-
- /*
- * Visit clocks first since any early integer can be mapped
- * to one.
- */
- bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
- ret = visit_clock_decl(ctx, iter);
- if (ret) {
- _PERROR("error while visiting clock declaration (%d)",
- ret);
- goto error;
- }
- }
-
- /*
- * 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) {
- _PERROR("error while visiting root declaration (%d)",
- ret);
- goto error;
- }
- }
-
- /* Callsite are not supported */
- bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
- found_callsite = TRUE;
- break;
- }
-
- if (found_callsite) {
- _PWARNING("%s", "\"callsite\" blocks are not supported as of this version");
- }
-
- /* Environment */
- bt_list_for_each_entry(iter, &node->u.root.env, siblings) {
- ret = visit_env(ctx, iter);
- if (ret) {
- _PERROR("error while visiting environment block (%d)",
- ret);
- goto error;
- }
- }
-
- /* Trace */
- bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
- ret = visit_trace_decl(ctx, iter);
- if (ret) {
- _PERROR("%s", "error while visiting trace declaration");
- goto error;
- }
- }
-
- /* Streams */
- bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
- ret = visit_stream_decl(ctx, iter);
- if (ret) {
- _PERROR("%s", "error while visiting stream declaration");
- goto error;
- }
- }
-
- /* Events */
- bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
- ret = visit_event_decl(ctx, iter);
- if (ret) {
- _PERROR("%s", "error while visiting event declaration");
- goto error;
- }
- }
- break;
- }
- case NODE_UNKNOWN:
- default:
- _PERROR("unknown node type: %d", (int) node->type);
- ret = -EINVAL;
- goto error;
- }
-
- /* Add stream classes to trace now */
- ret = add_stream_classes_to_trace(ctx);
- if (ret) {
- _PERROR("%s", "cannot add stream classes to trace");
- }
-
- ctx_destroy(ctx);
- printf_verbose("done!\n");
-
- return ret;
-
-error:
- BT_PUT(packet_header_decl);
- ctx_destroy(ctx);
- BT_PUT(*trace);
-
- return ret;
-}
+++ /dev/null
-/*
- * ctf-visitor-parent-links.c
- *
- * Common Trace Format Metadata Parent Link Creator.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/list.h>
-#include "ctf-scanner.h"
-#include "ctf-parser.h"
-#include "ctf-ast.h"
-
-#define fprintf_dbg(fd, fmt, args...) fprintf(fd, "%s: " fmt, __func__, ## args)
-
-static
-int ctf_visitor_unary_expression(FILE *fd, int depth, struct ctf_node *node)
-{
- int ret = 0;
-
- switch (node->u.unary_expression.link) {
- case UNARY_LINK_UNKNOWN:
- case UNARY_DOTLINK:
- case UNARY_ARROWLINK:
- case UNARY_DOTDOTDOT:
- break;
- default:
- fprintf(fd, "[error] %s: unknown expression link type %d\n", __func__,
- (int) 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(fd, depth + 1,
- node->u.unary_expression.u.sbrac_exp);
- if (ret)
- return ret;
- break;
-
- case UNARY_UNKNOWN:
- default:
- fprintf(fd, "[error] %s: unknown expression type %d\n", __func__,
- (int) node->u.unary_expression.type);
- return -EINVAL;
- }
- return 0;
-}
-
-static
-int ctf_visitor_type_specifier(FILE *fd, int depth, struct ctf_node *node)
-{
- int ret;
-
- switch (node->u.type_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.type_specifier.node->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, node->u.type_specifier.node);
- if (ret)
- return ret;
- break;
-
- case TYPESPEC_UNKNOWN:
- default:
- fprintf(fd, "[error] %s: unknown type specifier %d\n", __func__,
- (int) node->u.type_specifier.type);
- return -EINVAL;
- }
- return 0;
-}
-
-static
-int ctf_visitor_type_declarator(FILE *fd, int depth, struct ctf_node *node)
-{
- int ret = 0;
- struct ctf_node *iter;
-
- depth++;
-
- bt_list_for_each_entry(iter, &node->u.type_declarator.pointers,
- siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
-
- switch (node->u.type_declarator.type) {
- case TYPEDEC_ID:
- break;
- case TYPEDEC_NESTED:
- if (node->u.type_declarator.u.nested.type_declarator) {
- node->u.type_declarator.u.nested.type_declarator->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1,
- node->u.type_declarator.u.nested.type_declarator);
- if (ret)
- return ret;
- }
- if (!node->u.type_declarator.u.nested.abstract_array) {
- bt_list_for_each_entry(iter, &node->u.type_declarator.u.nested.length,
- siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- }
- if (node->u.type_declarator.bitfield_len) {
- node->u.type_declarator.bitfield_len = node;
- ret = ctf_visitor_parent_links(fd, depth + 1,
- node->u.type_declarator.bitfield_len);
- if (ret)
- return ret;
- }
- break;
- case TYPEDEC_UNKNOWN:
- default:
- fprintf(fd, "[error] %s: unknown type declarator %d\n", __func__,
- (int) node->u.type_declarator.type);
- return -EINVAL;
- }
- depth--;
- return 0;
-}
-
-int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node)
-{
- 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(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- depth--;
- break;
- case NODE_UNARY_EXPRESSION:
- return ctf_visitor_unary_expression(fd, depth, node);
-
- case NODE_TYPEDEF:
- depth++;
- node->u._typedef.type_specifier_list->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, node->u._typedef.type_specifier_list);
- if (ret)
- return ret;
- bt_list_for_each_entry(iter, &node->u._typedef.type_declarators, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- depth--;
- break;
- case NODE_TYPEALIAS_TARGET:
- depth++;
- node->u.typealias_target.type_specifier_list->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias_target.type_specifier_list);
- if (ret)
- return ret;
- bt_list_for_each_entry(iter, &node->u.typealias_target.type_declarators, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- depth--;
- break;
- case NODE_TYPEALIAS_ALIAS:
- depth++;
- node->u.typealias_alias.type_specifier_list->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias_alias.type_specifier_list);
- if (ret)
- return ret;
- bt_list_for_each_entry(iter, &node->u.typealias_alias.type_declarators, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- depth--;
- break;
- case NODE_TYPEALIAS:
- node->u.typealias.target->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias.target);
- if (ret)
- return ret;
- node->u.typealias.alias->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias.alias);
- if (ret)
- return ret;
- break;
-
- case NODE_TYPE_SPECIFIER_LIST:
- bt_list_for_each_entry(iter, &node->u.type_specifier_list.head, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- break;
-
- case NODE_TYPE_SPECIFIER:
- ret = ctf_visitor_type_specifier(fd, depth, node);
- if (ret)
- return ret;
- break;
- case NODE_POINTER:
- break;
- case NODE_TYPE_DECLARATOR:
- ret = ctf_visitor_type_declarator(fd, depth, node);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- break;
- case NODE_ENUM:
- depth++;
- if (node->u._enum.container_type) {
- ret = ctf_visitor_parent_links(fd, depth + 1, node->u._enum.container_type);
- if (ret)
- return ret;
- }
-
- bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- depth--;
- break;
- case NODE_STRUCT_OR_VARIANT_DECLARATION:
- node->u.struct_or_variant_declaration.type_specifier_list->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1,
- node->u.struct_or_variant_declaration.type_specifier_list);
- if (ret)
- return ret;
- bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.type_declarators, siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u._struct.min_align,
- siblings) {
- iter->parent = node;
- ret = ctf_visitor_parent_links(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- break;
-
- case NODE_UNKNOWN:
- default:
- fprintf(fd, "[error] %s: unknown node type %d\n", __func__,
- (int) node->type);
- return -EINVAL;
- }
- return ret;
-}
+++ /dev/null
-/*
- * ctf-visitor-semantic-validator.c
- *
- * Common Trace Format Metadata Semantic Validator.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/list.h>
-#include "ctf-scanner.h"
-#include "ctf-parser.h"
-#include "ctf-ast.h"
-
-#define _bt_list_first_entry(ptr, type, member) \
- bt_list_entry((ptr)->next, type, member)
-
-#define fprintf_dbg(fd, fmt, args...) fprintf(fd, "%s: " fmt, __func__, ## args)
-
-static
-int _ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node);
-
-static
-int ctf_visitor_unary_expression(FILE *fd, int depth, struct ctf_node *node)
-{
- 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) {
- fprintf(fd, "[error]: semantic error (left child of a ctf expression is only allowed to be a string)\n");
-
- 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:
- fprintf(fd, "[error]: semantic error (children of type declarator and enum can only be unsigned numeric constants or references to fields (a.b.c))\n");
- 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:
- fprintf(fd, "[error]: semantic error (structure alignment attribute can only be unsigned numeric constants)\n");
- 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.
- */
- fprintf(fd, "[error]: semantic error (nested unary expressions not allowed ( () and [] ))\n");
- 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) {
- fprintf(fd, "[error]: semantic error (empty link not allowed except on first node of unary expression (need to separate nodes with \".\" or \"->\")\n");
- 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) {
- fprintf(fd, "[error]: semantic error (links \".\" and \"->\" are only allowed as children of ctf expression)\n");
- goto errperm;
- }
- /*
- * Only strings can be separated linked by . or ->.
- * This includes "", '' and non-quoted identifiers.
- */
- if (node->u.unary_expression.type != UNARY_STRING) {
- fprintf(fd, "[error]: semantic error (links \".\" and \"->\" are only allowed to separate strings and identifiers)\n");
- 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) {
- fprintf(fd, "[error]: semantic error (links \".\" and \"->\" are not allowed before first node of the unary expression list)\n");
- goto errperm;
- }
- break;
- case UNARY_DOTDOTDOT:
- /* We only allow ... link between children of enumerator. */
- if (node->parent->type != NODE_ENUMERATOR) {
- fprintf(fd, "[error]: semantic error (link \"...\" is only allowed within enumerator)\n");
- 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) {
- fprintf(fd, "[error]: semantic error (link \"...\" is not allowed on the first node of the unary expression list)\n");
- goto errperm;
- }
- break;
- default:
- fprintf(fd, "[error] %s: unknown expression link type %d\n", __func__,
- (int) node->u.unary_expression.link);
- return -EINVAL;
- }
- return 0;
-
-errinval:
- fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
- node_type(node->parent), node_type(node));
- return -EINVAL; /* Incoherent structure */
-
-errperm:
- fprintf(fd, "[error] %s: semantic error (parent type %s for node type %s)\n", __func__,
- node_type(node->parent), node_type(node));
- return -EPERM; /* Structure not allowed */
-}
-
-static
-int ctf_visitor_type_specifier_list(FILE *fd, int depth, struct ctf_node *node)
-{
- 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:
- fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
- node_type(node->parent), node_type(node));
- return -EINVAL; /* Incoherent structure */
-}
-
-static
-int ctf_visitor_type_specifier(FILE *fd, int depth, struct ctf_node *node)
-{
- 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:
- fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
- node_type(node->parent), node_type(node));
- return -EINVAL; /* Incoherent structure */
-}
-
-static
-int ctf_visitor_type_declarator(FILE *fd, int depth, struct ctf_node *node)
-{
- int ret = 0;
- struct ctf_node *iter;
-
- depth++;
-
- switch (node->parent->type) {
- case NODE_TYPE_DECLARATOR:
- /*
- * A nested type declarator is not allowed to contain pointers.
- */
- if (!bt_list_empty(&node->u.type_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 typealias).
- * NOT accepting alias with identifier. The declarator should
- * be either empty or contain pointer(s).
- */
- if (node->u.type_declarator.type == TYPEDEC_NESTED)
- goto errperm;
- bt_list_for_each_entry(iter, &node->parent->u.typealias_alias.type_specifier_list->u.type_specifier_list.head,
- siblings) {
- switch (iter->u.type_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.type_declarator.pointers))
- goto errperm;
- break;
- default:
- break;
- }
- }
- if (node->u.type_declarator.type == TYPEDEC_ID &&
- node->u.type_declarator.u.id != NULL)
- 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.type_declarator.pointers,
- siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
-
- switch (node->u.type_declarator.type) {
- case TYPEDEC_ID:
- break;
- case TYPEDEC_NESTED:
- {
- if (node->u.type_declarator.u.nested.type_declarator) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1,
- node->u.type_declarator.u.nested.type_declarator);
- if (ret)
- return ret;
- }
- if (!node->u.type_declarator.u.nested.abstract_array) {
- bt_list_for_each_entry(iter, &node->u.type_declarator.u.nested.length,
- siblings) {
- if (iter->type != NODE_UNARY_EXPRESSION) {
- fprintf(fd, "[error] %s: expecting unary expression as length\n", __func__);
- return -EINVAL;
- }
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- } else {
- if (node->parent->type == NODE_TYPEALIAS_TARGET) {
- fprintf(fd, "[error] %s: abstract array declarator not permitted as target of typealias\n", __func__);
- return -EINVAL;
- }
- }
- if (node->u.type_declarator.bitfield_len) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1,
- node->u.type_declarator.bitfield_len);
- if (ret)
- return ret;
- }
- break;
- }
- case TYPEDEC_UNKNOWN:
- default:
- fprintf(fd, "[error] %s: unknown type declarator %d\n", __func__,
- (int) node->u.type_declarator.type);
- return -EINVAL;
- }
- depth--;
- return 0;
-
-errinval:
- fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
- node_type(node->parent), node_type(node));
- return -EINVAL; /* Incoherent structure */
-
-errperm:
- fprintf(fd, "[error] %s: semantic error (parent type %s for node type %s)\n", __func__,
- node_type(node->parent), node_type(node));
- return -EPERM; /* Structure not allowed */
-}
-
-static
-int _ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node)
-{
- 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(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- depth--;
- break;
- case NODE_UNARY_EXPRESSION:
- return ctf_visitor_unary_expression(fd, depth, node);
-
- 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(fd, depth + 1,
- node->u._typedef.type_specifier_list);
- if (ret)
- return ret;
- bt_list_for_each_entry(iter, &node->u._typedef.type_declarators, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- 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(fd, depth + 1,
- node->u.typealias_target.type_specifier_list);
- if (ret)
- return ret;
- nr_declarators = 0;
- bt_list_for_each_entry(iter, &node->u.typealias_target.type_declarators, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- if (ret)
- return ret;
- nr_declarators++;
- }
- if (nr_declarators > 1) {
- fprintf(fd, "[error] %s: Too many declarators in typealias alias (%d, max is 1)\n", __func__, 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(fd, depth + 1,
- node->u.typealias_alias.type_specifier_list);
- if (ret)
- return ret;
- nr_declarators = 0;
- bt_list_for_each_entry(iter, &node->u.typealias_alias.type_declarators, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- if (ret)
- return ret;
- nr_declarators++;
- }
- if (nr_declarators > 1) {
- fprintf(fd, "[error] %s: Too many declarators in typealias alias (%d, max is 1)\n", __func__, 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(fd, depth + 1, node->u.typealias.target);
- if (ret)
- return ret;
- ret = _ctf_visitor_semantic_check(fd, depth + 1, node->u.typealias.alias);
- if (ret)
- return ret;
- break;
-
- case NODE_TYPE_SPECIFIER_LIST:
- ret = ctf_visitor_type_specifier_list(fd, depth, node);
- if (ret)
- return ret;
- break;
- case NODE_TYPE_SPECIFIER:
- ret = ctf_visitor_type_specifier(fd, depth, node);
- 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_type_declarator(fd, depth, node);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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) {
- fprintf(fd, "[error]: semantic error (first unary expression of enumerator is unexpected)\n");
- 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) {
- fprintf(fd, "[error]: semantic error (second unary expression of enumerator is unexpected)\n");
- goto errperm;
- }
- break;
- default:
- goto errperm;
- }
- }
- }
-
- bt_list_for_each_entry(iter, &node->u.enumerator.values, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- 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(fd, depth + 1, node->u._enum.container_type);
- if (ret)
- return ret;
-
- bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- 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(fd, depth + 1,
- node->u.struct_or_variant_declaration.type_specifier_list);
- if (ret)
- return ret;
- bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.type_declarators, siblings) {
- ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- 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(fd, depth + 1, iter);
- if (ret)
- return ret;
- }
- break;
-
- case NODE_UNKNOWN:
- default:
- fprintf(fd, "[error] %s: unknown node type %d\n", __func__,
- (int) node->type);
- return -EINVAL;
- }
- return ret;
-
-errinval:
- fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
- node_type(node->parent), node_type(node));
- return -EINVAL; /* Incoherent structure */
-
-errperm:
- fprintf(fd, "[error] %s: semantic error (parent type %s for node type %s)\n", __func__,
- node_type(node->parent), node_type(node));
- return -EPERM; /* Structure not allowed */
-}
-
-int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node)
-{
- 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.
- */
- printf_verbose("CTF visitor: parent links creation... ");
- ret = ctf_visitor_parent_links(fd, depth, node);
- if (ret)
- return ret;
- printf_verbose("done.\n");
- printf_verbose("CTF visitor: semantic check... ");
- ret = _ctf_visitor_semantic_check(fd, depth, node);
- if (ret)
- return ret;
- printf_verbose("done.\n");
- return ret;
-}
+++ /dev/null
-/*
- * objstack.c
- *
- * Common Trace Format Object Stack.
- *
- * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <babeltrace/list.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/align.h>
-
-#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[];
-};
-
-BT_HIDDEN
-struct objstack *objstack_create(void)
-{
- struct objstack *objstack;
- struct objstack_node *node;
-
- objstack = calloc(1, sizeof(*objstack));
- if (!objstack)
- return NULL;
- node = calloc(sizeof(struct objstack_node) + OBJSTACK_INIT_LEN,
- sizeof(char));
- if (!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);
-}
-
-BT_HIDDEN
-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 = calloc(sizeof(struct objstack_node) + (last_node->len << 1),
- sizeof(char));
- if (!new_node) {
- return NULL;
- }
- bt_list_add_tail(&new_node->node, &objstack->head);
- new_node->len = last_node->len << 1;
- return new_node;
-}
-
-BT_HIDDEN
-void *objstack_alloc(struct objstack *objstack, size_t len)
-{
- struct objstack_node *last_node;
- void *p;
-
- len = 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;
-}
+++ /dev/null
-#ifndef _OBJSTACK_H
-#define _OBJSTACK_H
-
-/*
- * objstack.h
- *
- * Common Trace Format Object Stack.
- *
- * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-struct objstack;
-
-BT_HIDDEN
-struct objstack *objstack_create(void);
-BT_HIDDEN
-void objstack_destroy(struct objstack *objstack);
-
-/*
- * Allocate len bytes of zeroed memory.
- * Return NULL on error.
- */
-BT_HIDDEN
-void *objstack_alloc(struct objstack *objstack, size_t len);
-
-#endif /* _OBJSTACK_H */
AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
-SUBDIRS = fs lttng-live
+SUBDIRS = common fs lttng-live
plugindir = "$(PLUGINSDIR)"
plugin_LTLIBRARIES = libbabeltrace-plugin-ctf.la
--- /dev/null
+SUBDIRS = btr notif-iter metadata
+
+AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-common.la
+libbabeltrace_plugin_ctf_common_la_SOURCES =
+libbabeltrace_plugin_ctf_common_la_LIBADD = \
+ $(builddir)/btr/libctf-btr.la \
+ $(builddir)/metadata/libctf-parser.la \
+ $(builddir)/metadata/libctf-ast.la \
+ $(builddir)/notif-iter/libctf-notif-iter.la
--- /dev/null
+/*
+ * Babeltrace - CTF binary type reader (BTR)
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <string.h>
+#include <babeltrace/bitfield.h>
+#include <babeltrace/ctf-ir/field-types.h>
+#include <babeltrace/ref.h>
+#include <babeltrace/align.h>
+#include <glib.h>
+
+#include "btr.h"
+
+#define PRINT_ERR_STREAM btr->err_stream
+#define PRINT_PREFIX "ctf-btr"
+#include "print.h"
+
+#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 type of base field, one of:
+ *
+ * * Structure
+ * * Array
+ * * Sequence
+ * * Variant
+ *
+ * Owned by this.
+ */
+ struct bt_ctf_field_type *base_type;
+
+ /* Length of base field (always 1 for variant types) */
+ int64_t base_len;
+
+ /* Lndex of next field to read */
+ int64_t index;
+};
+
+/* Visit stack */
+struct stack {
+ /* Entries (struct stack_entry *) (top is last element) */
+ GPtrArray *entries;
+};
+
+/* Reading states */
+enum btr_state {
+ BTR_STATE_NEXT_FIELD,
+ BTR_STATE_ALIGN_BASIC,
+ BTR_STATE_ALIGN_COMPOUND,
+ BTR_STATE_READ_BASIC_BEGIN,
+ BTR_STATE_READ_BASIC_CONTINUE,
+ BTR_STATE_DONE,
+};
+
+/* Binary type reader */
+struct bt_ctf_btr {
+ /* Bisit stack */
+ struct stack *stack;
+
+ /* Error stream */
+ FILE *err_stream;
+
+ /* Current basic field type */
+ struct bt_ctf_field_type *cur_basic_field_type;
+
+ /* Current state */
+ enum btr_state state;
+
+ /*
+ * Last basic field type's byte order.
+ *
+ * This is used to detect errors since two contiguous basic
+ * types for which the common boundary is not the boundary of
+ * a byte cannot have different byte orders.
+ *
+ * This is set to BT_CTF_BYTE_ORDER_UNKNOWN on reset and when
+ * the last basic field type was a string type.
+ */
+ enum bt_ctf_byte_order last_bo;
+
+ /* Current byte order (copied to last_bo after a successful read) */
+ enum bt_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_ctf_btr_cbs cbs;
+
+ /* Private data */
+ void *data;
+ } user;
+};
+
+static
+void stack_entry_free_func(gpointer data)
+{
+ struct stack_entry *entry = data;
+
+ BT_PUT(entry->base_type);
+ g_free(entry);
+}
+
+static
+struct stack *stack_new(void)
+{
+ struct stack *stack = NULL;
+
+ stack = g_new0(struct stack, 1);
+ if (!stack) {
+ goto error;
+ }
+
+ stack->entries = g_ptr_array_new_with_free_func(stack_entry_free_func);
+ if (!stack->entries) {
+ goto error;
+ }
+
+ return stack;
+
+error:
+ g_free(stack);
+
+ return NULL;
+}
+
+static
+void stack_destroy(struct stack *stack)
+{
+ if (!stack) {
+ return;
+ }
+
+ g_ptr_array_free(stack->entries, TRUE);
+ g_free(stack);
+}
+
+static inline
+int64_t get_compound_field_type_length(struct bt_ctf_btr *btr,
+ struct bt_ctf_field_type *field_type)
+{
+ int64_t length;
+
+ switch (bt_ctf_field_type_get_type_id(field_type)) {
+ case BT_CTF_TYPE_ID_STRUCT:
+ length = (int64_t) bt_ctf_field_type_structure_get_field_count(
+ field_type);
+ break;
+ case BT_CTF_TYPE_ID_VARIANT:
+ /* Variant field types always "contain" a single type */
+ length = 1;
+ break;
+ case BT_CTF_TYPE_ID_ARRAY:
+ length = bt_ctf_field_type_array_get_length(field_type);
+ break;
+ case BT_CTF_TYPE_ID_SEQUENCE:
+ length = btr->user.cbs.query.get_sequence_length(field_type,
+ btr->user.data);
+ break;
+ default:
+ PERR("Cannot get length of field type with type ID %d\n",
+ bt_ctf_field_type_get_type_id(field_type));
+ length = BT_CTF_BTR_STATUS_ERROR;
+ }
+
+ return length;
+}
+
+static
+int stack_push(struct stack *stack, struct bt_ctf_field_type *base_type,
+ size_t base_len)
+{
+ int ret = 0;
+ struct stack_entry *entry;
+
+ assert(stack);
+ assert(base_type);
+
+ entry = g_new0(struct stack_entry, 1);
+ if (!entry) {
+ ret = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ entry->base_type = base_type;
+ bt_get(entry->base_type);
+ entry->base_len = base_len;
+ g_ptr_array_add(stack->entries, entry);
+
+end:
+ return ret;
+}
+
+static
+int stack_push_with_len(struct bt_ctf_btr *btr,
+ struct bt_ctf_field_type *base_type)
+{
+ int ret = 0;
+ int64_t base_len = get_compound_field_type_length(btr, base_type);
+
+ if (base_len < 0) {
+ PERR("Failed to get compound field type's length\n");
+ ret = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ ret = stack_push(btr->stack, base_type, (size_t) base_len);
+
+end:
+ return ret;
+}
+
+static inline
+unsigned int stack_size(struct stack *stack)
+{
+ assert(stack);
+
+ return stack->entries->len;
+}
+
+static
+void stack_pop(struct stack *stack)
+{
+ assert(stack);
+ assert(stack_size(stack));
+ g_ptr_array_remove_index(stack->entries, stack->entries->len - 1);
+}
+
+static inline
+bool stack_empty(struct stack *stack)
+{
+ return stack_size(stack) == 0;
+}
+
+static
+void stack_clear(struct stack *stack)
+{
+ assert(stack);
+
+ if (!stack_empty(stack)) {
+ g_ptr_array_remove_range(stack->entries, 0, stack_size(stack));
+ }
+
+ assert(stack_empty(stack));
+}
+
+static inline
+struct stack_entry *stack_top(struct stack *stack)
+{
+ assert(stack);
+ assert(stack_size(stack));
+
+ return g_ptr_array_index(stack->entries, stack->entries->len - 1);
+}
+
+static inline
+size_t available_bits(struct bt_ctf_btr *btr)
+{
+ return btr->buf.sz - btr->buf.at;
+}
+
+static inline
+void consume_bits(struct bt_ctf_btr *btr, size_t incr)
+{
+ btr->buf.at += incr;
+}
+
+static inline
+bool has_enough_bits(struct bt_ctf_btr *btr, size_t sz)
+{
+ return available_bits(btr) >= sz;
+}
+
+static inline
+bool at_least_one_bit_left(struct bt_ctf_btr *btr)
+{
+ return has_enough_bits(btr, 1);
+}
+
+static inline
+size_t packet_at(struct bt_ctf_btr *btr)
+{
+ return btr->buf.packet_offset + btr->buf.at;
+}
+
+static inline
+size_t buf_at_from_addr(struct bt_ctf_btr *btr)
+{
+ /*
+ * Considering this:
+ *
+ * ====== offset ===== (17)
+ *
+ * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
+ * ^
+ * addr (0) ==== at ==== (12)
+ *
+ * We want this:
+ *
+ * =============================== (29)
+ */
+ return btr->buf.offset + btr->buf.at;
+}
+
+static inline
+int get_basic_field_type_size(struct bt_ctf_btr *btr,
+ struct bt_ctf_field_type *field_type)
+{
+ int size;
+
+ switch (bt_ctf_field_type_get_type_id(field_type)) {
+ case BT_CTF_TYPE_ID_INTEGER:
+ size = bt_ctf_field_type_integer_get_size(field_type);
+ break;
+ case BT_CTF_TYPE_ID_FLOAT:
+ {
+ int exp_dig, mant_dig;
+
+ exp_dig =
+ bt_ctf_field_type_floating_point_get_exponent_digits(
+ field_type);
+ mant_dig =
+ bt_ctf_field_type_floating_point_get_mantissa_digits(
+ field_type);
+ if (exp_dig < 0 || mant_dig < 0) {
+ PERR("Failed to get floating point number type's sizes\n");
+ size = BT_CTF_BTR_STATUS_ERROR;
+ }
+
+ size = exp_dig + mant_dig;
+ break;
+ }
+ case BT_CTF_TYPE_ID_ENUM:
+ {
+ struct bt_ctf_field_type *int_type;
+
+ int_type = bt_ctf_field_type_enumeration_get_container_type(
+ field_type);
+ if (!int_type) {
+ PERR("Failed to get enumeration type's container type\n");
+ size = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ size = get_basic_field_type_size(btr, int_type);
+ BT_PUT(int_type);
+ break;
+ }
+ default:
+ size = BT_CTF_BTR_STATUS_ERROR;
+ break;
+ }
+
+end:
+ return size;
+}
+
+static
+void stitch_reset(struct bt_ctf_btr *btr)
+{
+ btr->stitch.offset = 0;
+ btr->stitch.at = 0;
+}
+
+static inline
+size_t stitch_at_from_addr(struct bt_ctf_btr *btr)
+{
+ return btr->stitch.offset + btr->stitch.at;
+}
+
+static
+void stitch_append_from_buf(struct bt_ctf_btr *btr, 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(btr));
+ buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(btr));
+ nb_bytes = BITS_TO_BYTES_CEIL(sz);
+ assert(nb_bytes > 0);
+ memcpy(&btr->stitch.buf[stitch_byte_at], &btr->buf.addr[buf_byte_at],
+ nb_bytes);
+ btr->stitch.at += sz;
+ consume_bits(btr, sz);
+}
+
+static
+void stitch_append_from_remaining_buf(struct bt_ctf_btr *btr)
+{
+ stitch_append_from_buf(btr, available_bits(btr));
+}
+
+static
+void stitch_set_from_remaining_buf(struct bt_ctf_btr *btr)
+{
+ stitch_reset(btr);
+ btr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(btr));
+ stitch_append_from_remaining_buf(btr);
+}
+
+static inline
+enum bt_ctf_btr_status read_unsigned_bitfield(const uint8_t *buf, size_t at,
+ int64_t field_size, enum bt_ctf_byte_order bo, uint64_t *v)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ switch (bo) {
+ case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
+ case BT_CTF_BYTE_ORDER_NETWORK:
+ bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
+ break;
+ case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
+ bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
+ break;
+ default:
+ status = BT_CTF_BTR_STATUS_ERROR;
+ }
+
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status read_signed_bitfield(const uint8_t *buf, size_t at,
+ int64_t field_size, enum bt_ctf_byte_order bo, int64_t *v)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ switch (bo) {
+ case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
+ case BT_CTF_BYTE_ORDER_NETWORK:
+ bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
+ break;
+ case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
+ bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
+ break;
+ default:
+ status = BT_CTF_BTR_STATUS_ERROR;
+ }
+
+ return status;
+}
+
+typedef enum bt_ctf_btr_status (* read_basic_and_call_cb_t)(struct bt_ctf_btr *,
+ const uint8_t *, size_t);
+
+static inline
+enum bt_ctf_btr_status validate_contiguous_bo(struct bt_ctf_btr *btr,
+ enum bt_ctf_byte_order next_bo)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ /* Always valid when at a byte boundary */
+ if (packet_at(btr) % 8 == 0) {
+ goto end;
+ }
+
+ /* Always valid if last byte order is unknown */
+ if (btr->last_bo == BT_CTF_BYTE_ORDER_UNKNOWN) {
+ goto end;
+ }
+
+ /* Always valid if next byte order is unknown */
+ if (next_bo == BT_CTF_BYTE_ORDER_UNKNOWN) {
+ goto end;
+ }
+
+ /* Make sure last byte order is compatible with the next byte order */
+ switch (btr->last_bo) {
+ case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
+ case BT_CTF_BYTE_ORDER_NETWORK:
+ if (next_bo != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
+ next_bo != BT_CTF_BYTE_ORDER_NETWORK) {
+ status = BT_CTF_BTR_STATUS_ERROR;
+ }
+ break;
+ case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
+ if (next_bo != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN) {
+ status = BT_CTF_BTR_STATUS_ERROR;
+ }
+ break;
+ default:
+ status = BT_CTF_BTR_STATUS_ERROR;
+ }
+
+end:
+ return status;
+}
+
+static
+enum bt_ctf_btr_status read_basic_float_and_call_cb(struct bt_ctf_btr *btr,
+ const uint8_t *buf, size_t at)
+{
+ int ret;
+ double dblval;
+ int64_t field_size;
+ enum bt_ctf_byte_order bo;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
+ bo = bt_ctf_field_type_get_byte_order(btr->cur_basic_field_type);
+ btr->cur_bo = bo;
+
+ switch (field_size) {
+ case 32:
+ {
+ uint64_t v;
+ union {
+ uint32_t u;
+ float f;
+ } f32;
+
+ ret = bt_ctf_field_type_floating_point_get_mantissa_digits(
+ btr->cur_basic_field_type);
+ assert(ret == 24);
+ ret = bt_ctf_field_type_floating_point_get_exponent_digits(
+ btr->cur_basic_field_type);
+ assert(ret == 8);
+ status = read_unsigned_bitfield(buf, at, field_size, bo, &v);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("Failed to reader unsigned bitfield\n");
+ goto end;
+ }
+
+ f32.u = (uint32_t) v;
+ dblval = (double) f32.f;
+ break;
+ }
+ case 64:
+ {
+ union {
+ uint64_t u;
+ double d;
+ } f64;
+
+ ret = bt_ctf_field_type_floating_point_get_mantissa_digits(
+ btr->cur_basic_field_type);
+ assert(ret == 53);
+ ret = bt_ctf_field_type_floating_point_get_exponent_digits(
+ btr->cur_basic_field_type);
+ assert(ret == 11);
+ status = read_unsigned_bitfield(buf, at, field_size, bo,
+ &f64.u);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("Failed to reader unsigned bitfield\n");
+ goto end;
+ }
+
+ dblval = f64.d;
+ break;
+ }
+ default:
+ /* Only 32-bit and 64-bit fields are supported currently */
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ if (btr->user.cbs.types.floating_point) {
+ status = btr->user.cbs.types.floating_point(dblval,
+ btr->cur_basic_field_type, btr->user.data);
+ }
+
+end:
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_int_and_call(struct bt_ctf_btr *btr,
+ const uint8_t *buf, size_t at, struct bt_ctf_field_type *int_type,
+ struct bt_ctf_field_type *orig_type)
+{
+ int signd;
+ int64_t field_size;
+ enum bt_ctf_byte_order bo;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ signd = bt_ctf_field_type_integer_get_signed(int_type);
+ field_size = get_basic_field_type_size(btr, int_type);
+ if (field_size < 1) {
+ PERR("Failed to get basic field type's size\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ bo = bt_ctf_field_type_get_byte_order(int_type);
+
+ /*
+ * Update current byte order now because we could be reading
+ * the integer value of an enumeration type, and thus we know
+ * here the actual supporting integer type's byte order.
+ */
+ btr->cur_bo = bo;
+
+ if (signd) {
+ int64_t v;
+
+ status = read_signed_bitfield(buf, at, field_size, bo, &v);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("Failed to reader signed bitfield\n");
+ goto end;
+ }
+
+ if (btr->user.cbs.types.signed_int) {
+ status = btr->user.cbs.types.signed_int(v,
+ btr->cur_basic_field_type, btr->user.data);
+ }
+ } else {
+ uint64_t v;
+
+ status = read_unsigned_bitfield(buf, at, field_size, bo, &v);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("Failed to reader unsigned bitfield\n");
+ goto end;
+ }
+
+ if (btr->user.cbs.types.unsigned_int) {
+ status = btr->user.cbs.types.unsigned_int(v,
+ btr->cur_basic_field_type, btr->user.data);
+ }
+ }
+
+end:
+ return status;
+}
+
+static
+enum bt_ctf_btr_status read_basic_int_and_call_cb(struct bt_ctf_btr *btr,
+ const uint8_t *buf, size_t at)
+{
+ return read_basic_int_and_call(btr, buf, at, btr->cur_basic_field_type,
+ btr->cur_basic_field_type);
+}
+
+static
+enum bt_ctf_btr_status read_basic_enum_and_call_cb(struct bt_ctf_btr *btr,
+ const uint8_t *buf, size_t at)
+{
+ struct bt_ctf_field_type *int_field_type;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ int_field_type = bt_ctf_field_type_enumeration_get_container_type(
+ btr->cur_basic_field_type);
+ if (!int_field_type) {
+ PERR("Failed to get enumeration type's container type\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ status = read_basic_int_and_call(btr, buf, at,
+ int_field_type, btr->cur_basic_field_type);
+
+end:
+ BT_PUT(int_field_type);
+
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_type_and_call_continue(struct bt_ctf_btr *btr,
+ read_basic_and_call_cb_t read_basic_and_call_cb)
+{
+ size_t available;
+ int64_t field_size;
+ int64_t needed_bits;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ if (!at_least_one_bit_left(btr)) {
+ status = BT_CTF_BTR_STATUS_EOF;
+ goto end;
+ }
+
+ field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
+ if (field_size < 1) {
+ PERR("Failed to get basic field type's size\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ available = available_bits(btr);
+ needed_bits = field_size - btr->stitch.at;
+ if (needed_bits <= available) {
+ /* We have all the bits; append to stitch, then decode */
+ stitch_append_from_buf(btr, needed_bits);
+ status = read_basic_and_call_cb(btr, btr->stitch.buf,
+ btr->stitch.offset);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("Failed to read basic field\n");
+ goto end;
+ }
+
+ if (stack_empty(btr->stack)) {
+ /* Root is a basic type */
+ btr->state = BTR_STATE_DONE;
+ } else {
+ /* Go to next field */
+ stack_top(btr->stack)->index++;
+ btr->state = BTR_STATE_NEXT_FIELD;
+ btr->last_bo = btr->cur_bo;
+ }
+ goto end;
+ }
+
+ /* We are here; it means we don't have enough data to decode this */
+ stitch_append_from_remaining_buf(btr);
+ status = BT_CTF_BTR_STATUS_EOF;
+
+end:
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_type_and_call_begin(struct bt_ctf_btr *btr,
+ read_basic_and_call_cb_t read_basic_and_call_cb)
+{
+ size_t available;
+ int64_t field_size;
+ enum bt_ctf_byte_order bo;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ if (!at_least_one_bit_left(btr)) {
+ status = BT_CTF_BTR_STATUS_EOF;
+ goto end;
+ }
+
+ field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
+
+ if (field_size < 1) {
+ PERR("Failed to get basic field type's size\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ bo = bt_ctf_field_type_get_byte_order(btr->cur_basic_field_type);
+ status = validate_contiguous_bo(btr, bo);
+
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("Invalid contiguous byte orders\n");
+ goto end;
+ }
+
+ available = available_bits(btr);
+
+ if (field_size <= available) {
+ /* We have all the bits; decode and set now */
+ status = read_basic_and_call_cb(btr, btr->buf.addr,
+ buf_at_from_addr(btr));
+
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("Failed to read basic type\n");
+ goto end;
+ }
+
+ consume_bits(btr, field_size);
+
+ if (stack_empty(btr->stack)) {
+ /* Root is a basic type */
+ btr->state = BTR_STATE_DONE;
+ } else {
+ /* Go to next field */
+ stack_top(btr->stack)->index++;
+ btr->state = BTR_STATE_NEXT_FIELD;
+ btr->last_bo = btr->cur_bo;
+ }
+
+ goto end;
+ }
+
+ /* We are here; it means we don't have enough data to decode this */
+ stitch_set_from_remaining_buf(btr);
+ btr->state = BTR_STATE_READ_BASIC_CONTINUE;
+ status = BT_CTF_BTR_STATUS_EOF;
+
+end:
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_int_type_and_call_begin(
+ struct bt_ctf_btr *btr)
+{
+ return read_basic_type_and_call_begin(btr, read_basic_int_and_call_cb);
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_int_type_and_call_continue(
+ struct bt_ctf_btr *btr)
+{
+ return read_basic_type_and_call_continue(btr,
+ read_basic_int_and_call_cb);
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_float_type_and_call_begin(
+ struct bt_ctf_btr *btr)
+{
+ return read_basic_type_and_call_begin(btr,
+ read_basic_float_and_call_cb);
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_float_type_and_call_continue(
+ struct bt_ctf_btr *btr)
+{
+ return read_basic_type_and_call_continue(btr,
+ read_basic_float_and_call_cb);
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_enum_type_and_call_begin(
+ struct bt_ctf_btr *btr)
+{
+ return read_basic_type_and_call_begin(btr,
+ read_basic_enum_and_call_cb);
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_enum_type_and_call_continue(
+ struct bt_ctf_btr *btr)
+{
+ return read_basic_type_and_call_continue(btr,
+ read_basic_enum_and_call_cb);
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_string_type_and_call(
+ struct bt_ctf_btr *btr, bool begin)
+{
+ size_t buf_at_bytes;
+ const uint8_t *result;
+ size_t available_bytes;
+ const uint8_t *first_chr;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ if (!at_least_one_bit_left(btr)) {
+ status = BT_CTF_BTR_STATUS_EOF;
+ goto end;
+ }
+
+ assert(buf_at_from_addr(btr) % 8 == 0);
+ available_bytes = BITS_TO_BYTES_FLOOR(available_bits(btr));
+ buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(btr));
+ first_chr = &btr->buf.addr[buf_at_bytes];
+ result = memchr(first_chr, '\0', available_bytes);
+
+ if (begin && btr->user.cbs.types.string_begin) {
+ status = btr->user.cbs.types.string_begin(
+ btr->cur_basic_field_type, btr->user.data);
+
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("string_begin() user callback function failed\n");
+ goto end;
+ }
+ }
+
+ if (!result) {
+ /* No null character yet */
+ if (btr->user.cbs.types.string) {
+ status = btr->user.cbs.types.string(
+ (const char *) first_chr,
+ available_bytes, btr->cur_basic_field_type,
+ btr->user.data);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("string() user callback function failed\n");
+ goto end;
+ }
+ }
+
+ consume_bits(btr, BYTES_TO_BITS(available_bytes));
+ btr->state = BTR_STATE_READ_BASIC_CONTINUE;
+ status = BT_CTF_BTR_STATUS_EOF;
+ } else {
+ /* Found the null character */
+ size_t result_len = (size_t) (result - first_chr);
+
+ if (btr->user.cbs.types.string && result_len) {
+ status = btr->user.cbs.types.string(
+ (const char *) first_chr,
+ result_len, btr->cur_basic_field_type,
+ btr->user.data);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("string() user callback function failed\n");
+ goto end;
+ }
+ }
+
+ if (btr->user.cbs.types.string_end) {
+ status = btr->user.cbs.types.string_end(
+ btr->cur_basic_field_type, btr->user.data);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("string_end() user callback function failed\n");
+ goto end;
+ }
+ }
+
+ consume_bits(btr, BYTES_TO_BITS(result_len + 1));
+
+ if (stack_empty(btr->stack)) {
+ /* Root is a basic type */
+ btr->state = BTR_STATE_DONE;
+ } else {
+ /* Go to next field */
+ stack_top(btr->stack)->index++;
+ btr->state = BTR_STATE_NEXT_FIELD;
+ btr->last_bo = btr->cur_bo;
+ }
+ }
+
+end:
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_begin_state(struct bt_ctf_btr *btr)
+{
+ enum bt_ctf_btr_status status;
+
+ assert(btr->cur_basic_field_type);
+
+ switch (bt_ctf_field_type_get_type_id(btr->cur_basic_field_type)) {
+ case BT_CTF_TYPE_ID_INTEGER:
+ status = read_basic_int_type_and_call_begin(btr);
+ break;
+ case BT_CTF_TYPE_ID_FLOAT:
+ status = read_basic_float_type_and_call_begin(btr);
+ break;
+ case BT_CTF_TYPE_ID_ENUM:
+ status = read_basic_enum_type_and_call_begin(btr);
+ break;
+ case BT_CTF_TYPE_ID_STRING:
+ status = read_basic_string_type_and_call(btr, true);
+ break;
+ default:
+ assert(false);
+ }
+
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status read_basic_continue_state(struct bt_ctf_btr *btr)
+{
+ enum bt_ctf_btr_status status;
+
+ assert(btr->cur_basic_field_type);
+
+ switch (bt_ctf_field_type_get_type_id(btr->cur_basic_field_type)) {
+ case BT_CTF_TYPE_ID_INTEGER:
+ status = read_basic_int_type_and_call_continue(btr);
+ break;
+ case BT_CTF_TYPE_ID_FLOAT:
+ status = read_basic_float_type_and_call_continue(btr);
+ break;
+ case BT_CTF_TYPE_ID_ENUM:
+ status = read_basic_enum_type_and_call_continue(btr);
+ break;
+ case BT_CTF_TYPE_ID_STRING:
+ status = read_basic_string_type_and_call(btr, false);
+ break;
+ default:
+ assert(false);
+ }
+
+ return status;
+}
+
+static inline
+size_t bits_to_skip_to_align_to(struct bt_ctf_btr *btr, size_t align)
+{
+ size_t aligned_packet_at;
+
+ aligned_packet_at = ALIGN(packet_at(btr), align);
+
+ return aligned_packet_at - packet_at(btr);
+}
+
+static inline
+enum bt_ctf_btr_status align_type_state(struct bt_ctf_btr *btr,
+ struct bt_ctf_field_type *field_type, enum btr_state next_state)
+{
+ int field_alignment;
+ size_t skip_bits;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ /* Get field's alignment */
+ field_alignment = bt_ctf_field_type_get_alignment(field_type);
+ if (field_alignment < 0) {
+ PERR("Failed to get type alignment\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ /*
+ * 0 means "undefined" for variants; what we really want is 1
+ * (always aligned)
+ */
+ if (field_alignment == 0) {
+ field_alignment = 1;
+ }
+
+ /* Compute how many bits we need to skip */
+ skip_bits = bits_to_skip_to_align_to(btr, field_alignment);
+
+ /* Nothing to skip? aligned */
+ if (skip_bits == 0) {
+ btr->state = next_state;
+ goto end;
+ }
+
+ /* Make sure there's at least one bit left */
+ if (!at_least_one_bit_left(btr)) {
+ status = BT_CTF_BTR_STATUS_EOF;
+ goto end;
+ }
+
+ /* Consume as many bits as possible in what's left */
+ consume_bits(btr, MIN(available_bits(btr), skip_bits));
+
+ /* Are we done now? */
+ skip_bits = bits_to_skip_to_align_to(btr, field_alignment);
+
+ if (skip_bits == 0) {
+ /* Yes: go to next state */
+ btr->state = next_state;
+ goto end;
+ } else {
+ /* No: need more data */
+ status = BT_CTF_BTR_STATUS_EOF;
+ }
+
+end:
+ return status;
+}
+
+static inline
+bool is_compound_type(struct bt_ctf_field_type *field_type)
+{
+ enum bt_ctf_type_id id = bt_ctf_field_type_get_type_id(field_type);
+
+ return id == BT_CTF_TYPE_ID_STRUCT || id == BT_CTF_TYPE_ID_ARRAY ||
+ id == BT_CTF_TYPE_ID_SEQUENCE || id == BT_CTF_TYPE_ID_VARIANT;
+}
+
+static inline
+enum bt_ctf_btr_status next_field_state(struct bt_ctf_btr *btr)
+{
+ int ret;
+ struct stack_entry *top;
+ struct bt_ctf_field_type *next_field_type = NULL;
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ if (stack_empty(btr->stack)) {
+ goto end;
+ }
+
+ top = stack_top(btr->stack);
+
+ /* Are we done with this base type? */
+ while (top->index == top->base_len) {
+ if (btr->user.cbs.types.compound_end) {
+ status = btr->user.cbs.types.compound_end(
+ top->base_type, btr->user.data);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("compound_end() user callback function failed\n");
+ goto end;
+ }
+ }
+
+ stack_pop(btr->stack);
+
+ /* Are we done with the root type? */
+ if (stack_empty(btr->stack)) {
+ btr->state = BTR_STATE_DONE;
+ goto end;
+ }
+
+ top = stack_top(btr->stack);
+ top->index++;
+ }
+
+ /* Get next field's type */
+ switch (bt_ctf_field_type_get_type_id(top->base_type)) {
+ case BT_CTF_TYPE_ID_STRUCT:
+ ret = bt_ctf_field_type_structure_get_field(
+ top->base_type, NULL, &next_field_type,
+ top->index);
+ if (ret) {
+ next_field_type = NULL;
+ }
+ break;
+ case BT_CTF_TYPE_ID_ARRAY:
+ next_field_type =
+ bt_ctf_field_type_array_get_element_type(
+ top->base_type);
+ break;
+ case BT_CTF_TYPE_ID_SEQUENCE:
+ next_field_type =
+ bt_ctf_field_type_sequence_get_element_type(
+ top->base_type);
+ break;
+ case BT_CTF_TYPE_ID_VARIANT:
+ /* Variant types are dynamic: query the user, he should know! */
+ next_field_type =
+ btr->user.cbs.query.get_variant_type(
+ top->base_type, btr->user.data);
+ break;
+ default:
+ break;
+ }
+
+ if (!next_field_type) {
+ PERR("Failed to get next field's type\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ if (is_compound_type(next_field_type)) {
+ if (btr->user.cbs.types.compound_begin) {
+ status = btr->user.cbs.types.compound_begin(
+ next_field_type, btr->user.data);
+ if (status != BT_CTF_BTR_STATUS_OK) {
+ PERR("compound_begin() user callback function failed\n");
+ goto end;
+ }
+ }
+
+ ret = stack_push_with_len(btr, next_field_type);
+ if (ret) {
+ PERR("Failed to push compound type onto the stack\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ /* Next state: align a compound type */
+ btr->state = BTR_STATE_ALIGN_COMPOUND;
+ } else {
+ /* Replace current basic field type */
+ BT_MOVE(btr->cur_basic_field_type, next_field_type);
+
+ /* Next state: align a basic type */
+ btr->state = BTR_STATE_ALIGN_BASIC;
+ }
+
+end:
+ BT_PUT(next_field_type);
+
+ return status;
+}
+
+static inline
+enum bt_ctf_btr_status handle_state(struct bt_ctf_btr *btr)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+
+ switch (btr->state) {
+ case BTR_STATE_NEXT_FIELD:
+ status = next_field_state(btr);
+ break;
+ case BTR_STATE_ALIGN_BASIC:
+ status = align_type_state(btr, btr->cur_basic_field_type,
+ BTR_STATE_READ_BASIC_BEGIN);
+ break;
+ case BTR_STATE_ALIGN_COMPOUND:
+ status = align_type_state(btr, stack_top(btr->stack)->base_type,
+ BTR_STATE_NEXT_FIELD);
+ break;
+ case BTR_STATE_READ_BASIC_BEGIN:
+ status = read_basic_begin_state(btr);
+ break;
+ case BTR_STATE_READ_BASIC_CONTINUE:
+ status = read_basic_continue_state(btr);
+ break;
+ case BTR_STATE_DONE:
+ break;
+ }
+
+ return status;
+}
+
+struct bt_ctf_btr *bt_ctf_btr_create(struct bt_ctf_btr_cbs cbs, void *data,
+ FILE *err_stream)
+{
+ struct bt_ctf_btr *btr;
+
+ btr = g_new0(struct bt_ctf_btr, 1);
+ if (!btr) {
+ PERR("Failed to allocate memory for binary type reader\n");
+ goto end;
+ }
+
+ btr->stack = stack_new();
+ if (!btr->stack) {
+ PERR("Failed to create stack\n");
+ bt_ctf_btr_destroy(btr);
+ btr = NULL;
+ goto end;
+ }
+
+ btr->state = BTR_STATE_NEXT_FIELD;
+ btr->user.cbs = cbs;
+ btr->user.data = data;
+ btr->err_stream = err_stream;
+
+end:
+ return btr;
+}
+
+void bt_ctf_btr_destroy(struct bt_ctf_btr *btr)
+{
+ if (btr->stack) {
+ stack_destroy(btr->stack);
+ }
+
+ BT_PUT(btr->cur_basic_field_type);
+ g_free(btr);
+}
+
+static
+void reset(struct bt_ctf_btr *btr)
+{
+ stack_clear(btr->stack);
+ BT_PUT(btr->cur_basic_field_type);
+ stitch_reset(btr);
+ btr->buf.addr = NULL;
+ btr->last_bo = BT_CTF_BYTE_ORDER_UNKNOWN;
+}
+
+size_t bt_ctf_btr_start(struct bt_ctf_btr *btr,
+ struct bt_ctf_field_type *type, const uint8_t *buf,
+ size_t offset, size_t packet_offset, size_t sz,
+ enum bt_ctf_btr_status *status)
+{
+ assert(btr);
+ assert(buf);
+ assert(sz > 0);
+ assert(BYTES_TO_BITS(sz) > offset);
+ reset(btr);
+ btr->buf.addr = buf;
+ btr->buf.offset = offset;
+ btr->buf.at = 0;
+ btr->buf.packet_offset = packet_offset;
+ btr->buf.buf_sz = sz;
+ btr->buf.sz = BYTES_TO_BITS(sz) - offset;
+ *status = BT_CTF_BTR_STATUS_OK;
+
+ /* Set root type */
+ if (is_compound_type(type)) {
+ /* Compound type: push on visit stack */
+ int stack_ret;
+
+ if (btr->user.cbs.types.compound_begin) {
+ *status = btr->user.cbs.types.compound_begin(
+ type, btr->user.data);
+ if (*status != BT_CTF_BTR_STATUS_OK) {
+ PERR("compound_begin() user callback function failed\n");
+ goto end;
+ }
+ }
+
+ stack_ret = stack_push_with_len(btr, type);
+ if (stack_ret) {
+ PERR("Failed to push initial compound type onto the stack\n");
+ *status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ btr->state = BTR_STATE_ALIGN_COMPOUND;
+ } else {
+ /* Basic type: set as current basic type */
+ btr->cur_basic_field_type = type;
+ bt_get(btr->cur_basic_field_type);
+ btr->state = BTR_STATE_ALIGN_BASIC;
+ }
+
+ /* Run the machine! */
+ while (true) {
+ *status = handle_state(btr);
+ if (*status != BT_CTF_BTR_STATUS_OK) {
+ break;
+ } else if (btr->state == BTR_STATE_DONE) {
+ break;
+ }
+ }
+
+ /* Update packet offset for next time */
+ btr->buf.packet_offset += btr->buf.at;
+
+end:
+ return btr->buf.at;
+}
+
+size_t bt_ctf_btr_continue(struct bt_ctf_btr *btr,
+ const uint8_t *buf, size_t sz,
+ enum bt_ctf_btr_status *status)
+{
+ assert(btr);
+ assert(buf);
+ assert(sz > 0);
+ btr->buf.addr = buf;
+ btr->buf.offset = 0;
+ btr->buf.at = 0;
+ btr->buf.buf_sz = sz;
+ btr->buf.sz = BYTES_TO_BITS(sz);
+ *status = BT_CTF_BTR_STATUS_OK;
+
+ /* Continue running the machine */
+ while (true) {
+ *status = handle_state(btr);
+ if (*status != BT_CTF_BTR_STATUS_OK) {
+ break;
+ } else if (btr->state == BTR_STATE_DONE) {
+ break;
+ }
+ }
+
+ /* Update packet offset for next time */
+ btr->buf.packet_offset += btr->buf.at;
+
+ return btr->buf.at;
+}
--- /dev/null
+define ctf-btr-show-stack
+ if (stack_empty($arg0))
+ printf "stack is empty!\n"
+ else
+ set $stack_size = stack_size($arg0)
+ set $stack_at = (int) ($stack_size - 1)
+ printf "%3s %10s %4s %3s\n", "pos", "base addr", "blen", "idx"
+
+ while ($stack_at >= 0)
+ set $stack_entry = (struct stack_entry *) g_ptr_array_index($arg0->entries, $stack_at)
+
+ if ($stack_at == $stack_size - 1)
+ printf "%3d %10p %3d %3d <-- top\n", $stack_at, \
+ $stack_entry->base_type, $stack_entry->base_len, \
+ $stack_entry->index
+ else
+ printf "%3d %10p %3d %3d\n", $stack_at, \
+ $stack_entry->base_type, $stack_entry->base_len, \
+ $stack_entry->index
+ end
+ set $stack_at = $stack_at - 1
+ end
+ end
+end
--- /dev/null
+#ifndef CTF_BTR_H
+#define CTF_BTR_H
+
+/*
+ * Babeltrace - CTF binary type reader (BTR)
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <babeltrace/ctf-ir/field-types.h>
+#include <babeltrace/babeltrace-internal.h>
+
+/**
+ * @file ctf-btr.h
+ *
+ * Event-driven CTF binary type reader (BTR).
+ *
+ * This is a common, internal API used by CTF source plugins. It allows
+ * a binary CTF IR field type to be decoded from user-provided buffers.
+ * As the type is decoded (and, possibly, its nested types), registered
+ * user callback functions are called.
+ *
+ * This API is only concerned with reading one CTF type 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 types are
+ * requested to the user when needed.
+ */
+
+/**
+ * Binary type reader API status codes.
+ */
+enum bt_ctf_btr_status {
+ /**
+ * The binary stream reader reached the end of the user-provided
+ * buffer, but data is still needed to finish decoding the
+ * requested type.
+ *
+ * The user needs to call bt_ctf_btr_continue() as long as
+ * #BT_CTF_BTR_STATUS_EOF is returned to complete the decoding
+ * process of a given type.
+ */
+ BT_CTF_BTR_STATUS_EOF = -4,
+
+ /** Invalid argument. */
+ BT_CTF_BTR_STATUS_INVAL = -3,
+
+ /** General error. */
+ BT_CTF_BTR_STATUS_ERROR = -1,
+
+ /** Everything okay. */
+ BT_CTF_BTR_STATUS_OK = 0,
+};
+
+/** Type reader. */
+struct bt_ctf_btr;
+
+/*
+ * Type reader user callback functions.
+ */
+struct bt_ctf_btr_cbs {
+ /**
+ * Type callback functions.
+ *
+ * This CTF binary type reader is event-driven. The following
+ * functions are called during the decoding process, either when
+ * a compound type begins/ends, or when a basic type is
+ * completely decoded (along with its value).
+ *
+ * Each function also receives the CTF IR field type associated
+ * with the call, and user data (registered to the type reader
+ * calling them). This field type is a weak reference; the
+ * callback function must use bt_ctf_field_type_get() to keep
+ * its own reference of it.
+ *
+ * Actual CTF IR fields are \em not created here; this would be
+ * the responsibility of a type reader's user (the provider of
+ * those callback functions).
+ *
+ * All the type callback functions return one of the following
+ * values:
+ *
+ * - <b>#BT_CTF_BTR_STATUS_OK</b>: Everything is okay;
+ * continue the decoding process.
+ * - <b>#BT_CTF_BTR_STATUS_ERROR</b>: General error (reported
+ * to type reader's user).
+ *
+ * Any member of this structure may be set to \c NULL, should
+ * a specific notification be not needed.
+ */
+ struct {
+ /**
+ * Called when a signed integer type is completely
+ * decoded. This could also be the supporting signed
+ * integer type of an enumeration type (\p type will
+ * indicate this).
+ *
+ * @param value Signed integer value
+ * @param type Integer or enumeration type (weak
+ * reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* signed_int)(int64_t value,
+ struct bt_ctf_field_type *type, void *data);
+
+ /**
+ * Called when an unsigned integer type is completely
+ * decoded. This could also be the supporting signed
+ * integer type of an enumeration type (\p type will
+ * indicate this).
+ *
+ * @param value Unsigned integer value
+ * @param type Integer or enumeration type (weak
+ * reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* unsigned_int)(uint64_t value,
+ struct bt_ctf_field_type *type, void *data);
+
+ /**
+ * Called when a floating point number type is
+ * completely decoded.
+ *
+ * @param value Floating point number value
+ * @param type Floating point number type (weak
+ * reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* floating_point)(double value,
+ struct bt_ctf_field_type *type, void *data);
+
+ /**
+ * Called when a string type begins.
+ *
+ * All the following user callback function calls will
+ * be made to bt_ctf_btr_cbs::types::string(), each of
+ * them providing one substring of the complete string
+ * type's value.
+ *
+ * @param type Beginning string type (weak reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* string_begin)(
+ struct bt_ctf_field_type *type, void *data);
+
+ /**
+ * Called when a string type's substring is decoded
+ * (between a call to bt_ctf_btr_cbs::types::string_begin()
+ * and a call to bt_ctf_btr_cbs::types::string_end()).
+ *
+ * @param value String value (\em not null-terminated)
+ * @param len String value length
+ * @param type String type (weak reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* string)(const char *value,
+ size_t len, struct bt_ctf_field_type *type,
+ void *data);
+
+ /**
+ * Called when a string type ends.
+ *
+ * @param type Ending string type (weak reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* string_end)(
+ struct bt_ctf_field_type *type, void *data);
+
+ /**
+ * Called when a compound type begins.
+ *
+ * All the following type callback function calls will
+ * signal sequential elements of this compound type,
+ * until the next corresponding
+ * bt_ctf_btr_cbs::types::compound_end() is called.
+ *
+ * If \p type is a variant type, then only one type
+ * callback function call will follow before the call to
+ * bt_ctf_btr_cbs::types::compound_end(). This single
+ * call indicates the selected type of this variant
+ * type.
+ *
+ * @param type Beginning compound type (weak reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* compound_begin)(
+ struct bt_ctf_field_type *type, void *data);
+
+ /**
+ * Called when a compound type ends.
+ *
+ * @param type Ending compound type (weak reference)
+ * @param data User data
+ * @returns #BT_CTF_BTR_STATUS_OK or
+ * #BT_CTF_BTR_STATUS_ERROR
+ */
+ enum bt_ctf_btr_status (* compound_end)(
+ struct bt_ctf_field_type *type, void *data);
+ } types;
+
+ /**
+ * Query callback functions are used when the type reader needs
+ * dynamic information, i.e. a sequence type's current length
+ * or a variant type's current selected type.
+ *
+ * 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
+ * type.
+ *
+ * @param type Sequence type (weak reference)
+ * @param data User data
+ * @returns Sequence length or
+ * #BT_CTF_BTR_STATUS_ERROR on error
+ */
+ int64_t (* get_sequence_length)(struct bt_ctf_field_type *type,
+ void *data);
+
+ /**
+ * Called to query the current selected type of a given
+ * variant type.
+ *
+ * @param type Variant type (weak reference)
+ * @param data User data
+ * @returns Current selected type (owned by
+ * this) or \c NULL on error
+ */
+ struct bt_ctf_field_type * (* get_variant_type)(
+ struct bt_ctf_field_type *type, void *data);
+ } query;
+};
+
+/**
+ * Creates a CTF binary type reader.
+ *
+ * @param cbs User callback functions
+ * @param data User data (passed to user callback functions)
+ * @param err_stream Error stream (can be \c NULL to disable)
+ * @returns New binary type reader on success, or \c NULL on error
+ */
+struct bt_ctf_btr *bt_ctf_btr_create(struct bt_ctf_btr_cbs cbs, void *data,
+ FILE *err_stream);
+
+/**
+ * Destroys a CTF binary type reader, freeing all internal resources.
+ *
+ * @param btr Binary type reader
+ */
+void bt_ctf_btr_destroy(struct bt_ctf_btr *btr);
+
+/**
+ * Decodes a given CTF type 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:
+ *
+ * - <b>#BT_CTF_BTR_STATUS_OK</b>: Decoding is done.
+ * - <b>#BT_CTF_BTR_STATUS_EOF</b>: The end of the buffer was reached,
+ * but more data is needed to finish the decoding process of the
+ * requested type. The user needs to call bt_ctf_btr_continue()
+ * as long as #BT_CTF_BTR_STATUS_EOF is returned to complete the
+ * decoding process of the original type.
+ * - <b>#BT_CTF_BTR_STATUS_INVAL</b>: Invalid argument.
+ * - <b>#BT_CTF_BTR_STATUS_ERROR</b>: General error.
+ *
+ * Calling this function resets the type reader's internal state. If
+ * #BT_CTF_BTR_STATUS_EOF is returned, bt_ctf_btr_continue() needs to
+ * be called next, \em not bt_ctf_btr_decode().
+ *
+ * @param btr Binary type reader
+ * @param type Type to decode (weak reference)
+ * @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 type (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_ctf_btr_start(struct bt_ctf_btr *btr,
+ struct bt_ctf_field_type *type, const uint8_t *buf,
+ size_t offset, size_t packet_offset, size_t sz,
+ enum bt_ctf_btr_status *status);
+
+/**
+ * Continues the decoding process a given CTF type.
+ *
+ * The number of bits consumed by this function is returned.
+ *
+ * The \p status output parameter is where a status is placed, amongst
+ * the following:
+ *
+ * - <b>#BT_CTF_BTR_STATUS_OK</b>: decoding is done.
+ * - <b>#BT_CTF_BTR_STATUS_EOF</b>: the end of the buffer was reached,
+ * but more data is needed to finish the decoding process of the
+ * requested type. The user needs to call bt_ctf_btr_continue()
+ * as long as #BT_CTF_BTR_STATUS_EOF is returned to complete the
+ * decoding process of the original type.
+ * - <b>#BT_CTF_BTR_STATUS_INVAL</b>: invalid argument.
+ * - <b>#BT_CTF_BTR_STATUS_ERROR</b>: general error.
+ *
+ * @param btr Binary type 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_ctf_btr_continue(struct bt_ctf_btr *btr,
+ const uint8_t *buf, size_t sz,
+ enum bt_ctf_btr_status *status);
+
+#endif /* CTF_BTR_H */
--- /dev/null
+#ifndef CTF_BTR_PRINT_H
+#define CTF_BTR_PRINT_H
+
+/*
+ * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <babeltrace/babeltrace-internal.h>
+
+#define PERR(fmt, ...) \
+ do { \
+ if (PRINT_ERR_STREAM) { \
+ fprintf(PRINT_ERR_STREAM, \
+ "Error: " PRINT_PREFIX ": " fmt, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PWARN(fmt, ...) \
+ do { \
+ if (PRINT_ERR_STREAM) { \
+ fprintf(PRINT_ERR_STREAM, \
+ "Warning: " PRINT_PREFIX ": " fmt, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PDBG(fmt, ...) \
+ do { \
+ if (babeltrace_debug) { \
+ fprintf(stderr, \
+ "Debug: " PRINT_PREFIX ": " fmt, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#endif /* CTF_BTR_PRINT_H */
--- /dev/null
+AM_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir)/include -I$(srcdir)
+AM_CFLAGS = $(PACKAGE_CFLAGS)
+BUILT_SOURCES = parser.h parser.c lexer.c
+AM_YFLAGS = -t -d -v
+
+noinst_LTLIBRARIES = libctf-parser.la libctf-ast.la
+
+noinst_HEADERS = scanner.h ast.h scanner-symbols.h
+
+libctf_parser_la_SOURCES = lexer.l parser.y objstack.c
+# ctf-scanner-symbols.h is included to prefix generated yy_* symbols
+# with bt_.
+libctf_parser_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir) \
+ -include $(srcdir)/scanner-symbols.h
+
+libctf_ast_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)
+libctf_ast_la_SOURCES = \
+ visitor-generate-ir.c \
+ visitor-semantic-validator.c \
+ visitor-parent-links.c
+libctf_ast_la_LIBADD = $(top_builddir)/lib/libbabeltrace.la
+
+if BABELTRACE_BUILD_WITH_LIBUUID
+libctf_ast_la_LIBADD += -luuid
+endif
+
+if BABELTRACE_BUILD_WITH_LIBC_UUID
+libctf_ast_la_LIBADD += -lc
+endif
+
+if BABELTRACE_BUILD_WITH_MINGW
+libctf_ast_la_LIBADD += -lrpcrt4 -lintl -liconv -lole32 -lpopt
+endif
+
+CLEANFILES = $(BUILT_SOURCES) parser.output
--- /dev/null
+#ifndef _CTF_AST_H
+#define _CTF_AST_H
+
+/*
+ * ctf-ast.h
+ *
+ * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <glib.h>
+#include <babeltrace/list.h>
+#include <babeltrace/ctf-ir/trace.h>
+
+// 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;
+
+#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
+ NR_NODE_TYPES,
+};
+
+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, typedef,
+ * typealias and type_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, typedef,
+ * typealias and type_specifier_list.
+ */
+ struct bt_list_head declaration_list;
+ } event;
+ struct {
+ /*
+ * Children nodes are ctf_expression, typedef,
+ * typealias and type_specifier_list.
+ */
+ struct bt_list_head declaration_list;
+ } stream;
+ struct {
+ /*
+ * Children nodes are ctf_expression, typedef,
+ * typealias and type_specifier_list.
+ */
+ struct bt_list_head declaration_list;
+ } env;
+ struct {
+ /*
+ * Children nodes are ctf_expression, typedef,
+ * typealias and type_specifier_list.
+ */
+ struct bt_list_head declaration_list;
+ } trace;
+ struct {
+ /*
+ * Children nodes are ctf_expression, typedef,
+ * typealias and type_specifier_list.
+ */
+ struct bt_list_head declaration_list;
+ } clock;
+ struct {
+ /*
+ * Children nodes are ctf_expression, typedef,
+ * typealias and type_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 {
+ enum {
+ UNARY_UNKNOWN = 0,
+ UNARY_STRING,
+ UNARY_SIGNED_CONSTANT,
+ UNARY_UNSIGNED_CONSTANT,
+ UNARY_SBRAC,
+ } 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;
+ enum {
+ UNARY_LINK_UNKNOWN = 0,
+ UNARY_DOTLINK,
+ UNARY_ARROWLINK,
+ UNARY_DOTDOTDOT,
+ } link;
+ } unary_expression;
+ struct {
+ struct ctf_node *type_specifier_list;
+ struct bt_list_head type_declarators;
+ } _typedef;
+ /* new type is "alias", existing type "target" */
+ struct {
+ struct ctf_node *type_specifier_list;
+ struct bt_list_head type_declarators;
+ } typealias_target;
+ struct {
+ struct ctf_node *type_specifier_list;
+ struct bt_list_head type_declarators;
+ } typealias_alias;
+ struct {
+ struct ctf_node *target;
+ struct ctf_node *alias;
+ } typealias;
+ struct {
+ enum {
+ 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,
+ } type;
+ /* For struct, variant and enum */
+ struct ctf_node *node;
+ const char *id_type;
+ } type_specifier;
+ struct {
+ /* list of type_specifier */
+ struct bt_list_head head;
+ } type_specifier_list;
+ struct {
+ unsigned int const_qualifier;
+ } pointer;
+ struct {
+ struct bt_list_head pointers;
+ enum {
+ TYPEDEC_UNKNOWN = 0,
+ TYPEDEC_ID, /* identifier */
+ TYPEDEC_NESTED, /* (), array or sequence */
+ } type;
+ union {
+ char *id;
+ struct {
+ /* typedec has no pointer list */
+ struct ctf_node *type_declarator;
+ /*
+ * unary expression (value) or
+ * type_specifier_list.
+ */
+ struct bt_list_head length;
+ /* for abstract type declarator */
+ unsigned int abstract_array;
+ } nested;
+ } u;
+ struct ctf_node *bitfield_len;
+ } type_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
+ * type_specifier_list.
+ */
+ struct ctf_node *container_type;
+ struct bt_list_head enumerator_list;
+ int has_body;
+ } _enum;
+ struct {
+ struct ctf_node *type_specifier_list;
+ struct bt_list_head type_declarators;
+ } struct_or_variant_declaration;
+ struct {
+ char *name;
+ char *choice;
+ /* list of typedef, typealias and declarations */
+ struct bt_list_head declaration_list;
+ int has_body;
+ } variant;
+ struct {
+ char *name;
+ /* list of typedef, typealias 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 ctf_trace;
+
+BT_HIDDEN
+int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
+ struct bt_ctf_trace **trace);
+
+BT_HIDDEN
+int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node);
+
+BT_HIDDEN
+int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node);
+
+BT_HIDDEN
+int ctf_destroy_metadata(struct ctf_trace *trace);
+
+#endif /* _CTF_AST_H */
--- /dev/null
+%{
+/*
+ * lexer.l
+ *
+ * Common Trace Formal Lexer
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <babeltrace/babeltrace-internal.h>
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+
+#define PARSE_INTEGER_LITERAL(base) \
+ do { \
+ errno = 0; \
+ yylval->ull = strtoull(yytext, NULL, base); \
+ if (errno) { \
+ printfl_perror(yylineno, "Integer literal"); \
+ return ERROR; \
+ } \
+ } while (0)
+
+BT_HIDDEN
+void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src);
+
+static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
+ __attribute__((unused));
+static int input (yyscan_t yyscanner) __attribute__((unused));
+
+BT_HIDDEN
+int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim);
+
+%}
+
+%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);
+<comment_ml>[^*\n]* /* eat anything that's not a '*' */
+<comment_ml>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment_ml>\n
+<comment_ml>"*"+"/" BEGIN(INITIAL);
+
+"//"[^\n]*\n /* skip comment */
+
+L?\"(\\.|[^\\"])*\" { if (import_string(yyextra, yylval, yytext, '\"') < 0) return ERROR; else return STRING_LITERAL; }
+L?\'(\\.|[^\\'])*\' { if (import_string(yyextra, yylval, yytext, '\'') < 0) return ERROR; else return CHARACTER_LITERAL; }
+
+"[" return LSBRAC;
+"]" return RSBRAC;
+"(" return LPAREN;
+")" return RPAREN;
+"{" return LBRAC;
+"}" return RBRAC;
+"->" return RARROW;
+"*" return STAR;
+"+" return PLUS;
+"-" return MINUS;
+"<" return LT;
+">" return GT;
+:= return TYPEASSIGN;
+: return COLON;
+; return SEMICOLON;
+"..." return DOTDOTDOT;
+"." return DOT;
+= return EQUAL;
+"," return COMMA;
+align setstring(yyextra, yylval, yytext); return TOK_ALIGN;
+const setstring(yyextra, yylval, yytext); return CONST;
+char setstring(yyextra, yylval, yytext); return CHAR;
+clock setstring(yyextra, yylval, yytext); return CLOCK;
+double setstring(yyextra, yylval, yytext); return DOUBLE;
+enum setstring(yyextra, yylval, yytext); return ENUM;
+env setstring(yyextra, yylval, yytext); return ENV;
+event setstring(yyextra, yylval, yytext); return EVENT;
+floating_point setstring(yyextra, yylval, yytext); return FLOATING_POINT;
+float setstring(yyextra, yylval, yytext); return FLOAT;
+integer setstring(yyextra, yylval, yytext); return INTEGER;
+int setstring(yyextra, yylval, yytext); return INT;
+long setstring(yyextra, yylval, yytext); return LONG;
+short setstring(yyextra, yylval, yytext); return SHORT;
+signed setstring(yyextra, yylval, yytext); return SIGNED;
+stream setstring(yyextra, yylval, yytext); return STREAM;
+string setstring(yyextra, yylval, yytext); return STRING;
+struct setstring(yyextra, yylval, yytext); return STRUCT;
+trace setstring(yyextra, yylval, yytext); return TRACE;
+callsite setstring(yyextra, yylval, yytext); return CALLSITE;
+typealias setstring(yyextra, yylval, yytext); return TYPEALIAS;
+typedef setstring(yyextra, yylval, yytext); return TYPEDEF;
+unsigned setstring(yyextra, yylval, yytext); return UNSIGNED;
+variant setstring(yyextra, yylval, yytext); return VARIANT;
+void setstring(yyextra, yylval, yytext); return VOID;
+_Bool setstring(yyextra, yylval, yytext); return _BOOL;
+_Complex setstring(yyextra, yylval, yytext); return _COMPLEX;
+_Imaginary setstring(yyextra, yylval, yytext); return _IMAGINARY;
+[1-9]{DIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(10); return INTEGER_LITERAL;
+0{OCTALDIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(8); return INTEGER_LITERAL;
+0[xX]{HEXDIGIT}+{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(16); return INTEGER_LITERAL;
+
+{IDENTIFIER} printf_debug("<IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); if (is_type(yyextra, yytext)) return ID_TYPE; else return IDENTIFIER;
+[ \t\r\n] ; /* ignore */
+. printfl_error(yylineno, "invalid character '0x%02X'", yytext[0]); return ERROR;
+%%
--- /dev/null
+/*
+ * objstack.c
+ *
+ * Common Trace Format Object Stack.
+ *
+ * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <babeltrace/list.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/align.h>
+
+#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[];
+};
+
+BT_HIDDEN
+struct objstack *objstack_create(void)
+{
+ struct objstack *objstack;
+ struct objstack_node *node;
+
+ objstack = calloc(1, sizeof(*objstack));
+ if (!objstack)
+ return NULL;
+ node = calloc(sizeof(struct objstack_node) + OBJSTACK_INIT_LEN,
+ sizeof(char));
+ if (!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);
+}
+
+BT_HIDDEN
+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 = calloc(sizeof(struct objstack_node) + (last_node->len << 1),
+ sizeof(char));
+ if (!new_node) {
+ return NULL;
+ }
+ bt_list_add_tail(&new_node->node, &objstack->head);
+ new_node->len = last_node->len << 1;
+ return new_node;
+}
+
+BT_HIDDEN
+void *objstack_alloc(struct objstack *objstack, size_t len)
+{
+ struct objstack_node *last_node;
+ void *p;
+
+ len = 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;
+}
--- /dev/null
+#ifndef _OBJSTACK_H
+#define _OBJSTACK_H
+
+/*
+ * objstack.h
+ *
+ * Common Trace Format Object Stack.
+ *
+ * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+struct objstack;
+
+BT_HIDDEN
+struct objstack *objstack_create(void);
+BT_HIDDEN
+void objstack_destroy(struct objstack *objstack);
+
+/*
+ * Allocate len bytes of zeroed memory.
+ * Return NULL on error.
+ */
+BT_HIDDEN
+void *objstack_alloc(struct objstack *objstack, size_t len);
+
+#endif /* _OBJSTACK_H */
--- /dev/null
+%{
+/*
+ * ctf-parser.y
+ *
+ * Common Trace Format Metadata Grammar.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <glib.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <babeltrace/list.h>
+#include <babeltrace/babeltrace-internal.h>
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+#include "objstack.h"
+
+BT_HIDDEN
+int yydebug;
+
+/* 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;
+ }
+}
+
+BT_HIDDEN
+int yyparse(struct ctf_scanner *scanner, yyscan_t yyscanner);
+BT_HIDDEN
+int yylex(union YYSTYPE *yyval, yyscan_t yyscanner);
+BT_HIDDEN
+int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals);
+BT_HIDDEN
+int yylex_destroy(yyscan_t yyscanner);
+BT_HIDDEN
+void yyrestart(FILE * in_str, yyscan_t yyscanner);
+BT_HIDDEN
+int yyget_lineno(yyscan_t yyscanner);
+BT_HIDDEN
+char *yyget_text(yyscan_t yyscanner);
+
+static const char *node_type_to_str[] = {
+#define ENTRY(S) [S] = #S,
+ FOREACH_CTF_NODES(ENTRY)
+#undef ENTRY
+};
+
+/*
+ * 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 = {
+ .type = NODE_ERROR,
+};
+
+BT_HIDDEN
+const char *node_type(struct ctf_node *node)
+{
+ if (node->type < NR_NODE_TYPES)
+ return node_type_to_str[node->type];
+ else
+ return NULL;
+}
+
+void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src)
+{
+ lvalp->s = 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;
+ }
+ }
+ assert(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 = objstack_alloc(scanner->objstack, len);
+ if (src[0] == 'L') {
+ // TODO: import wide string
+ printfl_error(yyget_lineno(scanner),
+ "Wide string not supported yet.");
+ 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->types = 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->types);
+}
+
+static void push_scope(struct ctf_scanner *scanner)
+{
+ struct ctf_scanner_scope *ns;
+
+ printf_debug("push scope\n");
+ ns = 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;
+
+ printf_debug("pop scope\n");
+ 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 = (int) (long) g_hash_table_lookup(s->types, id);
+ printf_debug("lookup %p %s %d\n", s, id, ret);
+ return ret;
+}
+
+BT_HIDDEN
+int is_type(struct ctf_scanner *scanner, const char *id)
+{
+ struct ctf_scanner_scope *it;
+ int ret = 0;
+
+ for (it = scanner->cs; it != NULL; it = it->parent) {
+ if (lookup_type(it, id)) {
+ ret = 1;
+ break;
+ }
+ }
+ printf_debug("is type %s %d\n", id, ret);
+ return ret;
+}
+
+static void add_type(struct ctf_scanner *scanner, char *id)
+{
+ printf_debug("add type %s\n", id);
+ if (lookup_type(scanner->cs, id))
+ return;
+ g_hash_table_insert(scanner->cs->types, id, id);
+}
+
+static struct ctf_node *make_node(struct ctf_scanner *scanner,
+ enum node_type type)
+{
+ struct ctf_node *node;
+
+ node = objstack_alloc(scanner->objstack, sizeof(*node));
+ if (!node) {
+ printfl_fatal(yyget_lineno(scanner->scanner), "out of memory");
+ 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;
+ printfn_fatal(node, "trying to create root node");
+ 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._typedef.type_declarators);
+ break;
+ case NODE_TYPEALIAS_TARGET:
+ BT_INIT_LIST_HEAD(&node->u.typealias_target.type_declarators);
+ break;
+ case NODE_TYPEALIAS_ALIAS:
+ BT_INIT_LIST_HEAD(&node->u.typealias_alias.type_declarators);
+ break;
+ case NODE_TYPEALIAS:
+ break;
+
+ case NODE_TYPE_SPECIFIER:
+ break;
+ case NODE_TYPE_SPECIFIER_LIST:
+ BT_INIT_LIST_HEAD(&node->u.type_specifier_list.head);
+ break;
+ case NODE_POINTER:
+ break;
+ case NODE_TYPE_DECLARATOR:
+ BT_INIT_LIST_HEAD(&node->u.type_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.type_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;
+ printfn_fatal(node, "unknown node type '%d'", (int) 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:
+ printfn_fatal(node, "unknown node type '%d'", (int) 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:
+ printfn_fatal(node, "unknown node type %d", parent->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int reparent_typealias(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:
+ printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int reparent_type_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.type_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:
+ printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int reparent_type_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._typedef.type_specifier_list = node;
+ break;
+ case NODE_TYPEALIAS_TARGET:
+ parent->u.typealias_target.type_specifier_list = node;
+ break;
+ case NODE_TYPEALIAS_ALIAS:
+ parent->u.typealias_alias.type_specifier_list = node;
+ break;
+ case NODE_ENUM:
+ parent->u._enum.container_type = node;
+ break;
+ case NODE_STRUCT_OR_VARIANT_DECLARATION:
+ parent->u.struct_or_variant_declaration.type_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:
+ printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int reparent_type_declarator(struct ctf_node *node,
+ struct ctf_node *parent)
+{
+ switch (parent->type) {
+ case NODE_TYPE_DECLARATOR:
+ parent->u.type_declarator.type = TYPEDEC_NESTED;
+ parent->u.type_declarator.u.nested.type_declarator = node;
+ break;
+ case NODE_STRUCT_OR_VARIANT_DECLARATION:
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.struct_or_variant_declaration.type_declarators);
+ break;
+ case NODE_TYPEDEF:
+ _bt_list_splice_tail(&node->tmp_head, &parent->u._typedef.type_declarators);
+ break;
+ case NODE_TYPEALIAS_TARGET:
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.typealias_target.type_declarators);
+ break;
+ case NODE_TYPEALIAS_ALIAS:
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.typealias_alias.type_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:
+ printfn_fatal(node, "unknown node type '%d'", (int) 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:
+ printfn_fatal(node, "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.type_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.typealias.target = node;
+ else
+ return -EINVAL;
+ case NODE_TYPEALIAS_ALIAS:
+ if (parent->type == NODE_TYPEALIAS)
+ parent->u.typealias.alias = node;
+ else
+ return -EINVAL;
+ case NODE_TYPEALIAS:
+ return reparent_typealias(node, parent);
+
+ case NODE_POINTER:
+ if (parent->type == NODE_TYPE_DECLARATOR) {
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.type_declarator.pointers);
+ } else
+ return -EPERM;
+ break;
+ case NODE_TYPE_DECLARATOR:
+ return reparent_type_declarator(node, parent);
+
+ case NODE_TYPE_SPECIFIER_LIST:
+ return reparent_type_specifier_list(node, parent);
+
+ case NODE_TYPE_SPECIFIER:
+ return reparent_type_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:
+ printfn_fatal(node, "unknown node type '%d'", (int) parent->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+BT_HIDDEN
+void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str)
+{
+ printfl_error(yyget_lineno(scanner->scanner),
+ "token \"%s\": %s\n",
+ yyget_text(scanner->scanner), str);
+}
+
+BT_HIDDEN
+int yywrap(void)
+{
+ return 1;
+}
+
+#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 = 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);
+ if (yydebug)
+ fprintf(stdout, "Scanner input is a%s.\n",
+ isatty(fileno(input)) ? "n interactive tty" :
+ " noninteractive file");
+ return yyparse(scanner, scanner->scanner);
+}
+
+struct ctf_scanner *ctf_scanner_alloc(void)
+{
+ struct ctf_scanner *scanner;
+ int ret;
+
+ yydebug = babeltrace_debug;
+
+ scanner = malloc(sizeof(*scanner));
+ if (!scanner)
+ return NULL;
+ memset(scanner, 0, sizeof(*scanner));
+ ret = yylex_init_extra(scanner, &scanner->scanner);
+ if (ret) {
+ printf_fatal("yylex_init error");
+ 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)
+ printf_fatal("yylex_destroy error");
+cleanup_scanner:
+ free(scanner);
+ return NULL;
+}
+
+void ctf_scanner_free(struct ctf_scanner *scanner)
+{
+ int ret;
+
+ if (!scanner)
+ return;
+ finalize_scope(&scanner->root_scope);
+ objstack_destroy(scanner->objstack);
+ ret = yylex_destroy(scanner->scanner);
+ if (ret)
+ printf_error("yylex_destroy error");
+ free(scanner);
+}
+
+%}
+
+%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 INTEGER_LITERAL STRING_LITERAL CHARACTER_LITERAL LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW STAR PLUS MINUS LT GT TYPEASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA CONST CHAR DOUBLE ENUM ENV EVENT FLOATING_POINT FLOAT INTEGER INT LONG SHORT SIGNED STREAM STRING STRUCT TRACE CALLSITE CLOCK TYPEALIAS TYPEDEF UNSIGNED VARIANT VOID _BOOL _COMPLEX _IMAGINARY TOK_ALIGN
+%token <s> IDENTIFIER ID_TYPE
+%token ERROR
+%union
+{
+ long long ll;
+ unsigned long long ull;
+ char c;
+ char *s;
+ struct ctf_node *n;
+}
+
+%type <s> STRING_LITERAL CHARACTER_LITERAL
+
+%type <s> keywords
+
+%type <ull> INTEGER_LITERAL
+%type <n> postfix_expression unary_expression unary_expression_or_range
+
+%type <n> declaration
+%type <n> event_declaration
+%type <n> stream_declaration
+%type <n> env_declaration
+%type <n> trace_declaration
+%type <n> clock_declaration
+%type <n> callsite_declaration
+%type <n> integer_declaration_specifiers
+%type <n> declaration_specifiers
+%type <n> alias_declaration_specifiers
+
+%type <n> type_declarator_list
+%type <n> integer_type_specifier
+%type <n> type_specifier
+%type <n> struct_type_specifier
+%type <n> variant_type_specifier
+%type <n> enum_type_specifier
+%type <n> struct_or_variant_declaration_list
+%type <n> struct_or_variant_declaration
+%type <n> struct_or_variant_declarator_list
+%type <n> struct_or_variant_declarator
+%type <n> enumerator_list
+%type <n> enumerator
+%type <n> abstract_declarator_list
+%type <n> abstract_declarator
+%type <n> direct_abstract_declarator
+%type <n> alias_abstract_declarator_list
+%type <n> alias_abstract_declarator
+%type <n> direct_alias_abstract_declarator
+%type <n> declarator
+%type <n> direct_declarator
+%type <n> type_declarator
+%type <n> direct_type_declarator
+%type <n> pointer
+%type <n> ctf_assignment_expression_list
+%type <n> 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:
+ VOID
+ { $$ = yylval.s; }
+ | CHAR
+ { $$ = yylval.s; }
+ | SHORT
+ { $$ = yylval.s; }
+ | INT
+ { $$ = yylval.s; }
+ | LONG
+ { $$ = yylval.s; }
+ | FLOAT
+ { $$ = yylval.s; }
+ | DOUBLE
+ { $$ = yylval.s; }
+ | SIGNED
+ { $$ = yylval.s; }
+ | UNSIGNED
+ { $$ = yylval.s; }
+ | _BOOL
+ { $$ = yylval.s; }
+ | _COMPLEX
+ { $$ = yylval.s; }
+ | _IMAGINARY
+ { $$ = yylval.s; }
+ | FLOATING_POINT
+ { $$ = yylval.s; }
+ | INTEGER
+ { $$ = yylval.s; }
+ | STRING
+ { $$ = yylval.s; }
+ | ENUM
+ { $$ = yylval.s; }
+ | VARIANT
+ { $$ = yylval.s; }
+ | STRUCT
+ { $$ = yylval.s; }
+ | CONST
+ { $$ = yylval.s; }
+ | TYPEDEF
+ { $$ = yylval.s; }
+ | EVENT
+ { $$ = yylval.s; }
+ | STREAM
+ { $$ = yylval.s; }
+ | ENV
+ { $$ = yylval.s; }
+ | TRACE
+ { $$ = yylval.s; }
+ | CLOCK
+ { $$ = yylval.s; }
+ | CALLSITE
+ { $$ = yylval.s; }
+ | 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;
+ }
+ | INTEGER_LITERAL
+ {
+ $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+ $$->u.unary_expression.type = UNARY_UNSIGNED_CONSTANT;
+ $$->u.unary_expression.u.unsigned_constant = $1;
+ }
+ | STRING_LITERAL
+ {
+ $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+ $$->u.unary_expression.type = UNARY_STRING;
+ $$->u.unary_expression.u.string = $1;
+ }
+ | CHARACTER_LITERAL
+ {
+ $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+ $$->u.unary_expression.type = UNARY_STRING;
+ $$->u.unary_expression.u.string = $1;
+ }
+ | LPAREN unary_expression RPAREN
+ {
+ $$ = $2;
+ }
+ | postfix_expression LSBRAC unary_expression 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 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 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 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 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 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; }
+ | 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");
+ }
+ }
+ | 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_UNSIGNED_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 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 SEMICOLON
+ { $$ = $1; }
+ | event_declaration
+ { $$ = $1; }
+ | stream_declaration
+ { $$ = $1; }
+ | env_declaration
+ { $$ = $1; }
+ | trace_declaration
+ { $$ = $1; }
+ | clock_declaration
+ { $$ = $1; }
+ | callsite_declaration
+ { $$ = $1; }
+ | declaration_specifiers TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u._typedef.type_specifier_list = list;
+ _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u._typedef.type_specifier_list = list;
+ _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | declaration_specifiers TYPEDEF type_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u._typedef.type_specifier_list = list;
+ _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | TYPEALIAS declaration_specifiers abstract_declarator_list TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEALIAS);
+ $$->u.typealias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
+ $$->u.typealias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u.typealias.target->u.typealias_target.type_specifier_list = list;
+ _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.typealias.target->u.typealias_target.type_declarators);
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u.typealias.alias->u.typealias_alias.type_specifier_list = list;
+ _bt_list_splice_tail(&($5)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.typealias.alias->u.typealias_alias.type_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:
+ EVENT LBRAC
+ { push_scope(scanner); }
+ ;
+
+event_declaration_end:
+ RBRAC 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:
+ STREAM LBRAC
+ { push_scope(scanner); }
+ ;
+
+stream_declaration_end:
+ RBRAC 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:
+ ENV LBRAC
+ { push_scope(scanner); }
+ ;
+
+env_declaration_end:
+ RBRAC 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:
+ TRACE LBRAC
+ { push_scope(scanner); }
+ ;
+
+trace_declaration_end:
+ RBRAC SEMICOLON
+ { pop_scope(scanner); }
+ ;
+
+clock_declaration:
+ CLOCK clock_declaration_begin clock_declaration_end
+ {
+ $$ = make_node(scanner, NODE_CLOCK);
+ }
+ | 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:
+ LBRAC
+ { push_scope(scanner); }
+ ;
+
+clock_declaration_end:
+ RBRAC SEMICOLON
+ { pop_scope(scanner); }
+ ;
+
+callsite_declaration:
+ CALLSITE callsite_declaration_begin callsite_declaration_end
+ {
+ $$ = make_node(scanner, NODE_CALLSITE);
+ }
+ | 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:
+ LBRAC
+ { push_scope(scanner); }
+ ;
+
+callsite_declaration_end:
+ RBRAC SEMICOLON
+ { pop_scope(scanner); }
+ ;
+
+integer_declaration_specifiers:
+ CONST
+ {
+ struct ctf_node *node;
+
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ node = make_node(scanner, NODE_TYPE_SPECIFIER);
+ node->u.type_specifier.type = TYPESPEC_CONST;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | integer_type_specifier
+ {
+ struct ctf_node *node;
+
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ node = $1;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | integer_declaration_specifiers CONST
+ {
+ struct ctf_node *node;
+
+ $$ = $1;
+ node = make_node(scanner, NODE_TYPE_SPECIFIER);
+ node->u.type_specifier.type = TYPESPEC_CONST;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | integer_declaration_specifiers integer_type_specifier
+ {
+ $$ = $1;
+ bt_list_add_tail(&($2)->siblings, &($$)->u.type_specifier_list.head);
+ }
+ ;
+
+declaration_specifiers:
+ CONST
+ {
+ struct ctf_node *node;
+
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ node = make_node(scanner, NODE_TYPE_SPECIFIER);
+ node->u.type_specifier.type = TYPESPEC_CONST;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | type_specifier
+ {
+ struct ctf_node *node;
+
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ node = $1;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | declaration_specifiers CONST
+ {
+ struct ctf_node *node;
+
+ $$ = $1;
+ node = make_node(scanner, NODE_TYPE_SPECIFIER);
+ node->u.type_specifier.type = TYPESPEC_CONST;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | declaration_specifiers type_specifier
+ {
+ $$ = $1;
+ bt_list_add_tail(&($2)->siblings, &($$)->u.type_specifier_list.head);
+ }
+ ;
+
+type_declarator_list:
+ type_declarator
+ { $$ = $1; }
+ | type_declarator_list COMMA type_declarator
+ {
+ $$ = $1;
+ bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
+ }
+ ;
+
+integer_type_specifier:
+ CHAR
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_CHAR;
+ }
+ | SHORT
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_SHORT;
+ }
+ | INT
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_INT;
+ }
+ | LONG
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_LONG;
+ }
+ | SIGNED
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_SIGNED;
+ }
+ | UNSIGNED
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_UNSIGNED;
+ }
+ | _BOOL
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_BOOL;
+ }
+ | ID_TYPE
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_ID_TYPE;
+ $$->u.type_specifier.id_type = yylval.s;
+ }
+ | INTEGER LBRAC RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_INTEGER;
+ $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
+ }
+ | INTEGER LBRAC ctf_assignment_expression_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_INTEGER;
+ $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
+ if (set_parent_node($3, $$->u.type_specifier.node))
+ reparent_error(scanner, "integer reparent error");
+ }
+ ;
+
+type_specifier:
+ VOID
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_VOID;
+ }
+ | CHAR
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_CHAR;
+ }
+ | SHORT
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_SHORT;
+ }
+ | INT
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_INT;
+ }
+ | LONG
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_LONG;
+ }
+ | FLOAT
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_FLOAT;
+ }
+ | DOUBLE
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_DOUBLE;
+ }
+ | SIGNED
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_SIGNED;
+ }
+ | UNSIGNED
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_UNSIGNED;
+ }
+ | _BOOL
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_BOOL;
+ }
+ | _COMPLEX
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_COMPLEX;
+ }
+ | _IMAGINARY
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_IMAGINARY;
+ }
+ | ID_TYPE
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_ID_TYPE;
+ $$->u.type_specifier.id_type = yylval.s;
+ }
+ | FLOATING_POINT LBRAC RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_FLOATING_POINT;
+ $$->u.type_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
+ }
+ | FLOATING_POINT LBRAC ctf_assignment_expression_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_FLOATING_POINT;
+ $$->u.type_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
+ if (set_parent_node($3, $$->u.type_specifier.node))
+ reparent_error(scanner, "floating point reparent error");
+ }
+ | INTEGER LBRAC RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_INTEGER;
+ $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
+ }
+ | INTEGER LBRAC ctf_assignment_expression_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_INTEGER;
+ $$->u.type_specifier.node = make_node(scanner, NODE_INTEGER);
+ if (set_parent_node($3, $$->u.type_specifier.node))
+ reparent_error(scanner, "integer reparent error");
+ }
+ | STRING
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_STRING;
+ $$->u.type_specifier.node = make_node(scanner, NODE_STRING);
+ }
+ | STRING LBRAC RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_STRING;
+ $$->u.type_specifier.node = make_node(scanner, NODE_STRING);
+ }
+ | STRING LBRAC ctf_assignment_expression_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_STRING;
+ $$->u.type_specifier.node = make_node(scanner, NODE_STRING);
+ if (set_parent_node($3, $$->u.type_specifier.node))
+ reparent_error(scanner, "string reparent error");
+ }
+ | ENUM enum_type_specifier
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_ENUM;
+ $$->u.type_specifier.node = $2;
+ }
+ | VARIANT variant_type_specifier
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_VARIANT;
+ $$->u.type_specifier.node = $2;
+ }
+ | STRUCT struct_type_specifier
+ {
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+ $$->u.type_specifier.type = TYPESPEC_STRUCT;
+ $$->u.type_specifier.node = $2;
+ }
+ ;
+
+struct_type_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 TOK_ALIGN LPAREN unary_expression 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 TOK_ALIGN LPAREN unary_expression 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 TOK_ALIGN LPAREN unary_expression 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:
+ LBRAC
+ { push_scope(scanner); }
+ ;
+
+struct_declaration_end:
+ RBRAC
+ { pop_scope(scanner); }
+ ;
+
+variant_type_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");
+ }
+ | LT IDENTIFIER 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");
+ }
+ | LT ID_TYPE 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 LT IDENTIFIER 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 LT IDENTIFIER GT
+ {
+ $$ = make_node(scanner, NODE_VARIANT);
+ $$->u.variant.has_body = 0;
+ $$->u.variant.name = $1;
+ $$->u.variant.choice = $3;
+ }
+ | IDENTIFIER LT ID_TYPE 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 LT ID_TYPE 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 LT IDENTIFIER 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 LT IDENTIFIER GT
+ {
+ $$ = make_node(scanner, NODE_VARIANT);
+ $$->u.variant.has_body = 0;
+ $$->u.variant.name = $1;
+ $$->u.variant.choice = $3;
+ }
+ | ID_TYPE LT ID_TYPE 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 LT ID_TYPE GT
+ {
+ $$ = make_node(scanner, NODE_VARIANT);
+ $$->u.variant.has_body = 0;
+ $$->u.variant.name = $1;
+ $$->u.variant.choice = $3;
+ }
+ ;
+
+variant_declaration_begin:
+ LBRAC
+ { push_scope(scanner); }
+ ;
+
+variant_declaration_end:
+ RBRAC
+ { pop_scope(scanner); }
+ ;
+
+enum_type_specifier:
+ LBRAC enumerator_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
+ }
+ | COLON integer_declaration_specifiers LBRAC enumerator_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ ($$)->u._enum.container_type = $2;
+ _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
+ }
+ | IDENTIFIER LBRAC enumerator_list 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 COLON integer_declaration_specifiers LBRAC enumerator_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ $$->u._enum.enum_id = $1;
+ ($$)->u._enum.container_type = $3;
+ _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
+ }
+ | ID_TYPE LBRAC enumerator_list 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 COLON integer_declaration_specifiers LBRAC enumerator_list RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ $$->u._enum.enum_id = $1;
+ ($$)->u._enum.container_type = $3;
+ _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
+ }
+ | LBRAC enumerator_list COMMA RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
+ }
+ | COLON integer_declaration_specifiers LBRAC enumerator_list COMMA RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ ($$)->u._enum.container_type = $2;
+ _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
+ }
+ | IDENTIFIER LBRAC enumerator_list COMMA 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 COLON integer_declaration_specifiers LBRAC enumerator_list COMMA RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ $$->u._enum.enum_id = $1;
+ ($$)->u._enum.container_type = $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 LBRAC enumerator_list COMMA 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 COLON integer_declaration_specifiers LBRAC enumerator_list COMMA RBRAC
+ {
+ $$ = make_node(scanner, NODE_ENUM);
+ $$->u._enum.has_body = 1;
+ $$->u._enum.enum_id = $1;
+ ($$)->u._enum.container_type = $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 SEMICOLON
+ {
+ struct ctf_node *list;
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ $$ = make_node(scanner, NODE_STRUCT_OR_VARIANT_DECLARATION);
+ ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
+ _bt_list_splice_tail(&($2)->tmp_head, &($$)->u.struct_or_variant_declaration.type_declarators);
+ }
+ | declaration_specifiers TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u._typedef.type_specifier_list = list;
+ _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u._typedef.type_specifier_list = list;
+ _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | declaration_specifiers TYPEDEF type_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | TYPEALIAS declaration_specifiers abstract_declarator_list TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list SEMICOLON
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEALIAS);
+ $$->u.typealias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
+ $$->u.typealias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u.typealias.target->u.typealias_target.type_specifier_list = list;
+ _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.typealias.target->u.typealias_target.type_declarators);
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u.typealias.alias->u.typealias_alias.type_specifier_list = list;
+ _bt_list_splice_tail(&($5)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.typealias.alias->u.typealias_alias.type_declarators);
+ }
+ ;
+
+alias_declaration_specifiers:
+ CONST
+ {
+ struct ctf_node *node;
+
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ node = make_node(scanner, NODE_TYPE_SPECIFIER);
+ node->u.type_specifier.type = TYPESPEC_CONST;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | type_specifier
+ {
+ struct ctf_node *node;
+
+ $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ node = $1;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_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.type_specifier.type = TYPESPEC_ID_TYPE;
+ node->u.type_specifier.id_type = yylval.s;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | alias_declaration_specifiers CONST
+ {
+ struct ctf_node *node;
+
+ $$ = $1;
+ node = make_node(scanner, NODE_TYPE_SPECIFIER);
+ node->u.type_specifier.type = TYPESPEC_CONST;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ | alias_declaration_specifiers type_specifier
+ {
+ $$ = $1;
+ bt_list_add_tail(&($2)->siblings, &($$)->u.type_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.type_specifier.type = TYPESPEC_ID_TYPE;
+ node->u.type_specifier.id_type = yylval.s;
+ bt_list_add_tail(&node->siblings, &($$)->u.type_specifier_list.head);
+ }
+ ;
+
+struct_or_variant_declarator_list:
+ struct_or_variant_declarator
+ { $$ = $1; }
+ | struct_or_variant_declarator_list COMMA struct_or_variant_declarator
+ {
+ $$ = $1;
+ bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
+ }
+ ;
+
+struct_or_variant_declarator:
+ declarator
+ { $$ = $1; }
+ | COLON unary_expression
+ { $$ = $2; }
+ | declarator COLON unary_expression
+ {
+ $$ = $1;
+ if (set_parent_node($3, $1))
+ reparent_error(scanner, "struct_or_variant_declarator");
+ }
+ ;
+
+enumerator_list:
+ enumerator
+ { $$ = $1; }
+ | enumerator_list 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;
+ }
+ | STRING_LITERAL
+ {
+ $$ = make_node(scanner, NODE_ENUMERATOR);
+ $$->u.enumerator.id = $1;
+ }
+ | IDENTIFIER 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 EQUAL unary_expression_or_range
+ {
+ $$ = make_node(scanner, NODE_ENUMERATOR);
+ $$->u.enumerator.id = $1;
+ bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
+ }
+ | keywords EQUAL unary_expression_or_range
+ {
+ $$ = make_node(scanner, NODE_ENUMERATOR);
+ $$->u.enumerator.id = $1;
+ bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
+ }
+ | STRING_LITERAL 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 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.type_declarator.pointers);
+ }
+ ;
+
+direct_abstract_declarator:
+ /* empty */
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_ID;
+ /* id is NULL */
+ }
+ | IDENTIFIER
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_ID;
+ $$->u.type_declarator.u.id = $1;
+ }
+ | LPAREN abstract_declarator RPAREN
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $2;
+ }
+ | direct_abstract_declarator LSBRAC unary_expression RSBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $1;
+ BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
+ }
+ | direct_abstract_declarator LSBRAC RSBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $1;
+ $$->u.type_declarator.u.nested.abstract_array = 1;
+ }
+ ;
+
+alias_abstract_declarator_list:
+ alias_abstract_declarator
+ { $$ = $1; }
+ | alias_abstract_declarator_list 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.type_declarator.pointers);
+ }
+ ;
+
+direct_alias_abstract_declarator:
+ /* empty */
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_ID;
+ /* id is NULL */
+ }
+ | LPAREN alias_abstract_declarator RPAREN
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $2;
+ }
+ | direct_alias_abstract_declarator LSBRAC unary_expression RSBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $1;
+ BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
+ }
+ | direct_alias_abstract_declarator LSBRAC RSBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $1;
+ $$->u.type_declarator.u.nested.abstract_array = 1;
+ }
+ ;
+
+declarator:
+ direct_declarator
+ { $$ = $1; }
+ | pointer direct_declarator
+ {
+ $$ = $2;
+ bt_list_splice(&($1)->tmp_head, &($$)->u.type_declarator.pointers);
+ }
+ ;
+
+direct_declarator:
+ IDENTIFIER
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_ID;
+ $$->u.type_declarator.u.id = $1;
+ }
+ | LPAREN declarator RPAREN
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $2;
+ }
+ | direct_declarator LSBRAC unary_expression RSBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $1;
+ BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
+ }
+ ;
+
+type_declarator:
+ direct_type_declarator
+ { $$ = $1; }
+ | pointer direct_type_declarator
+ {
+ $$ = $2;
+ bt_list_splice(&($1)->tmp_head, &($$)->u.type_declarator.pointers);
+ }
+ ;
+
+direct_type_declarator:
+ IDENTIFIER
+ {
+ add_type(scanner, $1);
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_ID;
+ $$->u.type_declarator.u.id = $1;
+ }
+ | LPAREN type_declarator RPAREN
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $2;
+ }
+ | direct_type_declarator LSBRAC unary_expression RSBRAC
+ {
+ $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+ $$->u.type_declarator.type = TYPEDEC_NESTED;
+ $$->u.type_declarator.u.nested.type_declarator = $1;
+ BT_INIT_LIST_HEAD(&($$)->u.type_declarator.u.nested.length);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.type_declarator.u.nested.length);
+ }
+ ;
+
+pointer:
+ STAR
+ {
+ $$ = make_node(scanner, NODE_POINTER);
+ }
+ | STAR pointer
+ {
+ $$ = make_node(scanner, NODE_POINTER);
+ bt_list_splice(&($2)->tmp_head, &($$)->tmp_head);
+ }
+ | 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 */
+ CONST
+ | type_qualifier_list CONST
+ ;
+
+/* 2.3: CTF-specific declarations */
+
+ctf_assignment_expression_list:
+ ctf_assignment_expression SEMICOLON
+ { $$ = $1; }
+ | ctf_assignment_expression_list ctf_assignment_expression SEMICOLON
+ {
+ $$ = $1;
+ bt_list_add_tail(&($2)->siblings, &($$)->tmp_head);
+ }
+ ;
+
+ctf_assignment_expression:
+ unary_expression 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 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 TYPEDEF declaration_specifiers type_declarator_list
+ {
+ struct ctf_node *list;
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
+ _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | TYPEDEF declaration_specifiers type_declarator_list
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u._typedef.type_specifier_list = list;
+ _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | declaration_specifiers TYPEDEF type_declarator_list
+ {
+ struct ctf_node *list;
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ _bt_list_splice_tail(&($1)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ $$ = make_node(scanner, NODE_TYPEDEF);
+ ($$)->u.struct_or_variant_declaration.type_specifier_list = list;
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._typedef.type_declarators);
+ }
+ | TYPEALIAS declaration_specifiers abstract_declarator_list TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list
+ {
+ struct ctf_node *list;
+
+ $$ = make_node(scanner, NODE_TYPEALIAS);
+ $$->u.typealias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
+ $$->u.typealias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u.typealias.target->u.typealias_target.type_specifier_list = list;
+ _bt_list_splice_tail(&($2)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.typealias.target->u.typealias_target.type_declarators);
+
+ list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+ $$->u.typealias.alias->u.typealias_alias.type_specifier_list = list;
+ _bt_list_splice_tail(&($5)->u.type_specifier_list.head, &list->u.type_specifier_list.head);
+ _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.typealias.alias->u.typealias_alias.type_declarators);
+ }
+ ;
--- /dev/null
+#ifndef _CTF_SCANNER_SYMBOLS
+#define _CTF_SCANNER_SYMBOLS
+
+/*
+ * ctf-scanner-symbols.h
+ *
+ * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#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 */
--- /dev/null
+#ifndef _CTF_SCANNER_H
+#define _CTF_SCANNER_H
+
+/*
+ * ctf-scanner.h
+ *
+ * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <stdio.h>
+#include "ast.h"
+
+#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 *types;
+};
+
+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;
+}
+
+BT_HIDDEN
+int is_type(struct ctf_scanner *scanner, const char *id);
+
+#endif /* _CTF_SCANNER_H */
--- /dev/null
+/*
+ * ctf-visitor-generate-ir.c
+ *
+ * Common Trace Format metadata visitor (generates CTF IR objects).
+ *
+ * Based on older ctf-visitor-generate-io-struct.c.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2015-2016 - Philippe Proulx <philippe.proulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <babeltrace/ctf/metadata.h>
+#include <babeltrace/compat/uuid.h>
+#include <babeltrace/endian.h>
+#include <babeltrace/ref.h>
+#include <babeltrace/ctf/events-internal.h>
+#include <babeltrace/ctf-ir/trace.h>
+#include <babeltrace/ctf-ir/stream-class.h>
+#include <babeltrace/ctf-ir/event.h>
+#include <babeltrace/ctf-ir/event-class.h>
+#include <babeltrace/ctf-ir/field-types.h>
+#include <babeltrace/ctf-ir/field-types-internal.h>
+#include <babeltrace/ctf-ir/clock.h>
+
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+
+/* 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))
+
+/* 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_LOGLEVEL_SET = _BV(4),
+ _EVENT_CONTEXT_SET = _BV(5),
+ _EVENT_FIELDS_SET = _BV(6),
+};
+
+/* Prefixes of type 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, _type, _member) \
+ bt_list_entry((_ptr)->next, _type, _member)
+
+#define _BT_CTF_FIELD_TYPE_INIT(_name) struct bt_ctf_field_type *_name = NULL;
+
+/* Error printing wrappers */
+#define _PERROR(_fmt, ...) \
+ do { \
+ fprintf(ctx->efd, "[error] %s: " _fmt "\n", \
+ __func__, __VA_ARGS__); \
+ } while (0)
+
+#define _PWARNING(_fmt, ...) \
+ do { \
+ fprintf(ctx->efd, "[warning] %s: " _fmt "\n", \
+ __func__, __VA_ARGS__); \
+ } while (0)
+
+#define _FPERROR(_stream, _fmt, ...) \
+ do { \
+ fprintf(_stream, "[error] %s: " _fmt "\n", \
+ __func__, __VA_ARGS__); \
+ } while (0)
+
+#define _FPWARNING(_stream, _fmt, ...) \
+ do { \
+ fprintf(_stream, "[warning] %s: " _fmt "\n", \
+ __func__, __VA_ARGS__); \
+ } while (0)
+
+#define _PERROR_DUP_ATTR(_attr, _entity) \
+ do { \
+ fprintf(ctx->efd, \
+ "[error] %s: duplicate attribute \"" \
+ _attr "\" in " _entity "\n", __func__); \
+ } while (0)
+
+/*
+ * 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 type.
+ *
+ * GQuark -> struct bt_ctf_field_type *
+ */
+ GHashTable *decl_map;
+
+ /* Parent scope; NULL if this is the root declaration scope */
+ struct ctx_decl_scope *parent_scope;
+};
+
+/*
+ * Visitor context.
+ */
+struct ctx {
+ /* Trace being filled (weak ref.) */
+ struct bt_ctf_trace *trace;
+
+ /* Error stream to use during visit */
+ FILE *efd;
+
+ /* Current declaration scope (top of the stack) */
+ struct ctx_decl_scope *current_scope;
+
+ /* 1 if trace declaration is visited */
+ int is_trace_visited;
+
+ /* Trace attributes */
+ uint64_t trace_major;
+ uint64_t trace_minor;
+ unsigned char trace_uuid[BABELTRACE_UUID_LEN];
+
+ /*
+ * Stream IDs to stream classes.
+ *
+ * int64_t -> struct bt_ctf_stream_class *
+ */
+ GHashTable *stream_classes;
+};
+
+/**
+ * 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 ctx_decl_scope *par_scope)
+{
+ struct ctx_decl_scope *scope;
+
+ scope = g_new(struct ctx_decl_scope, 1);
+ if (!scope) {
+ goto end;
+ }
+
+ scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) bt_ctf_field_type_put);
+ 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)
+{
+ GQuark qname = 0;
+
+ assert(name);
+
+ /* Prefix character + original string + '\0' */
+ char *prname = g_new(char, strlen(name) + 2);
+ if (!prname) {
+ goto end;
+ }
+
+ sprintf(prname, "%c%s", prefix, name);
+ qname = g_quark_from_string(prname);
+ g_free(prname);
+
+end:
+ return qname;
+}
+
+/**
+ * Looks up a prefixed type alias within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param prefix Prefix character
+ * @param name Alias name
+ * @param level Number of levels to dig (-1 means infinite)
+ * @returns Declaration, or NULL if not found
+ */
+static
+struct bt_ctf_field_type *ctx_decl_scope_lookup_prefix_alias(
+ struct ctx_decl_scope *scope, char prefix,
+ const char *name, int levels)
+{
+ GQuark qname = 0;
+ int cur_levels = 0;
+ _BT_CTF_FIELD_TYPE_INIT(decl);
+ struct ctx_decl_scope *cur_scope = scope;
+
+ assert(scope);
+ assert(name);
+ qname = get_prefixed_named_quark(prefix, name);
+ if (!qname) {
+ goto error;
+ }
+
+ if (levels < 0) {
+ levels = INT_MAX;
+ }
+
+ while (cur_scope && cur_levels < levels) {
+ decl = g_hash_table_lookup(cur_scope->decl_map,
+ (gconstpointer) (unsigned long) qname);
+ if (decl) {
+ /* Caller's reference */
+ bt_get(decl);
+ break;
+ }
+
+ cur_scope = cur_scope->parent_scope;
+ cur_levels++;
+ }
+
+ return decl;
+
+error:
+ return NULL;
+}
+
+/**
+ * Looks up a type alias within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param name Alias name
+ * @param level Number of levels to dig (-1 means infinite)
+ * @returns Declaration, or NULL if not found
+ */
+static
+struct bt_ctf_field_type *ctx_decl_scope_lookup_alias(
+ struct ctx_decl_scope *scope, const char *name, int levels)
+{
+ return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS,
+ name, levels);
+}
+
+/**
+ * Looks up an enumeration within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param name Enumeration name
+ * @param level Number of levels to dig (-1 means infinite)
+ * @returns Declaration, or NULL if not found
+ */
+static
+struct bt_ctf_field_type *ctx_decl_scope_lookup_enum(
+ struct ctx_decl_scope *scope, const char *name, int levels)
+{
+ return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM,
+ name, levels);
+}
+
+/**
+ * Looks up a structure within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param name Structure name
+ * @param level Number of levels to dig (-1 means infinite)
+ * @returns Declaration, or NULL if not found
+ */
+static
+struct bt_ctf_field_type *ctx_decl_scope_lookup_struct(
+ struct ctx_decl_scope *scope, const char *name, int levels)
+{
+ return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_STRUCT,
+ name, levels);
+}
+
+/**
+ * Looks up a variant within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param name Variant name
+ * @param level Number of levels to dig (-1 means infinite)
+ * @returns Declaration, or NULL if not found
+ */
+static
+struct bt_ctf_field_type *ctx_decl_scope_lookup_variant(
+ struct ctx_decl_scope *scope, const char *name, int levels)
+{
+ return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_VARIANT,
+ name, levels);
+}
+
+/**
+ * Registers a prefixed type alias within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param prefix Prefix character
+ * @param name Alias name (non-NULL)
+ * @param decl Declaration to register
+ * @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 bt_ctf_field_type *decl)
+{
+ int ret = 0;
+ GQuark qname = 0;
+ _BT_CTF_FIELD_TYPE_INIT(edecl);
+
+ assert(scope);
+ assert(name);
+ assert(decl);
+ qname = get_prefixed_named_quark(prefix, name);
+ if (!qname) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Make sure alias does not exist in local scope */
+ edecl = ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1);
+ if (edecl) {
+ BT_PUT(edecl);
+ ret = -EEXIST;
+ goto error;
+ }
+
+ g_hash_table_insert(scope->decl_map,
+ (gpointer) (unsigned long) qname, decl);
+
+ /* Hash table's reference */
+ bt_get(decl);
+
+ return 0;
+
+error:
+ return ret;
+}
+
+/**
+ * Registers a type alias within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param name Alias name (non-NULL)
+ * @param decl Declaration to register
+ * @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 bt_ctf_field_type *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 declaration to register
+ * @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 bt_ctf_field_type *decl)
+{
+ return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM,
+ name, decl);
+}
+
+/**
+ * Registers a structure declaration within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param name Structure name (non-NULL)
+ * @param decl Structure declaration to register
+ * @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 bt_ctf_field_type *decl)
+{
+ return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT,
+ name, decl);
+}
+
+/**
+ * Registers a variant declaration within a declaration scope.
+ *
+ * @param scope Declaration scope
+ * @param name Variant name (non-NULL)
+ * @param decl Variant declaration 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 bt_ctf_field_type *decl)
+{
+ return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT,
+ name, decl);
+}
+
+/**
+ * Creates a new visitor context.
+ *
+ * @param trace Associated trace
+ * @param efd Error stream
+ * @returns New visitor context, or NULL on error
+ */
+static
+struct ctx *ctx_create(struct bt_ctf_trace *trace, FILE *efd)
+{
+ struct ctx *ctx = NULL;
+ struct ctx_decl_scope *scope = NULL;
+
+ ctx = g_new(struct ctx, 1);
+ if (!ctx) {
+ goto error;
+ }
+
+ /* Root declaration scope */
+ scope = ctx_decl_scope_create(NULL);
+ if (!scope) {
+ goto error;
+ }
+
+ ctx->stream_classes = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL, (GDestroyNotify) bt_put);
+ if (!ctx->stream_classes) {
+ goto error;
+ }
+
+ ctx->trace = trace;
+ ctx->efd = efd;
+ ctx->current_scope = scope;
+ ctx->is_trace_visited = FALSE;
+
+ return ctx;
+
+error:
+ g_free(ctx);
+ ctx_decl_scope_destroy(scope);
+
+ return NULL;
+}
+
+/**
+ * Destroys a visitor context.
+ *
+ * @param ctx Visitor context to destroy
+ */
+static
+void ctx_destroy(struct ctx *ctx)
+{
+ struct ctx_decl_scope *scope;
+ /*
+ * Destroy all scopes, from current one to the root scope.
+ */
+
+ if (!ctx) {
+ goto end;
+ }
+
+ scope = ctx->current_scope;
+
+ while (scope) {
+ struct ctx_decl_scope *parent_scope = scope->parent_scope;
+
+ ctx_decl_scope_destroy(scope);
+ scope = parent_scope;
+ }
+
+ g_hash_table_destroy(ctx->stream_classes);
+ g_free(ctx);
+
+end:
+ return;
+}
+
+/**
+ * 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 ctx *ctx)
+{
+ int ret = 0;
+ struct ctx_decl_scope *new_scope;
+
+ assert(ctx);
+ new_scope = ctx_decl_scope_create(ctx->current_scope);
+ if (!new_scope) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ ctx->current_scope = new_scope;
+
+end:
+ return ret;
+}
+
+static
+void ctx_pop_scope(struct ctx *ctx)
+{
+ struct ctx_decl_scope *parent_scope = NULL;
+
+ 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_type_specifier_list(struct ctx *ctx, struct ctf_node *ts_list,
+ struct bt_ctf_field_type **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
+char *concatenate_unary_strings(struct bt_list_head *head)
+{
+ int i = 0;
+ GString *str;
+ struct ctf_node *node;
+
+ str = g_string_new(NULL);
+
+ 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);
+}
+
+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 bt_list_head *head, uint64_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_link != UNARY_LINK_UNKNOWN || i != 0;
+ if (cond) {
+ 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_UNSIGNED_CONSTANT &&
+ uexpr_type != UNARY_SIGNED_CONSTANT) ||
+ uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
+ if (cond) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ switch (node->u.unary_expression.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 bt_list_head *head, unsigned char *uuid)
+{
+ 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_parse(src_string, uuid);
+ if (ret) {
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+static
+int get_boolean(FILE *efd, struct ctf_node *unary_expr)
+{
+ int ret = 0;
+
+ if (unary_expr->type != NODE_UNARY_EXPRESSION) {
+ _FPERROR(efd, "%s", "expecting unary expression");
+ 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") || !strcmp(str, "TRUE")) {
+ ret = TRUE;
+ } else if (!strcmp(str, "false") || !strcmp(str, "FALSE")) {
+ ret = FALSE;
+ } else {
+ _FPERROR(efd, "unexpected string \"%s\"", str);
+ ret = -EINVAL;
+ goto end;
+ }
+ break;
+ }
+ default:
+ _FPERROR(efd, "%s", "unexpected unary expression type");
+ ret = -EINVAL;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static
+enum bt_ctf_byte_order byte_order_from_unary_expr(FILE *efd,
+ struct ctf_node *unary_expr)
+{
+ const char *str;
+ enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_UNKNOWN;
+
+ if (unary_expr->u.unary_expression.type != UNARY_STRING) {
+ _FPERROR(efd, "%s",
+ "\"byte_order\" attribute: expecting string");
+ goto end;
+ }
+
+ str = unary_expr->u.unary_expression.u.string;
+
+ if (!strcmp(str, "be") || !strcmp(str, "network")) {
+ bo = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
+ } else if (!strcmp(str, "le")) {
+ bo = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
+ } else if (!strcmp(str, "native")) {
+ bo = BT_CTF_BYTE_ORDER_NATIVE;
+ } else {
+ _FPERROR(efd, "unexpected \"byte_order\" attribute value \"%s\"; should be \"be\", \"le\", \"network\", or \"native\"",
+ str);
+ goto end;
+ }
+
+end:
+ return bo;
+}
+
+static
+enum bt_ctf_byte_order get_real_byte_order(struct ctx *ctx,
+ struct ctf_node *uexpr)
+{
+ enum bt_ctf_byte_order bo = byte_order_from_unary_expr(ctx->efd, uexpr);
+
+ if (bo == BT_CTF_BYTE_ORDER_NATIVE) {
+ bo = bt_ctf_trace_get_byte_order(ctx->trace);
+ }
+
+ return bo;
+}
+
+static
+int is_align_valid(uint64_t align)
+{
+ return (align != 0) && !(align & (align - 1));
+}
+
+static
+int get_type_specifier_name(struct ctx *ctx, struct ctf_node *type_specifier,
+ GString *str)
+{
+ int ret = 0;
+
+ if (type_specifier->type != NODE_TYPE_SPECIFIER) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ switch (type_specifier->u.type_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 (type_specifier->u.type_specifier.id_type) {
+ g_string_append(str,
+ type_specifier->u.type_specifier.id_type);
+ }
+ break;
+ case TYPESPEC_STRUCT:
+ {
+ struct ctf_node *node = type_specifier->u.type_specifier.node;
+
+ if (!node->u._struct.name) {
+ _PERROR("%s", "unexpected empty structure 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 = type_specifier->u.type_specifier.node;
+
+ if (!node->u.variant.name) {
+ _PERROR("%s", "unexpected empty variant 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 = type_specifier->u.type_specifier.node;
+
+ if (!node->u._enum.enum_id) {
+ _PERROR("%s", "unexpected empty 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:
+ _PERROR("%s", "unknown specifier");
+ ret = -EINVAL;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static
+int get_type_specifier_list_name(struct ctx *ctx,
+ struct ctf_node *type_specifier_list, GString *str)
+{
+ int ret;
+ struct ctf_node *iter;
+ int alias_item_nr = 0;
+ struct bt_list_head *head =
+ &type_specifier_list->u.type_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_type_specifier_name(ctx, iter, str);
+ if (ret) {
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+static
+GQuark create_typealias_identifier(struct ctx *ctx,
+ struct ctf_node *type_specifier_list,
+ struct ctf_node *node_type_declarator)
+{
+ int ret;
+ char *str_c;
+ GString *str;
+ GQuark qalias = 0;
+ struct ctf_node *iter;
+ struct bt_list_head *pointers =
+ &node_type_declarator->u.type_declarator.pointers;
+
+ str = g_string_new("");
+ ret = get_type_specifier_list_name(ctx, type_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_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
+ GQuark *field_name, struct ctf_node *node_type_declarator,
+ struct bt_ctf_field_type **field_decl,
+ struct bt_ctf_field_type *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 type declarator node */
+ if (node_type_declarator) {
+ if (node_type_declarator->u.type_declarator.type ==
+ TYPEDEC_UNKNOWN) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* TODO: GCC bitfields not supported yet */
+ if (node_type_declarator->u.type_declarator.bitfield_len !=
+ NULL) {
+ _PERROR("%s", "GCC bitfields are not supported as of this version");
+ ret = -EPERM;
+ goto error;
+ }
+ }
+
+ /* Find the right nested declaration if not provided */
+ if (!nested_decl) {
+ struct bt_list_head *pointers =
+ &node_type_declarator->u.type_declarator.pointers;
+
+ if (node_type_declarator && !bt_list_empty(pointers)) {
+ GQuark qalias;
+ _BT_CTF_FIELD_TYPE_INIT(nested_decl_copy);
+
+ /*
+ * If we have a pointer declarator, it HAS to
+ * be present in the typealiases (else fail).
+ */
+ qalias = create_typealias_identifier(ctx,
+ type_specifier_list, node_type_declarator);
+ nested_decl =
+ ctx_decl_scope_lookup_alias(ctx->current_scope,
+ g_quark_to_string(qalias), -1);
+ if (!nested_decl) {
+ _PERROR("cannot find typealias \"%s\"",
+ g_quark_to_string(qalias));
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Make a copy of it */
+ nested_decl_copy = bt_ctf_field_type_copy(nested_decl);
+ BT_PUT(nested_decl);
+ if (!nested_decl_copy) {
+ _PERROR("%s", "cannot copy nested declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ BT_MOVE(nested_decl, nested_decl_copy);
+
+ /* Force integer's base to 16 since it's a pointer */
+ if (bt_ctf_field_type_is_integer(nested_decl)) {
+ bt_ctf_field_type_integer_set_base(nested_decl,
+ BT_CTF_INTEGER_BASE_HEXADECIMAL);
+ }
+ } else {
+ ret = visit_type_specifier_list(ctx,
+ type_specifier_list, &nested_decl);
+ if (ret) {
+ assert(!nested_decl);
+ goto error;
+ }
+ }
+ }
+
+ assert(nested_decl);
+
+ if (!node_type_declarator) {
+ BT_MOVE(*field_decl, nested_decl);
+ goto end;
+ }
+
+ if (node_type_declarator->u.type_declarator.type == TYPEDEC_ID) {
+ if (node_type_declarator->u.type_declarator.u.id) {
+ const char *id =
+ node_type_declarator->u.type_declarator.u.id;
+
+ *field_name = g_quark_from_string(id);
+ } else {
+ *field_name = 0;
+ }
+
+ BT_MOVE(*field_decl, nested_decl);
+ goto end;
+ } else {
+ struct ctf_node *first;
+ _BT_CTF_FIELD_TYPE_INIT(decl);
+ _BT_CTF_FIELD_TYPE_INIT(outer_field_decl);
+ struct bt_list_head *length =
+ &node_type_declarator->
+ u.type_declarator.u.nested.length;
+
+ /* Create array/sequence, pass nested_decl as child */
+ if (bt_list_empty(length)) {
+ _PERROR("%s",
+ "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) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ switch (first->u.unary_expression.type) {
+ case UNARY_UNSIGNED_CONSTANT:
+ {
+ size_t len;
+ _BT_CTF_FIELD_TYPE_INIT(array_decl);
+
+ len = first->u.unary_expression.u.unsigned_constant;
+ array_decl = bt_ctf_field_type_array_create(nested_decl,
+ len);
+ BT_PUT(nested_decl);
+ if (!array_decl) {
+ _PERROR("%s",
+ "cannot create array declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ BT_MOVE(decl, array_decl);
+ break;
+ }
+ case UNARY_STRING:
+ {
+ /* Lookup unsigned integer definition, create seq. */
+ _BT_CTF_FIELD_TYPE_INIT(seq_decl);
+ char *length_name = concatenate_unary_strings(length);
+
+ if (!length_name) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ seq_decl = bt_ctf_field_type_sequence_create(
+ nested_decl, length_name);
+ g_free(length_name);
+ BT_PUT(nested_decl);
+ if (!seq_decl) {
+ _PERROR("%s",
+ "cannot create sequence declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ BT_MOVE(decl, seq_decl);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+
+ assert(!nested_decl);
+ assert(decl);
+ 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_type_declarator(ctx, type_specifier_list,
+ field_name,
+ node_type_declarator->
+ u.type_declarator.u.nested.type_declarator,
+ &outer_field_decl, decl);
+ decl = NULL;
+ if (ret) {
+ assert(!outer_field_decl);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ assert(outer_field_decl);
+ BT_MOVE(*field_decl, outer_field_decl);
+ }
+
+end:
+ BT_PUT(nested_decl);
+ assert(*field_decl);
+
+ return 0;
+
+error:
+ BT_PUT(nested_decl);
+ BT_PUT(*field_decl);
+
+ return ret;
+}
+
+static
+int visit_struct_decl_field(struct ctx *ctx,
+ struct bt_ctf_field_type *struct_decl,
+ struct ctf_node *type_specifier_list,
+ struct bt_list_head *type_declarators)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+ _BT_CTF_FIELD_TYPE_INIT(field_decl);
+
+ bt_list_for_each_entry(iter, type_declarators, siblings) {
+ field_decl = NULL;
+ GQuark qfield_name;
+ const char *field_name;
+ _BT_CTF_FIELD_TYPE_INIT(efield_decl);
+
+ ret = visit_type_declarator(ctx, type_specifier_list,
+ &qfield_name, iter, &field_decl, NULL);
+ if (ret) {
+ assert(!field_decl);
+ _PERROR("%s", "unable to find structure field declaration type");
+ goto error;
+ }
+
+ assert(field_decl);
+ field_name = g_quark_to_string(qfield_name);
+
+ /* Check if field with same name already exists */
+ efield_decl =
+ bt_ctf_field_type_structure_get_field_type_by_name(
+ struct_decl, field_name);
+ if (efield_decl) {
+ BT_PUT(efield_decl);
+ _PERROR("duplicate field \"%s\" in structure",
+ field_name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Add field to structure */
+ ret = bt_ctf_field_type_structure_add_field(struct_decl,
+ field_decl, field_name);
+ BT_PUT(field_decl);
+ if (ret) {
+ _PERROR("cannot add field \"%s\" to structure",
+ g_quark_to_string(qfield_name));
+ goto error;
+ }
+ }
+
+ return 0;
+
+error:
+ BT_PUT(field_decl);
+
+ return ret;
+}
+
+static
+int visit_variant_decl_field(struct ctx *ctx,
+ struct bt_ctf_field_type *variant_decl,
+ struct ctf_node *type_specifier_list,
+ struct bt_list_head *type_declarators)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+ _BT_CTF_FIELD_TYPE_INIT(field_decl);
+
+ bt_list_for_each_entry(iter, type_declarators, siblings) {
+ field_decl = NULL;
+ GQuark qfield_name;
+ const char *field_name;
+ _BT_CTF_FIELD_TYPE_INIT(efield_decl);
+
+ ret = visit_type_declarator(ctx, type_specifier_list,
+ &qfield_name, iter, &field_decl, NULL);
+ if (ret) {
+ assert(!field_decl);
+ _PERROR("%s",
+ "unable to find variant field declaration type");
+ goto error;
+ }
+
+ assert(field_decl);
+ field_name = g_quark_to_string(qfield_name);
+
+ /* Check if field with same name already exists */
+ efield_decl =
+ bt_ctf_field_type_variant_get_field_type_by_name(
+ variant_decl, field_name);
+ if (efield_decl) {
+ BT_PUT(efield_decl);
+ _PERROR("duplicate field \"%s\" in variant",
+ field_name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Add field to structure */
+ ret = bt_ctf_field_type_variant_add_field(variant_decl,
+ field_decl, field_name);
+ BT_PUT(field_decl);
+ if (ret) {
+ _PERROR("cannot add field \"%s\" to variant",
+ g_quark_to_string(qfield_name));
+ goto error;
+ }
+ }
+
+ return 0;
+
+error:
+ BT_PUT(field_decl);
+
+ return ret;
+}
+
+static
+int visit_typedef(struct ctx *ctx, struct ctf_node *type_specifier_list,
+ struct bt_list_head *type_declarators)
+{
+ int ret = 0;
+ GQuark qidentifier;
+ struct ctf_node *iter;
+ _BT_CTF_FIELD_TYPE_INIT(type_decl);
+
+ bt_list_for_each_entry(iter, type_declarators, siblings) {
+ ret = visit_type_declarator(ctx, type_specifier_list,
+ &qidentifier, iter, &type_decl, NULL);
+ if (ret) {
+ _PERROR("%s", "problem creating type declaration");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ /* Do not allow typedef and typealias of untagged variants */
+ if (bt_ctf_field_type_is_variant(type_decl)) {
+ if (bt_ctf_field_type_variant_get_tag_name(type_decl)) {
+ _PERROR("%s", "typedef of untagged variant is not allowed");
+ ret = -EPERM;
+ goto end;
+ }
+ }
+
+ ret = ctx_decl_scope_register_alias(ctx->current_scope,
+ g_quark_to_string(qidentifier), type_decl);
+ if (ret) {
+ _PERROR("cannot register typedef \"%s\"",
+ g_quark_to_string(qidentifier));
+ goto end;
+ }
+ }
+
+end:
+ BT_PUT(type_decl);
+
+ return ret;
+}
+
+static
+int visit_typealias(struct ctx *ctx, struct ctf_node *target,
+ struct ctf_node *alias)
+{
+ int ret = 0;
+ GQuark qalias;
+ struct ctf_node *node;
+ GQuark qdummy_field_name;
+ _BT_CTF_FIELD_TYPE_INIT(type_decl);
+
+ /* Create target type declaration */
+ if (bt_list_empty(&target->u.typealias_target.type_declarators)) {
+ node = NULL;
+ } else {
+ node = _BT_LIST_FIRST_ENTRY(
+ &target->u.typealias_target.type_declarators,
+ struct ctf_node, siblings);
+ }
+
+ ret = visit_type_declarator(ctx,
+ target->u.typealias_target.type_specifier_list,
+ &qdummy_field_name, node, &type_decl, NULL);
+ if (ret) {
+ assert(!type_decl);
+ _PERROR("%s", "problem creating type declaration");
+ goto end;
+ }
+
+ /* Do not allow typedef and typealias of untagged variants */
+ if (bt_ctf_field_type_is_variant(type_decl)) {
+ if (bt_ctf_field_type_variant_get_tag_name(type_decl)) {
+ _PERROR("%s",
+ "typealias of untagged variant 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) {
+ _PERROR("%s", "expecting empty identifier");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ /* Create alias identifier */
+ node = _BT_LIST_FIRST_ENTRY(&alias->u.typealias_alias.type_declarators,
+ struct ctf_node, siblings);
+ qalias = create_typealias_identifier(ctx,
+ alias->u.typealias_alias.type_specifier_list, node);
+ ret = ctx_decl_scope_register_alias(ctx->current_scope,
+ g_quark_to_string(qalias), type_decl);
+ if (ret) {
+ _PERROR("cannot register typealias \"%s\"",
+ g_quark_to_string(qalias));
+ goto end;
+ }
+
+end:
+ BT_PUT(type_decl);
+
+ return ret;
+}
+
+static
+int visit_struct_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
+ struct bt_ctf_field_type *struct_decl)
+{
+ int ret = 0;
+
+ switch (entry_node->type) {
+ case NODE_TYPEDEF:
+ ret = visit_typedef(ctx,
+ entry_node->u._typedef.type_specifier_list,
+ &entry_node->u._typedef.type_declarators);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typedef in \"struct\" declaration");
+ goto end;
+ }
+ break;
+ case NODE_TYPEALIAS:
+ ret = visit_typealias(ctx, entry_node->u.typealias.target,
+ entry_node->u.typealias.alias);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typealias in \"struct\" declaration");
+ 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.
+ type_specifier_list,
+ &entry_node->u.struct_or_variant_declaration.
+ type_declarators);
+ if (ret) {
+ goto end;
+ }
+ break;
+ default:
+ _PERROR("unexpected node type: %d", (int) entry_node->type);
+ ret = -EINVAL;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static
+int visit_variant_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
+ struct bt_ctf_field_type *variant_decl)
+{
+ int ret = 0;
+
+ switch (entry_node->type) {
+ case NODE_TYPEDEF:
+ ret = visit_typedef(ctx,
+ entry_node->u._typedef.type_specifier_list,
+ &entry_node->u._typedef.type_declarators);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typedef in \"variant\" declaration");
+ goto end;
+ }
+ break;
+ case NODE_TYPEALIAS:
+ ret = visit_typealias(ctx, entry_node->u.typealias.target,
+ entry_node->u.typealias.alias);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typealias in \"variant\" declaration");
+ 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.
+ type_specifier_list,
+ &entry_node->u.struct_or_variant_declaration.
+ type_declarators);
+ if (ret) {
+ goto end;
+ }
+ break;
+ default:
+ _PERROR("unexpected node type: %d", (int) entry_node->type);
+ ret = -EINVAL;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static
+int visit_struct_decl(struct ctx *ctx, const char *name,
+ struct bt_list_head *decl_list, int has_body,
+ struct bt_list_head *min_align,
+ struct bt_ctf_field_type **struct_decl)
+{
+ int ret = 0;
+
+ *struct_decl = NULL;
+
+ /* For named struct (without body), lookup in declaration scope */
+ if (!has_body) {
+ _BT_CTF_FIELD_TYPE_INIT(struct_decl_copy);
+
+ if (!name) {
+ ret = -EPERM;
+ goto error;
+ }
+
+ *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope,
+ name, -1);
+ if (!*struct_decl) {
+ _PERROR("cannot find \"struct %s\"", name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Make a copy of it */
+ struct_decl_copy = bt_ctf_field_type_copy(*struct_decl);
+ if (!struct_decl_copy) {
+ _PERROR("%s",
+ "cannot create copy of structure declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ BT_MOVE(*struct_decl, struct_decl_copy);
+ } else {
+ struct ctf_node *entry_node;
+ uint64_t min_align_value = 0;
+
+ if (name) {
+ _BT_CTF_FIELD_TYPE_INIT(estruct_decl);
+
+ estruct_decl = ctx_decl_scope_lookup_struct(
+ ctx->current_scope, name, 1);
+ if (estruct_decl) {
+ BT_PUT(estruct_decl);
+ _PERROR("\"struct %s\" already declared in local scope",
+ name);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ if (!bt_list_empty(min_align)) {
+ ret = get_unary_unsigned(min_align, &min_align_value);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for structure declaration's \"align\" attribute");
+ goto error;
+ }
+ }
+
+ *struct_decl = bt_ctf_field_type_structure_create();
+ if (!*struct_decl) {
+ _PERROR("%s", "cannot create structure declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = ctx_push_scope(ctx);
+ if (ret) {
+ _PERROR("%s", "cannot push scope");
+ goto error;
+ }
+
+ bt_list_for_each_entry(entry_node, decl_list, siblings) {
+ ret = visit_struct_decl_entry(ctx, entry_node,
+ *struct_decl);
+ if (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) {
+ _PERROR("cannot register \"struct %s\" in declaration scope",
+ name);
+ goto error;
+ }
+ }
+ }
+
+ return 0;
+
+error:
+ BT_PUT(*struct_decl);
+
+ return ret;
+}
+
+static
+int visit_variant_decl(struct ctx *ctx, const char *name,
+ const char *tag, struct bt_list_head *decl_list,
+ int has_body, struct bt_ctf_field_type **variant_decl)
+{
+ int ret = 0;
+ _BT_CTF_FIELD_TYPE_INIT(untagged_variant_decl);
+
+ *variant_decl = NULL;
+
+ /* For named variant (without body), lookup in declaration scope */
+ if (!has_body) {
+ _BT_CTF_FIELD_TYPE_INIT(variant_decl_copy);
+
+ if (!name) {
+ ret = -EPERM;
+ goto error;
+ }
+
+ untagged_variant_decl =
+ ctx_decl_scope_lookup_variant(ctx->current_scope,
+ name, -1);
+ if (!untagged_variant_decl) {
+ _PERROR("cannot find \"variant %s\"", name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Make a copy of it */
+ variant_decl_copy = bt_ctf_field_type_copy(
+ untagged_variant_decl);
+ if (!variant_decl_copy) {
+ _PERROR("%s",
+ "cannot create copy of structure declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ BT_MOVE(untagged_variant_decl, variant_decl_copy);
+ } else {
+ struct ctf_node *entry_node;
+
+ if (name) {
+ struct bt_ctf_field_type *evariant_decl =
+ ctx_decl_scope_lookup_struct(ctx->current_scope,
+ name, 1);
+
+ if (evariant_decl) {
+ BT_PUT(evariant_decl);
+ _PERROR("\"variant %s\" already declared in local scope",
+ name);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ untagged_variant_decl = bt_ctf_field_type_variant_create(NULL,
+ NULL);
+ if (!untagged_variant_decl) {
+ _PERROR("%s", "cannot create variant declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = ctx_push_scope(ctx);
+ if (ret) {
+ _PERROR("%s", "cannot push scope");
+ 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) {
+ 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) {
+ _PERROR("cannot register \"variant %s\" in declaration scope",
+ name);
+ goto error;
+ }
+ }
+ }
+
+ /*
+ * If tagged, create tagged variant and return; otherwise
+ * return untagged variant.
+ */
+ if (!tag) {
+ BT_MOVE(*variant_decl, untagged_variant_decl);
+ } else {
+ /*
+ * At this point, we have a fresh untagged variant; nobody
+ * else owns it. Set its tag now.
+ */
+ ret = bt_ctf_field_type_variant_set_tag_name(
+ untagged_variant_decl, tag);
+ if (ret) {
+ goto error;
+ }
+
+ BT_MOVE(*variant_decl, untagged_variant_decl);
+ }
+
+ assert(!untagged_variant_decl);
+ assert(*variant_decl);
+
+ return 0;
+
+error:
+ BT_PUT(untagged_variant_decl);
+ BT_PUT(*variant_decl);
+
+ return ret;
+}
+
+static
+int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
+ struct bt_ctf_field_type *enum_decl, int64_t *last, int is_signed)
+{
+ int ret = 0;
+ int nr_vals = 0;
+ struct ctf_node *iter;
+ int64_t start = 0, end = 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) {
+ int64_t *target;
+
+ if (iter->type != NODE_UNARY_EXPRESSION) {
+ _PERROR("wrong unary expression for enumeration label \"%s\"",
+ 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 = iter->u.unary_expression.u.signed_constant;
+ break;
+ case UNARY_UNSIGNED_CONSTANT:
+ *target = (int64_t)
+ iter->u.unary_expression.u.unsigned_constant;
+ break;
+ default:
+ _PERROR("invalid enumeration entry: \"%s\"",
+ label);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (nr_vals > 1) {
+ _PERROR("invalid enumeration entry: \"%s\"",
+ label);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ nr_vals++;
+ }
+
+ if (nr_vals == 0) {
+ start = *last;
+ }
+
+ if (nr_vals <= 1) {
+ end = start;
+ }
+
+ *last = end + 1;
+
+ if (is_signed) {
+ ret = bt_ctf_field_type_enumeration_add_mapping(enum_decl, label,
+ start, end);
+ } else {
+ ret = bt_ctf_field_type_enumeration_add_mapping_unsigned(enum_decl,
+ label, (uint64_t) start, (uint64_t) end);
+ }
+ if (ret) {
+ _PERROR("cannot add mapping to enumeration for label \"%s\"",
+ label);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return ret;
+}
+
+static
+int visit_enum_decl(struct ctx *ctx, const char *name,
+ struct ctf_node *container_type,
+ struct bt_list_head *enumerator_list,
+ int has_body,
+ struct bt_ctf_field_type **enum_decl)
+{
+ int ret = 0;
+ GQuark qdummy_id;
+ _BT_CTF_FIELD_TYPE_INIT(integer_decl);
+
+ *enum_decl = NULL;
+
+ /* For named enum (without body), lookup in declaration scope */
+ if (!has_body) {
+ _BT_CTF_FIELD_TYPE_INIT(enum_decl_copy);
+
+ if (!name) {
+ ret = -EPERM;
+ goto error;
+ }
+
+ *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope,
+ name, -1);
+ if (!*enum_decl) {
+ _PERROR("cannot find \"enum %s\"", name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Make a copy of it */
+ enum_decl_copy = bt_ctf_field_type_copy(*enum_decl);
+ if (!enum_decl_copy) {
+ _PERROR("%s",
+ "cannot create copy of enumeration declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ BT_PUT(*enum_decl);
+ BT_MOVE(*enum_decl, enum_decl_copy);
+ } else {
+ struct ctf_node *iter;
+ int64_t last_value = 0;
+
+ if (name) {
+ _BT_CTF_FIELD_TYPE_INIT(eenum_decl);
+
+ eenum_decl = ctx_decl_scope_lookup_enum(
+ ctx->current_scope, name, 1);
+ if (eenum_decl) {
+ BT_PUT(eenum_decl);
+ _PERROR("\"enum %s\" already declared in local scope",
+ name);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ if (!container_type) {
+ integer_decl = ctx_decl_scope_lookup_alias(
+ ctx->current_scope, "int", -1);
+ if (!integer_decl) {
+ _PERROR("%s", "cannot find \"int\" type for enumeration");
+ ret = -EINVAL;
+ goto error;
+ }
+ } else {
+ ret = visit_type_declarator(ctx, container_type,
+ &qdummy_id, NULL, &integer_decl, NULL);
+ if (ret) {
+ assert(!integer_decl);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ assert(integer_decl);
+
+ if (!bt_ctf_field_type_is_integer(integer_decl)) {
+ _PERROR("%s", "container type for enumeration is not an integer");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ *enum_decl = bt_ctf_field_type_enumeration_create(integer_decl);
+ if (!*enum_decl) {
+ _PERROR("%s", "cannot create enumeration declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ bt_list_for_each_entry(iter, enumerator_list, siblings) {
+ ret = visit_enum_decl_entry(ctx, iter, *enum_decl,
+ &last_value,
+ bt_ctf_field_type_integer_get_signed(integer_decl));
+ if (ret) {
+ goto error;
+ }
+ }
+
+ if (name) {
+ ret = ctx_decl_scope_register_enum(ctx->current_scope,
+ name, *enum_decl);
+ if (ret) {
+ goto error;
+ }
+ }
+ }
+
+ BT_PUT(integer_decl);
+
+ return 0;
+
+error:
+ BT_PUT(integer_decl);
+ BT_PUT(*enum_decl);
+
+ return ret;
+}
+
+static
+int visit_type_specifier(struct ctx *ctx,
+ struct ctf_node *type_specifier_list,
+ struct bt_ctf_field_type **decl)
+{
+ int ret = 0;
+ GString *str = NULL;
+ _BT_CTF_FIELD_TYPE_INIT(decl_copy);
+
+ *decl = NULL;
+ str = g_string_new("");
+ ret = get_type_specifier_list_name(ctx, type_specifier_list, str);
+ if (ret) {
+ goto error;
+ }
+
+ *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1);
+ if (!*decl) {
+ _PERROR("cannot find type alias \"%s\"", str->str);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Make a copy of the type declaration */
+ decl_copy = bt_ctf_field_type_copy(*decl);
+ if (!decl_copy) {
+ _PERROR("%s", "cannot create copy of type declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ BT_MOVE(*decl, decl_copy);
+ (void) g_string_free(str, TRUE);
+ str = NULL;
+
+ return 0;
+
+error:
+ if (str) {
+ (void) g_string_free(str, TRUE);
+ }
+
+ BT_PUT(*decl);
+
+ return ret;
+}
+
+static
+int visit_integer_decl(struct ctx *ctx,
+ struct bt_list_head *expressions,
+ struct bt_ctf_field_type **integer_decl)
+{
+ int set = 0;
+ int ret = 0;
+ int signedness = 0;
+ struct ctf_node *expression;
+ uint64_t alignment = 0, size = 0;
+ struct bt_ctf_clock *mapped_clock = NULL;
+ enum bt_ctf_string_encoding encoding = BT_CTF_STRING_ENCODING_NONE;
+ enum bt_ctf_integer_base base = BT_CTF_INTEGER_BASE_DECIMAL;
+ enum bt_ctf_byte_order byte_order =
+ bt_ctf_trace_get_byte_order(ctx->trace);
+
+ *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) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left->u.unary_expression.u.string, "signed")) {
+ if (_IS_SET(&set, _INTEGER_SIGNED_SET)) {
+ _PERROR_DUP_ATTR("signed",
+ "integer declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ signedness = get_boolean(ctx->efd, right);
+ if (signedness < 0) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _INTEGER_SIGNED_SET);
+ } else if (!strcmp(left->u.unary_expression.u.string,
+ "byte_order")) {
+ if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) {
+ _PERROR_DUP_ATTR("byte_order",
+ "integer declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ byte_order = get_real_byte_order(ctx, right);
+ if (byte_order == BT_CTF_BYTE_ORDER_UNKNOWN) {
+ _PERROR("%s", "invalid \"byte_order\" attribute in integer declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _INTEGER_BYTE_ORDER_SET);
+ } else if (!strcmp(left->u.unary_expression.u.string, "size")) {
+ if (_IS_SET(&set, _INTEGER_SIZE_SET)) {
+ _PERROR_DUP_ATTR("size",
+ "integer declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type !=
+ UNARY_UNSIGNED_CONSTANT) {
+ _PERROR("%s", "invalid \"size\" attribute in integer declaration: expecting unsigned constant");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ size = right->u.unary_expression.u.unsigned_constant;
+ if (size == 0) {
+ _PERROR("%s", "invalid \"size\" attribute in integer declaration: expecting positive constant");
+ ret = -EINVAL;
+ goto error;
+ } else if (size > 64) {
+ _PERROR("%s", "invalid \"size\" attribute in integer declaration: integers over 64-bit are not supported as of this version");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _INTEGER_SIZE_SET);
+ } else if (!strcmp(left->u.unary_expression.u.string,
+ "align")) {
+ if (_IS_SET(&set, _INTEGER_ALIGN_SET)) {
+ _PERROR_DUP_ATTR("align",
+ "integer declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type !=
+ UNARY_UNSIGNED_CONSTANT) {
+ _PERROR("%s", "invalid \"align\" attribute in integer declaration: expecting unsigned constant");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ alignment =
+ right->u.unary_expression.u.unsigned_constant;
+ if (!is_align_valid(alignment)) {
+ _PERROR("%s", "invalid \"align\" attribute in integer declaration: expecting power of two");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _INTEGER_ALIGN_SET);
+ } else if (!strcmp(left->u.unary_expression.u.string, "base")) {
+ if (_IS_SET(&set, _INTEGER_BASE_SET)) {
+ _PERROR_DUP_ATTR("base", "integer declaration");
+ 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_CTF_INTEGER_BASE_BINARY;
+ break;
+ case 8:
+ base = BT_CTF_INTEGER_BASE_OCTAL;
+ break;
+ case 10:
+ base = BT_CTF_INTEGER_BASE_DECIMAL;
+ break;
+ case 16:
+ base = BT_CTF_INTEGER_BASE_HEXADECIMAL;
+ break;
+ default:
+ _PERROR("invalid \"base\" attribute in integer declaration: %" PRIu64,
+ right->u.unary_expression.u.unsigned_constant);
+ ret = -EINVAL;
+ goto error;
+ }
+ break;
+ }
+ case UNARY_STRING:
+ {
+ char *s_right = concatenate_unary_strings(
+ &expression->u.ctf_expression.right);
+ if (!s_right) {
+ _PERROR("%s", "unexpected unary expression for integer declaration's \"base\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(s_right, "decimal") ||
+ !strcmp(s_right, "dec") ||
+ !strcmp(s_right, "d") ||
+ !strcmp(s_right, "i") ||
+ !strcmp(s_right, "u")) {
+ base = BT_CTF_INTEGER_BASE_DECIMAL;
+ } else if (!strcmp(s_right, "hexadecimal") ||
+ !strcmp(s_right, "hex") ||
+ !strcmp(s_right, "x") ||
+ !strcmp(s_right, "X") ||
+ !strcmp(s_right, "p")) {
+ base = BT_CTF_INTEGER_BASE_HEXADECIMAL;
+ } else if (!strcmp(s_right, "octal") ||
+ !strcmp(s_right, "oct") ||
+ !strcmp(s_right, "o")) {
+ base = BT_CTF_INTEGER_BASE_OCTAL;
+ } else if (!strcmp(s_right, "binary") ||
+ !strcmp(s_right, "b")) {
+ base = BT_CTF_INTEGER_BASE_BINARY;
+ } else {
+ _PERROR("unexpected unary expression for integer declaration's \"base\" attribute: \"%s\"",
+ s_right);
+ g_free(s_right);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ g_free(s_right);
+ break;
+ }
+ default:
+ _PERROR("%s", "invalid \"base\" attribute in integer declaration: expecting unsigned constant or unary string");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _INTEGER_BASE_SET);
+ } else if (!strcmp(left->u.unary_expression.u.string,
+ "encoding")) {
+ char *s_right;
+
+ if (_IS_SET(&set, _INTEGER_ENCODING_SET)) {
+ _PERROR_DUP_ATTR("encoding",
+ "integer declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type != UNARY_STRING) {
+ _PERROR("%s", "invalid \"encoding\" attribute in integer declaration: expecting unary string");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ s_right = concatenate_unary_strings(
+ &expression->u.ctf_expression.right);
+ if (!s_right) {
+ _PERROR("%s", "unexpected unary expression for integer declaration's \"encoding\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(s_right, "UTF8") ||
+ !strcmp(s_right, "utf8") ||
+ !strcmp(s_right, "utf-8") ||
+ !strcmp(s_right, "UTF-8")) {
+ encoding = BT_CTF_STRING_ENCODING_UTF8;
+ } else if (!strcmp(s_right, "ASCII") ||
+ !strcmp(s_right, "ascii")) {
+ encoding = BT_CTF_STRING_ENCODING_ASCII;
+ } else if (!strcmp(s_right, "none")) {
+ encoding = BT_CTF_STRING_ENCODING_NONE;
+ } else {
+ _PERROR("invalid \"encoding\" attribute in integer declaration: unknown 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")) {
+ const char *clock_name;
+
+ if (_IS_SET(&set, _INTEGER_MAP_SET)) {
+ _PERROR_DUP_ATTR("map", "integer declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type != UNARY_STRING) {
+ _PERROR("%s", "invalid \"map\" attribute in integer declaration: 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 = concatenate_unary_strings(
+ &expression->u.ctf_expression.right);
+
+ if (!s_right) {
+ _PERROR("%s", "unexpected unary expression for integer declaration's \"map\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _PWARNING("invalid \"map\" attribute in integer declaration: unknown clock: \"%s\"",
+ s_right);
+ _SET(&set, _INTEGER_MAP_SET);
+ g_free(s_right);
+ continue;
+ }
+
+ mapped_clock = bt_ctf_trace_get_clock_by_name(
+ ctx->trace, clock_name);
+ if (!mapped_clock) {
+ _PERROR("invalid \"map\" attribute in integer declaration: cannot find clock \"%s\"",
+ clock_name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _INTEGER_MAP_SET);
+ } else {
+ _PWARNING("unknown attribute \"%s\" in integer declaration",
+ left->u.unary_expression.u.string);
+ }
+ }
+
+ if (!_IS_SET(&set, _INTEGER_SIZE_SET)) {
+ _PERROR("%s",
+ "missing \"size\" attribute in integer declaration");
+ 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 = bt_ctf_field_type_integer_create((unsigned int) size);
+ if (!*integer_decl) {
+ _PERROR("%s", "cannot create integer declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_field_type_integer_set_signed(*integer_decl, signedness);
+ ret |= bt_ctf_field_type_integer_set_base(*integer_decl, base);
+ ret |= bt_ctf_field_type_integer_set_encoding(*integer_decl, encoding);
+ ret |= bt_ctf_field_type_set_alignment(*integer_decl,
+ (unsigned int) alignment);
+ ret |= bt_ctf_field_type_set_byte_order(*integer_decl, byte_order);
+
+ if (mapped_clock) {
+ /* Move clock */
+ ret |= bt_ctf_field_type_integer_set_mapped_clock(
+ *integer_decl, mapped_clock);
+ bt_put(mapped_clock);
+ mapped_clock = NULL;
+ }
+
+ if (ret) {
+ _PERROR("%s", "cannot configure integer declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (mapped_clock) {
+ bt_put(mapped_clock);
+ }
+
+ BT_PUT(*integer_decl);
+
+ return ret;
+}
+
+static
+int visit_floating_point_number_decl(struct ctx *ctx,
+ struct bt_list_head *expressions,
+ struct bt_ctf_field_type **float_decl)
+{
+ int set = 0;
+ int ret = 0;
+ struct ctf_node *expression;
+ uint64_t alignment = 1, exp_dig = 0, mant_dig = 0;
+ enum bt_ctf_byte_order byte_order =
+ bt_ctf_trace_get_byte_order(ctx->trace);
+
+ *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) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left->u.unary_expression.u.string, "byte_order")) {
+ if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) {
+ _PERROR_DUP_ATTR("byte_order",
+ "floating point number declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ byte_order = get_real_byte_order(ctx, right);
+ if (byte_order == BT_CTF_BYTE_ORDER_UNKNOWN) {
+ _PERROR("%s", "invalid \"byte_order\" attribute in floating point number declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _FLOAT_BYTE_ORDER_SET);
+ } else if (!strcmp(left->u.unary_expression.u.string,
+ "exp_dig")) {
+ if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
+ _PERROR_DUP_ATTR("exp_dig",
+ "floating point number declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type !=
+ UNARY_UNSIGNED_CONSTANT) {
+ _PERROR("%s", "invalid \"exp_dig\" attribute in floating point number declaration: expecting unsigned constant");
+ 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")) {
+ if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
+ _PERROR_DUP_ATTR("mant_dig",
+ "floating point number declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type !=
+ UNARY_UNSIGNED_CONSTANT) {
+ _PERROR("%s", "invalid \"mant_dig\" attribute in floating point number declaration: expecting unsigned constant");
+ 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")) {
+ if (_IS_SET(&set, _FLOAT_ALIGN_SET)) {
+ _PERROR_DUP_ATTR("align",
+ "floating point number declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type !=
+ UNARY_UNSIGNED_CONSTANT) {
+ _PERROR("%s", "invalid \"align\" attribute in floating point number declaration: expecting unsigned constant");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ alignment = right->u.unary_expression.u.
+ unsigned_constant;
+
+ if (!is_align_valid(alignment)) {
+ _PERROR("%s", "invalid \"align\" attribute in floating point number declaration: expecting power of two");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(&set, _FLOAT_ALIGN_SET);
+ } else {
+ _PWARNING("unknown attribute \"%s\" in floating point number declaration",
+ left->u.unary_expression.u.string);
+ }
+ }
+
+ if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
+ _PERROR("%s", "missing \"mant_dig\" attribute in floating point number declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
+ _PERROR("%s", "missing \"exp_dig\" attribute in floating point number declaration");
+ 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 = bt_ctf_field_type_floating_point_create();
+ if (!*float_decl) {
+ _PERROR("%s",
+ "cannot create floating point number declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_field_type_floating_point_set_exponent_digits(
+ *float_decl, exp_dig);
+ ret |= bt_ctf_field_type_floating_point_set_mantissa_digits(
+ *float_decl, mant_dig);
+ ret |= bt_ctf_field_type_set_byte_order(*float_decl, byte_order);
+ ret |= bt_ctf_field_type_set_alignment(*float_decl, alignment);
+ if (ret) {
+ _PERROR("%s",
+ "cannot configure floating point number declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ BT_PUT(*float_decl);
+
+ return ret;
+}
+
+static
+int visit_string_decl(struct ctx *ctx,
+ struct bt_list_head *expressions,
+ struct bt_ctf_field_type **string_decl)
+{
+ int set = 0;
+ int ret = 0;
+ struct ctf_node *expression;
+ enum bt_ctf_string_encoding encoding = BT_CTF_STRING_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) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
+ char *s_right;
+
+ if (_IS_SET(&set, _STRING_ENCODING_SET)) {
+ _PERROR_DUP_ATTR("encoding",
+ "string declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (right->u.unary_expression.type != UNARY_STRING) {
+ _PERROR("%s", "invalid \"encoding\" attribute in string declaration: expecting unary string");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ s_right = concatenate_unary_strings(
+ &expression->u.ctf_expression.right);
+ if (!s_right) {
+ _PERROR("%s", "unexpected unary expression for string declaration's \"encoding\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(s_right, "UTF8") ||
+ !strcmp(s_right, "utf8") ||
+ !strcmp(s_right, "utf-8") ||
+ !strcmp(s_right, "UTF-8")) {
+ encoding = BT_CTF_STRING_ENCODING_UTF8;
+ } else if (!strcmp(s_right, "ASCII") ||
+ !strcmp(s_right, "ascii")) {
+ encoding = BT_CTF_STRING_ENCODING_ASCII;
+ } else if (!strcmp(s_right, "none")) {
+ encoding = BT_CTF_STRING_ENCODING_NONE;
+ } else {
+ _PERROR("invalid \"encoding\" attribute in string declaration: unknown encoding \"%s\"",
+ s_right);
+ g_free(s_right);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ g_free(s_right);
+ _SET(&set, _STRING_ENCODING_SET);
+ } else {
+ _PWARNING("unknown attribute \"%s\" in string declaration",
+ left->u.unary_expression.u.string);
+ }
+ }
+
+ *string_decl = bt_ctf_field_type_string_create();
+ if (!*string_decl) {
+ _PERROR("%s", "cannot create string declaration");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_field_type_string_set_encoding(*string_decl, encoding);
+ if (ret) {
+ _PERROR("%s", "cannot configure string declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ BT_PUT(*string_decl);
+
+ return ret;
+}
+
+static
+int visit_type_specifier_list(struct ctx *ctx,
+ struct ctf_node *ts_list,
+ struct bt_ctf_field_type **decl)
+{
+ int ret = 0;
+ struct ctf_node *first, *node;
+
+ *decl = NULL;
+
+ if (ts_list->type != NODE_TYPE_SPECIFIER_LIST) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ first = _BT_LIST_FIRST_ENTRY(&ts_list->u.type_specifier_list.head,
+ struct ctf_node, siblings);
+ if (first->type != NODE_TYPE_SPECIFIER) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ node = first->u.type_specifier.node;
+
+ switch (first->u.type_specifier.type) {
+ case TYPESPEC_INTEGER:
+ ret = visit_integer_decl(ctx, &node->u.integer.expressions,
+ decl);
+ if (ret) {
+ assert(!*decl);
+ goto error;
+ }
+ break;
+ case TYPESPEC_FLOATING_POINT:
+ ret = visit_floating_point_number_decl(ctx,
+ &node->u.floating_point.expressions, decl);
+ if (ret) {
+ assert(!*decl);
+ goto error;
+ }
+ break;
+ case TYPESPEC_STRING:
+ ret = visit_string_decl(ctx,
+ &node->u.string.expressions, decl);
+ if (ret) {
+ assert(!*decl);
+ goto error;
+ }
+ break;
+ case TYPESPEC_STRUCT:
+ ret = visit_struct_decl(ctx, node->u._struct.name,
+ &node->u._struct.declaration_list,
+ node->u._struct.has_body,
+ &node->u._struct.min_align, decl);
+ if (ret) {
+ assert(!*decl);
+ goto error;
+ }
+ break;
+ case TYPESPEC_VARIANT:
+ ret = visit_variant_decl(ctx, node->u.variant.name,
+ node->u.variant.choice,
+ &node->u.variant.declaration_list,
+ node->u.variant.has_body, decl);
+ if (ret) {
+ assert(!*decl);
+ goto error;
+ }
+ break;
+ case TYPESPEC_ENUM:
+ ret = visit_enum_decl(ctx, node->u._enum.enum_id,
+ node->u._enum.container_type,
+ &node->u._enum.enumerator_list,
+ node->u._enum.has_body, decl);
+ if (ret) {
+ assert(!*decl);
+ goto error;
+ }
+ 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_type_specifier(ctx, ts_list, decl);
+ if (ret) {
+ assert(!*decl);
+ goto error;
+ }
+ break;
+ default:
+ _PERROR("unexpected node type: %d",
+ (int) first->u.type_specifier.type);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ assert(*decl);
+
+ return 0;
+
+error:
+ BT_PUT(*decl);
+
+ return ret;
+}
+
+static
+int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
+ struct bt_ctf_event_class *event_class, int64_t *stream_id,
+ int *set)
+{
+ int ret = 0;
+ char *left = NULL;
+ _BT_CTF_FIELD_TYPE_INIT(decl);
+
+ switch (node->type) {
+ case NODE_TYPEDEF:
+ ret = visit_typedef(ctx, node->u._typedef.type_specifier_list,
+ &node->u._typedef.type_declarators);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typedef in \"event\" declaration");
+ goto error;
+ }
+ break;
+ case NODE_TYPEALIAS:
+ ret = visit_typealias(ctx, node->u.typealias.target,
+ node->u.typealias.alias);
+ if (ret) {
+ _PERROR("%s", "cannot add typealias in \"event\" declaration");
+ goto error;
+ }
+ break;
+ case NODE_CTF_EXPRESSION:
+ {
+ left = concatenate_unary_strings(&node->u.ctf_expression.left);
+ if (!left) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left, "name")) {
+ /* This is already known at this stage */
+ if (_IS_SET(set, _EVENT_NAME_SET)) {
+ _PERROR_DUP_ATTR("name", "event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ _SET(set, _EVENT_NAME_SET);
+ } else if (!strcmp(left, "id")) {
+ int64_t id;
+
+ if (_IS_SET(set, _EVENT_ID_SET)) {
+ _PERROR_DUP_ATTR("id", "event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(&node->u.ctf_expression.right,
+ (uint64_t *) &id);
+ if (ret || id < 0) {
+ _PERROR("%s", "unexpected unary expression for event declaration's \"id\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_event_class_set_id(event_class, id);
+ if (ret) {
+ _PERROR("%s",
+ "cannot set event declaration's ID");
+ goto error;
+ }
+
+ _SET(set, _EVENT_ID_SET);
+ } else if (!strcmp(left, "stream_id")) {
+ if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
+ _PERROR_DUP_ATTR("stream_id",
+ "event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(&node->u.ctf_expression.right,
+ (uint64_t *) stream_id);
+ if (ret || *stream_id < 0) {
+ _PERROR("%s", "unexpected unary expression for event declaration's \"stream_id\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(set, _EVENT_STREAM_ID_SET);
+ } else if (!strcmp(left, "context")) {
+ if (_IS_SET(set, _EVENT_CONTEXT_SET)) {
+ _PERROR("%s", "duplicate \"context\" entry in event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = visit_type_specifier_list(ctx,
+ _BT_LIST_FIRST_ENTRY(
+ &node->u.ctf_expression.right,
+ struct ctf_node, siblings),
+ &decl);
+ if (ret) {
+ _PERROR("%s", "cannot create event context declaration");
+ goto error;
+ }
+
+ assert(decl);
+ ret = bt_ctf_event_class_set_context_type(
+ event_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set event's context declaration");
+ goto error;
+ }
+
+ _SET(set, _EVENT_CONTEXT_SET);
+ } else if (!strcmp(left, "fields")) {
+ if (_IS_SET(set, _EVENT_FIELDS_SET)) {
+ _PERROR("%s", "duplicate \"fields\" entry in event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = visit_type_specifier_list(ctx,
+ _BT_LIST_FIRST_ENTRY(
+ &node->u.ctf_expression.right,
+ struct ctf_node, siblings),
+ &decl);
+ if (ret) {
+ _PERROR("%s", "cannot create event payload declaration");
+ goto error;
+ }
+
+ assert(decl);
+ ret = bt_ctf_event_class_set_payload_type(
+ event_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set event's payload declaration");
+ goto error;
+ }
+
+ _SET(set, _EVENT_FIELDS_SET);
+ } else if (!strcmp(left, "loglevel")) {
+ uint64_t loglevel;
+
+ if (_IS_SET(set, _EVENT_LOGLEVEL_SET)) {
+ _PERROR_DUP_ATTR("loglevel",
+ "event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(&node->u.ctf_expression.right,
+ &loglevel);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for event declaration's \"loglevel\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ // TODO: FIXME: set log level here
+
+ _SET(set, _EVENT_LOGLEVEL_SET);
+ } else if (!strcmp(left, "model.emf.uri")) {
+ char *right;
+
+ if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) {
+ _PERROR_DUP_ATTR("model.emf.uri",
+ "event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ right = concatenate_unary_strings(
+ &node->u.ctf_expression.right);
+ if (!right) {
+ _PERROR("%s", "unexpected unary expression for event declaration's \"model.emf.uri\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ // TODO: FIXME: set model EMF URI here
+
+ g_free(right);
+ _SET(set, _EVENT_MODEL_EMF_URI_SET);
+ } else {
+ _PWARNING("unknown attribute \"%s\" in event declaration",
+ left);
+ }
+
+ g_free(left);
+ left = NULL;
+ break;
+ }
+ default:
+ ret = -EPERM;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (left) {
+ g_free(left);
+ }
+
+ BT_PUT(decl);
+
+ return ret;
+}
+
+static
+char *get_event_decl_name(struct ctx *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 = concatenate_unary_strings(&iter->u.ctf_expression.left);
+ if (!left) {
+ goto error;
+ }
+
+ if (!strcmp(left, "name")) {
+ name = concatenate_unary_strings(
+ &iter->u.ctf_expression.right);
+ if (!name) {
+ _PERROR("%s", "unexpected unary expression for event declaration's \"name\" attribute");
+ goto error;
+ }
+ }
+
+ g_free(left);
+ left = NULL;
+
+ if (name) {
+ break;
+ }
+ }
+
+ return name;
+
+error:
+ g_free(left);
+
+ return NULL;
+}
+
+static
+int reset_event_decl_types(struct ctx *ctx,
+ struct bt_ctf_event_class *event_class)
+{
+ int ret = 0;
+ _BT_CTF_FIELD_TYPE_INIT(decl);
+
+ /* Event context */
+ decl = bt_ctf_field_type_structure_create();
+ if (!decl) {
+ _PERROR("%s", "cannot create initial, empty event context structure");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_event_class_set_context_type(event_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set initial, empty event context structure");
+ goto error;
+ }
+
+ /* Event payload */
+ decl = bt_ctf_field_type_structure_create();
+ if (!decl) {
+ _PERROR("%s", "cannot create initial, empty event payload structure");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_event_class_set_payload_type(event_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set initial, empty event payload structure");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ BT_PUT(decl);
+
+ return ret;
+}
+
+static
+int reset_stream_decl_types(struct ctx *ctx,
+ struct bt_ctf_stream_class *stream_class)
+{
+ int ret = 0;
+ _BT_CTF_FIELD_TYPE_INIT(decl);
+
+ /* Packet context */
+ decl = bt_ctf_field_type_structure_create();
+ if (!decl) {
+ _PERROR("%s", "cannot create initial, empty packet context structure");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_stream_class_set_packet_context_type(stream_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set initial, empty packet context structure");
+ goto error;
+ }
+
+ /* Event header */
+ decl = bt_ctf_field_type_structure_create();
+ if (!decl) {
+ _PERROR("%s", "cannot create initial, empty event header structure");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_stream_class_set_event_header_type(stream_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set initial, empty event header structure");
+ goto error;
+ }
+
+ /* Event context */
+ decl = bt_ctf_field_type_structure_create();
+ if (!decl) {
+ _PERROR("%s", "cannot create initial, empty stream event context structure");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_stream_class_set_event_context_type(stream_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set initial, empty stream event context structure");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ BT_PUT(decl);
+
+ return ret;
+}
+
+static
+struct bt_ctf_stream_class *create_reset_stream_class(struct ctx *ctx)
+{
+ int ret;
+ struct bt_ctf_stream_class *stream_class;
+
+ stream_class = bt_ctf_stream_class_create(NULL);
+ if (!stream_class) {
+ _PERROR("%s", "cannot create stream class");
+ goto error;
+ }
+
+ /*
+ * Set packet context, event header, and event context to empty
+ * structures to override the default ones.
+ */
+ ret = reset_stream_decl_types(ctx, stream_class);
+ if (ret) {
+ goto error;
+ }
+
+ return stream_class;
+
+error:
+ BT_PUT(stream_class);
+
+ return NULL;
+}
+
+static
+int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
+{
+ int ret = 0;
+ int set = 0;
+ int64_t event_id;
+ struct ctf_node *iter;
+ int64_t stream_id = -1;
+ char *event_name = NULL;
+ struct bt_ctf_event_class *event_class = NULL;
+ struct bt_ctf_event_class *eevent_class;
+ struct bt_ctf_stream_class *stream_class;
+ struct bt_list_head *decl_list = &node->u.event.declaration_list;
+
+ if (node->visited) {
+ goto end;
+ }
+
+ node->visited = TRUE;
+ event_name = get_event_decl_name(ctx, node);
+ if (!event_name) {
+ _PERROR("%s",
+ "missing \"name\" attribute in event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ event_class = bt_ctf_event_class_create(event_name);
+
+ /*
+ * Set context and fields to empty structures to override the
+ * default ones.
+ */
+ ret = reset_event_decl_types(ctx, event_class);
+ if (ret) {
+ goto error;
+ }
+
+
+ ret = ctx_push_scope(ctx);
+ if (ret) {
+ _PERROR("%s", "cannot push scope");
+ goto error;
+ }
+
+ bt_list_for_each_entry(iter, decl_list, siblings) {
+ ret = visit_event_decl_entry(ctx, iter, event_class,
+ &stream_id, &set);
+ if (ret) {
+ goto error;
+ }
+ }
+
+ if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) {
+ GList *keys = NULL;
+ struct bt_ctf_stream_class *new_stream_class;
+
+ /* Allow missing stream_id if there is only a single stream */
+ switch (g_hash_table_size(ctx->stream_classes)) {
+ case 0:
+ /* Create stream if there's none */
+ new_stream_class = create_reset_stream_class(ctx);
+ if (!new_stream_class) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_stream_class_set_id(new_stream_class, 0);
+ if (ret) {
+ _PERROR("%s", "cannot set stream's ID");
+ BT_PUT(new_stream_class);
+ goto error;
+ }
+
+ stream_id = 0;
+
+ /* Move reference to visitor's context */
+ g_hash_table_insert(ctx->stream_classes,
+ (gpointer) stream_id, new_stream_class);
+ new_stream_class = NULL;
+
+ break;
+ case 1:
+ /* Single stream: get its ID */
+ keys = g_hash_table_get_keys(ctx->stream_classes);
+ stream_id = (int64_t) keys->data;
+ g_list_free(keys);
+ keys = NULL;
+ break;
+ default:
+ _PERROR("%s", "missing \"stream_id\" attribute in event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+ }
+
+
+
+ assert(stream_id >= 0);
+
+ /* We have the stream ID now; borrow the stream class if found */
+ stream_class = g_hash_table_lookup(ctx->stream_classes,
+ (gpointer) stream_id);
+ if (!stream_class) {
+ _PERROR("cannot find stream class with ID %" PRId64,
+ stream_id);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!_IS_SET(&set, _EVENT_ID_SET)) {
+ /* Allow only one event without ID per stream */
+ if (bt_ctf_stream_class_get_event_class_count(stream_class) !=
+ 0) {
+ _PERROR("%s",
+ "missing \"id\" field in event declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ /* Automatic ID */
+ ret = bt_ctf_event_class_set_id(event_class, 0);
+ if (ret) {
+ _PERROR("%s", "cannot set event's ID");
+ goto error;
+ }
+ }
+
+ event_id = bt_ctf_event_class_get_id(event_class);
+ if (event_id < 0) {
+ _PERROR("%s", "cannot get event's ID");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ eevent_class = bt_ctf_stream_class_get_event_class_by_id(stream_class,
+ event_id);
+ if (eevent_class) {
+ BT_PUT(eevent_class);
+ _PERROR("%s", "duplicate event with ID %" PRId64 " in same stream");
+ ret = -EEXIST;
+ goto error;
+ }
+
+ eevent_class = bt_ctf_stream_class_get_event_class_by_name(stream_class,
+ event_name);
+ if (eevent_class) {
+ BT_PUT(eevent_class);
+ eevent_class = NULL;
+ _PERROR("%s",
+ "duplicate event with name \"%s\" in same stream");
+ ret = -EEXIST;
+ goto error;
+ }
+
+ g_free(event_name);
+ ret = bt_ctf_stream_class_add_event_class(stream_class, event_class);
+ BT_PUT(event_class);
+ event_class = NULL;
+
+ if (ret) {
+ _PERROR("%s", "cannot add event class to stream class");
+ goto error;
+ }
+
+end:
+ return 0;
+
+error:
+ g_free(event_name);
+ BT_PUT(event_class);
+
+ /* stream_class is borrowed; it still belongs to the hash table */
+
+ return ret;
+}
+
+static
+int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
+ struct bt_ctf_stream_class *stream_class, int *set)
+{
+ int ret = 0;
+ char *left = NULL;
+ _BT_CTF_FIELD_TYPE_INIT(decl);
+
+ switch (node->type) {
+ case NODE_TYPEDEF:
+ ret = visit_typedef(ctx, node->u._typedef.type_specifier_list,
+ &node->u._typedef.type_declarators);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typedef in \"stream\" declaration");
+ goto error;
+ }
+ break;
+ case NODE_TYPEALIAS:
+ ret = visit_typealias(ctx, node->u.typealias.target,
+ node->u.typealias.alias);
+ if (ret) {
+ _PERROR("%s", "cannot add typealias in \"stream\" declaration");
+ goto error;
+ }
+ break;
+ case NODE_CTF_EXPRESSION:
+ {
+ left = concatenate_unary_strings(&node->u.ctf_expression.left);
+ if (!left) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left, "id")) {
+ int64_t id;
+ gpointer ptr;
+
+ if (_IS_SET(set, _STREAM_ID_SET)) {
+ _PERROR_DUP_ATTR("id", "stream declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(&node->u.ctf_expression.right,
+ (uint64_t *) &id);
+ if (ret || id < 0) {
+ _PERROR("%s", "unexpected unary expression for stream declaration's \"id\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ptr = g_hash_table_lookup(ctx->stream_classes,
+ (gpointer) id);
+ if (ptr) {
+ _PERROR("duplicate stream with ID %" PRId64,
+ id);
+ ret = -EEXIST;
+ goto error;
+ }
+
+ ret = bt_ctf_stream_class_set_id(stream_class, id);
+ if (ret) {
+ _PERROR("%s",
+ "cannot set stream declaration's ID");
+ goto error;
+ }
+
+ _SET(set, _STREAM_ID_SET);
+ } else if (!strcmp(left, "event.header")) {
+ if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
+ _PERROR("%s", "duplicate \"event.header\" entry in stream declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = visit_type_specifier_list(ctx,
+ _BT_LIST_FIRST_ENTRY(
+ &node->u.ctf_expression.right,
+ struct ctf_node, siblings),
+ &decl);
+ if (ret) {
+ _PERROR("%s", "cannot create event header declaration");
+ goto error;
+ }
+
+ assert(decl);
+
+ ret = bt_ctf_stream_class_set_event_header_type(
+ stream_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set stream's event header declaration");
+ goto error;
+ }
+
+ _SET(set, _STREAM_EVENT_HEADER_SET);
+ } else if (!strcmp(left, "event.context")) {
+ if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
+ _PERROR("%s", "duplicate \"event.context\" entry in stream declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = visit_type_specifier_list(ctx,
+ _BT_LIST_FIRST_ENTRY(
+ &node->u.ctf_expression.right,
+ struct ctf_node, siblings),
+ &decl);
+ if (ret) {
+ _PERROR("%s", "cannot create stream event context declaration");
+ goto error;
+ }
+
+ assert(decl);
+
+ ret = bt_ctf_stream_class_set_event_context_type(
+ stream_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set stream's event context declaration");
+ goto error;
+ }
+
+ _SET(set, _STREAM_EVENT_CONTEXT_SET);
+ } else if (!strcmp(left, "packet.context")) {
+ if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
+ _PERROR("%s", "duplicate \"packet.context\" entry in stream declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = visit_type_specifier_list(ctx,
+ _BT_LIST_FIRST_ENTRY(
+ &node->u.ctf_expression.right,
+ struct ctf_node, siblings),
+ &decl);
+ if (ret) {
+ _PERROR("%s", "cannot create packet context declaration");
+ goto error;
+ }
+
+ assert(decl);
+
+ ret = bt_ctf_stream_class_set_packet_context_type(
+ stream_class, decl);
+ BT_PUT(decl);
+ if (ret) {
+ _PERROR("%s", "cannot set stream's packet context declaration");
+ goto error;
+ }
+
+ _SET(set, _STREAM_PACKET_CONTEXT_SET);
+ } else {
+ _PWARNING("unknown attribute \"%s\" in stream declaration",
+ left);
+ }
+
+ g_free(left);
+ left = NULL;
+ break;
+ }
+
+ default:
+ ret = -EPERM;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ g_free(left);
+ BT_PUT(decl);
+
+ return ret;
+}
+
+static
+int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
+{
+ int64_t id;
+ int set = 0;
+ int ret = 0;
+ struct ctf_node *iter;
+ struct bt_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 = create_reset_stream_class(ctx);
+ if (!stream_class) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = ctx_push_scope(ctx);
+ if (ret) {
+ _PERROR("%s", "cannot push scope");
+ goto error;
+ }
+
+ bt_list_for_each_entry(iter, decl_list, siblings) {
+ ret = visit_stream_decl_entry(ctx, iter, stream_class, &set);
+ if (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 */
+ _BT_CTF_FIELD_TYPE_INIT(stream_id_decl);
+ _BT_CTF_FIELD_TYPE_INIT(packet_header_decl);
+
+ packet_header_decl =
+ bt_ctf_trace_get_packet_header_type(ctx->trace);
+ if (!packet_header_decl) {
+ _PERROR("%s",
+ "cannot get trace packet header declaration");
+ goto error;
+ }
+
+ stream_id_decl =
+ bt_ctf_field_type_structure_get_field_type_by_name(
+ packet_header_decl, "stream_id");
+ BT_PUT(packet_header_decl);
+ if (!stream_id_decl) {
+ _PERROR("%s", "missing \"stream_id\" field in packet header declaration, but \"id\" attribute is declared for stream");
+ goto error;
+ }
+
+ if (!bt_ctf_field_type_is_integer(stream_id_decl)) {
+ BT_PUT(stream_id_decl);
+ _PERROR("%s", "\"stream_id\" field in packet header declaration is not an integer");
+ goto error;
+ }
+
+ BT_PUT(stream_id_decl);
+ } else {
+ /* Allow only _one_ ID-less stream */
+ if (g_hash_table_size(ctx->stream_classes) != 0) {
+ _PERROR("%s",
+ "missing \"id\" field in stream declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ /* Automatic ID: 0 */
+ ret = bt_ctf_stream_class_set_id(stream_class, 0);
+ }
+
+ id = bt_ctf_stream_class_get_id(stream_class);
+ if (id < 0) {
+ _PERROR("wrong stream ID: %" PRId64, id);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Move reference to visitor's context */
+ g_hash_table_insert(ctx->stream_classes, (gpointer) (int64_t) id,
+ stream_class);
+ stream_class = NULL;
+
+end:
+ return 0;
+
+error:
+ BT_PUT(stream_class);
+
+ return ret;
+}
+
+static
+int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
+{
+ int ret = 0;
+ char *left = NULL;
+ _BT_CTF_FIELD_TYPE_INIT(packet_header_decl);
+
+ switch (node->type) {
+ case NODE_TYPEDEF:
+ ret = visit_typedef(ctx, node->u._typedef.type_specifier_list,
+ &node->u._typedef.type_declarators);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typedef in \"trace\" declaration");
+ goto error;
+ }
+ break;
+ case NODE_TYPEALIAS:
+ ret = visit_typealias(ctx, node->u.typealias.target,
+ node->u.typealias.alias);
+ if (ret) {
+ _PERROR("%s",
+ "cannot add typealias in \"trace\" declaration");
+ goto error;
+ }
+ break;
+ case NODE_CTF_EXPRESSION:
+ {
+ left = concatenate_unary_strings(&node->u.ctf_expression.left);
+ if (!left) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left, "major")) {
+ if (_IS_SET(set, _TRACE_MAJOR_SET)) {
+ _PERROR_DUP_ATTR("major", "trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(&node->u.ctf_expression.right,
+ &ctx->trace_major);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for trace's \"major\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(set, _TRACE_MAJOR_SET);
+ } else if (!strcmp(left, "minor")) {
+ if (_IS_SET(set, _TRACE_MINOR_SET)) {
+ _PERROR_DUP_ATTR("minor", "trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(&node->u.ctf_expression.right,
+ &ctx->trace_minor);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for trace's \"minor\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ _SET(set, _TRACE_MINOR_SET);
+ } else if (!strcmp(left, "uuid")) {
+ if (_IS_SET(set, _TRACE_UUID_SET)) {
+ _PERROR_DUP_ATTR("uuid", "trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_uuid(&node->u.ctf_expression.right,
+ ctx->trace_uuid);
+ if (ret) {
+ _PERROR("%s",
+ "invalid trace declaration's UUID");
+ goto error;
+ }
+
+ _SET(set, _TRACE_UUID_SET);
+ } else if (!strcmp(left, "byte_order")) {
+ /* Native byte order is already known at this stage */
+ if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
+ _PERROR_DUP_ATTR("byte_order",
+ "trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ _SET(set, _TRACE_BYTE_ORDER_SET);
+ } else if (!strcmp(left, "packet.header")) {
+ if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
+ _PERROR("%s", "duplicate \"packet.header\" entry in trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = visit_type_specifier_list(ctx,
+ _BT_LIST_FIRST_ENTRY(
+ &node->u.ctf_expression.right,
+ struct ctf_node, siblings),
+ &packet_header_decl);
+ if (ret) {
+ _PERROR("%s", "cannot create packet header declaration");
+ goto error;
+ }
+
+ assert(packet_header_decl);
+ ret = bt_ctf_trace_set_packet_header_type(ctx->trace,
+ packet_header_decl);
+ BT_PUT(packet_header_decl);
+ if (ret) {
+ _PERROR("%s", "cannot set trace declaration's packet header declaration");
+ goto error;
+ }
+
+ _SET(set, _TRACE_PACKET_HEADER_SET);
+ } else {
+ _PWARNING("%s", "unknown attribute \"%s\" in trace declaration");
+ }
+
+ g_free(left);
+ left = NULL;
+ break;
+ }
+ default:
+ _PERROR("%s", "unknown expression in trace declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ g_free(left);
+ BT_PUT(packet_header_decl);
+
+ return ret;
+}
+
+static
+int visit_trace_decl(struct ctx *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) {
+ _PERROR("%s", "duplicate \"trace\" block");
+ ret = -EEXIST;
+ goto error;
+ }
+
+ ret = ctx_push_scope(ctx);
+ if (ret) {
+ _PERROR("%s", "cannot push scope");
+ goto error;
+ }
+
+ bt_list_for_each_entry(iter, decl_list, siblings) {
+ ret = visit_trace_decl_entry(ctx, iter, &set);
+ if (ret) {
+ ctx_pop_scope(ctx);
+ goto error;
+ }
+ }
+
+ ctx_pop_scope(ctx);
+
+ if (!_IS_SET(&set, _TRACE_MAJOR_SET)) {
+ _PERROR("%s",
+ "missing \"major\" attribute in trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (!_IS_SET(&set, _TRACE_MINOR_SET)) {
+ _PERROR("%s",
+ "missing \"minor\" attribute in trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+ _PERROR("%s", "missing \"byte_order\" attribute in trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ctx->is_trace_visited = TRUE;
+
+end:
+ return 0;
+
+error:
+ return ret;
+}
+
+static
+int visit_env(struct ctx *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) {
+ _PERROR("%s", "wrong expression in environment entry");
+ ret = -EPERM;
+ goto error;
+ }
+
+ left = concatenate_unary_strings(
+ &entry_node->u.ctf_expression.left);
+ if (!left) {
+ _PERROR("%s", "cannot get environment entry name");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (is_unary_string(right_head)) {
+ char *right = concatenate_unary_strings(right_head);
+
+ if (!right) {
+ _PERROR("unexpected unary expression for environment entry's value (\"%s\")",
+ left);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ printf_verbose("env.%s = \"%s\"\n", left, right);
+ ret = bt_ctf_trace_set_environment_field_string(
+ ctx->trace, left, right);
+ g_free(right);
+
+ if (ret) {
+ _PERROR("environment: cannot add entry \"%s\" to trace",
+ left);
+ goto error;
+ }
+ } 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(right_head,
+ (uint64_t *) &v);
+ } else {
+ ret = get_unary_signed(right_head, &v);
+ }
+ if (ret) {
+ _PERROR("unexpected unary expression for environment entry's value (\"%s\")",
+ left);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ printf_verbose("env.%s = %" PRId64 "\n", left, v);
+ ret = bt_ctf_trace_set_environment_field_integer(
+ ctx->trace, left, v);
+ if (ret) {
+ _PERROR("environment: cannot add entry \"%s\" to trace",
+ left);
+ goto error;
+ }
+ } else {
+ printf_verbose("%s: environment entry \"%s\" has unknown type\n",
+ __func__, left);
+ }
+
+ g_free(left);
+ left = NULL;
+ }
+
+end:
+ return 0;
+
+error:
+ g_free(left);
+
+ return ret;
+}
+
+static
+int set_trace_byte_order(struct ctx *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 = concatenate_unary_strings(
+ &node->u.ctf_expression.left);
+ if (!left) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left, "byte_order")) {
+ enum bt_ctf_byte_order bo;
+
+ if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+ _PERROR_DUP_ATTR("byte_order",
+ "trace declaration");
+ 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->efd,
+ right_node);
+ if (bo == BT_CTF_BYTE_ORDER_UNKNOWN) {
+ _PERROR("%s", "unknown \"byte_order\" attribute in trace declaration");
+ ret = -EINVAL;
+ goto error;
+ } else if (bo == BT_CTF_BYTE_ORDER_NATIVE) {
+ _PERROR("%s", "\"byte_order\" attribute cannot be set to \"native\" in trace declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = bt_ctf_trace_set_byte_order(
+ ctx->trace, bo);
+ if (ret) {
+ _PERROR("cannot set trace's byte order (%d)",
+ ret);
+ goto error;
+ }
+ }
+
+ g_free(left);
+ left = NULL;
+ }
+ }
+
+ if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+ _PERROR("%s", "missing \"byte_order\" attribute in trace declaration");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ g_free(left);
+
+ return ret;
+}
+
+static
+int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
+ struct bt_ctf_clock *clock, int *set)
+{
+ int ret = 0;
+ char *left = NULL;
+
+ if (entry_node->type != NODE_CTF_EXPRESSION) {
+ ret = -EPERM;
+ goto error;
+ }
+
+ left = concatenate_unary_strings(&entry_node->u.ctf_expression.left);
+ if (!left) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(left, "name")) {
+ char *right;
+
+ if (_IS_SET(set, _CLOCK_NAME_SET)) {
+ _PERROR_DUP_ATTR("name", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ right = concatenate_unary_strings(
+ &entry_node->u.ctf_expression.right);
+ if (!right) {
+ _PERROR("%s", "unexpected unary expression for clock declaration's \"name\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_name(clock, right);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's name");
+ g_free(right);
+ goto error;
+ }
+
+ g_free(right);
+ _SET(set, _CLOCK_NAME_SET);
+ } else if (!strcmp(left, "uuid")) {
+ unsigned char uuid[BABELTRACE_UUID_LEN];
+
+ if (_IS_SET(set, _CLOCK_UUID_SET)) {
+ _PERROR_DUP_ATTR("uuid", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_uuid(&entry_node->u.ctf_expression.right, uuid);
+ if (ret) {
+ _PERROR("%s", "invalid clock UUID");
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_uuid(clock, uuid);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's UUID");
+ goto error;
+ }
+
+ _SET(set, _CLOCK_UUID_SET);
+ } else if (!strcmp(left, "description")) {
+ char *right;
+
+ if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
+ _PERROR_DUP_ATTR("description", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ right = concatenate_unary_strings(
+ &entry_node->u.ctf_expression.right);
+ if (!right) {
+ _PERROR("%s", "unexpected unary expression for clock's \"description\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_description(clock, right);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's description");
+ g_free(right);
+ goto error;
+ }
+
+ g_free(right);
+ _SET(set, _CLOCK_DESCRIPTION_SET);
+ } else if (!strcmp(left, "freq")) {
+ uint64_t freq;
+
+ if (_IS_SET(set, _CLOCK_FREQ_SET)) {
+ _PERROR_DUP_ATTR("freq", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(
+ &entry_node->u.ctf_expression.right, &freq);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for clock declaration's \"freq\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_frequency(clock, freq);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's frequency");
+ goto error;
+ }
+
+ _SET(set, _CLOCK_FREQ_SET);
+ } else if (!strcmp(left, "precision")) {
+ uint64_t precision;
+
+ if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
+ _PERROR_DUP_ATTR("precision", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(
+ &entry_node->u.ctf_expression.right, &precision);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for clock declaration's \"precision\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_precision(clock, precision);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's precision");
+ goto error;
+ }
+
+ _SET(set, _CLOCK_PRECISION_SET);
+ } else if (!strcmp(left, "offset_s")) {
+ uint64_t offset_s;
+
+ if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
+ _PERROR_DUP_ATTR("offset_s", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(
+ &entry_node->u.ctf_expression.right, &offset_s);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for clock declaration's \"offset_s\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_offset_s(clock, offset_s);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's offset in seconds");
+ goto error;
+ }
+
+ _SET(set, _CLOCK_OFFSET_S_SET);
+ } else if (!strcmp(left, "offset")) {
+ uint64_t offset;
+
+ if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
+ _PERROR_DUP_ATTR("offset", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = get_unary_unsigned(
+ &entry_node->u.ctf_expression.right, &offset);
+ if (ret) {
+ _PERROR("%s", "unexpected unary expression for clock declaration's \"offset\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_offset(clock, offset);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's offset in cycles");
+ goto error;
+ }
+
+ _SET(set, _CLOCK_OFFSET_SET);
+ } else if (!strcmp(left, "absolute")) {
+ struct ctf_node *right;
+
+ if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
+ _PERROR_DUP_ATTR("absolute", "clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ right = _BT_LIST_FIRST_ENTRY(
+ &entry_node->u.ctf_expression.right,
+ struct ctf_node, siblings);
+ ret = get_boolean(ctx->efd, right);
+ if (ret < 0) {
+ _PERROR("%s", "unexpected unary expression for clock declaration's \"absolute\" attribute");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_clock_set_is_absolute(clock, ret);
+ if (ret) {
+ _PERROR("%s", "cannot set clock's absolute option");
+ goto error;
+ }
+
+ _SET(set, _CLOCK_ABSOLUTE_SET);
+ } else {
+ _PWARNING("unknown attribute \"%s\" in clock declaration",
+ left);
+ }
+
+ g_free(left);
+ left = NULL;
+
+ return 0;
+
+error:
+ g_free(left);
+
+ return ret;
+}
+
+static
+int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
+{
+ int ret = 0;
+ int set = 0;
+ struct bt_ctf_clock *clock;
+ struct ctf_node *entry_node;
+ struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list;
+
+ if (clock_node->visited) {
+ return 0;
+ }
+
+ clock_node->visited = TRUE;
+ clock = bt_ctf_clock_create(NULL);
+ if (!clock) {
+ _PERROR("%s", "cannot create clock");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ bt_list_for_each_entry(entry_node, decl_list, siblings) {
+ ret = visit_clock_decl_entry(ctx, entry_node, clock, &set);
+ if (ret) {
+ goto error;
+ }
+ }
+
+ if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
+ _PERROR("%s",
+ "missing \"name\" attribute in clock declaration");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (bt_ctf_trace_get_clock_count(ctx->trace) != 0) {
+ _PERROR("%s", "only CTF traces with a single clock declaration are supported as of this version");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = bt_ctf_trace_add_clock(ctx->trace, clock);
+ if (ret) {
+ _PERROR("%s", "cannot add clock to trace");
+ goto error;
+ }
+
+error:
+ BT_PUT(clock);
+
+ return ret;
+}
+
+static
+int visit_root_decl(struct ctx *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_typedef(ctx,
+ root_decl_node->u._typedef.type_specifier_list,
+ &root_decl_node->u._typedef.type_declarators);
+ if (ret) {
+ _PERROR("%s", "cannot add typedef in root scope");
+ goto end;
+ }
+ break;
+ case NODE_TYPEALIAS:
+ ret = visit_typealias(ctx, root_decl_node->u.typealias.target,
+ root_decl_node->u.typealias.alias);
+ if (ret) {
+ _PERROR("%s", "cannot add typealias in root scope");
+ goto end;
+ }
+ break;
+ case NODE_TYPE_SPECIFIER_LIST:
+ {
+ _BT_CTF_FIELD_TYPE_INIT(decl);
+
+ /*
+ * Just add the type specifier to the root
+ * declaration scope. Put local reference.
+ */
+ ret = visit_type_specifier_list(ctx, root_decl_node, &decl);
+ if (ret) {
+ assert(!decl);
+ goto end;
+ }
+
+ BT_PUT(decl);
+ break;
+ }
+ default:
+ ret = -EPERM;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static
+int add_stream_classes_to_trace(struct ctx *ctx)
+{
+ int ret;
+ GHashTableIter iter;
+ gpointer key, stream_class;
+
+ g_hash_table_iter_init(&iter, ctx->stream_classes);
+
+ while (g_hash_table_iter_next(&iter, &key, &stream_class)) {
+ ret = bt_ctf_trace_add_stream_class(ctx->trace,
+ stream_class);
+ if (ret) {
+ int64_t id = bt_ctf_stream_class_get_id(stream_class);
+ _PERROR("cannot add stream class %" PRId64 " to trace",
+ id);
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+int ctf_visitor_generate_ir(FILE *efd, struct ctf_node *node,
+ struct bt_ctf_trace **trace)
+{
+ int ret = 0;
+ struct ctx *ctx = NULL;
+ _BT_CTF_FIELD_TYPE_INIT(packet_header_decl);
+
+ printf_verbose("CTF visitor: AST -> CTF IR...\n");
+
+ *trace = bt_ctf_trace_create();
+ if (!*trace) {
+ _FPERROR(efd, "%s", "cannot create trace");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Set packet header to an empty struct tu override the default one */
+ packet_header_decl = bt_ctf_field_type_structure_create();
+
+ if (!packet_header_decl) {
+ _FPERROR(efd,
+ "%s",
+ "cannot create initial, empty packet header structure");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = bt_ctf_trace_set_packet_header_type(*trace, packet_header_decl);
+ BT_PUT(packet_header_decl);
+ if (ret) {
+ _FPERROR(efd,
+ "%s",
+ "cannot set initial, empty packet header structure");
+ goto error;
+ }
+
+ ctx = ctx_create(*trace, efd);
+ if (!ctx) {
+ _FPERROR(efd, "%s", "cannot create visitor context");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ switch (node->type) {
+ case NODE_ROOT:
+ {
+ struct ctf_node *iter;
+ int got_trace_decl = FALSE;
+ int found_callsite = FALSE;
+
+ /*
+ * Find trace declaration's byte order first (for early
+ * type aliases).
+ */
+ bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+ if (got_trace_decl) {
+ _PERROR("%s", "duplicate trace declaration");
+ goto error;
+ }
+
+ ret = set_trace_byte_order(ctx, iter);
+ if (ret) {
+ _PERROR("cannot set trace's byte order (%d)",
+ ret);
+ goto error;
+ }
+
+ got_trace_decl = TRUE;
+ }
+
+ if (!got_trace_decl) {
+ _PERROR("no trace declaration found (%d)", ret);
+ ret = -EPERM;
+ goto error;
+ }
+
+ /*
+ * Visit clocks first since any early integer can be mapped
+ * to one.
+ */
+ bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
+ ret = visit_clock_decl(ctx, iter);
+ if (ret) {
+ _PERROR("error while visiting clock declaration (%d)",
+ ret);
+ goto error;
+ }
+ }
+
+ /*
+ * 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) {
+ _PERROR("error while visiting root declaration (%d)",
+ ret);
+ goto error;
+ }
+ }
+
+ /* Callsite are not supported */
+ bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
+ found_callsite = TRUE;
+ break;
+ }
+
+ if (found_callsite) {
+ _PWARNING("%s", "\"callsite\" blocks are not supported as of this version");
+ }
+
+ /* Environment */
+ bt_list_for_each_entry(iter, &node->u.root.env, siblings) {
+ ret = visit_env(ctx, iter);
+ if (ret) {
+ _PERROR("error while visiting environment block (%d)",
+ ret);
+ goto error;
+ }
+ }
+
+ /* Trace */
+ bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+ ret = visit_trace_decl(ctx, iter);
+ if (ret) {
+ _PERROR("%s", "error while visiting trace declaration");
+ goto error;
+ }
+ }
+
+ /* Streams */
+ bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
+ ret = visit_stream_decl(ctx, iter);
+ if (ret) {
+ _PERROR("%s", "error while visiting stream declaration");
+ goto error;
+ }
+ }
+
+ /* Events */
+ bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
+ ret = visit_event_decl(ctx, iter);
+ if (ret) {
+ _PERROR("%s", "error while visiting event declaration");
+ goto error;
+ }
+ }
+ break;
+ }
+ case NODE_UNKNOWN:
+ default:
+ _PERROR("unknown node type: %d", (int) node->type);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Add stream classes to trace now */
+ ret = add_stream_classes_to_trace(ctx);
+ if (ret) {
+ _PERROR("%s", "cannot add stream classes to trace");
+ }
+
+ ctx_destroy(ctx);
+ printf_verbose("done!\n");
+
+ return ret;
+
+error:
+ BT_PUT(packet_header_decl);
+ ctx_destroy(ctx);
+ BT_PUT(*trace);
+
+ return ret;
+}
--- /dev/null
+/*
+ * ctf-visitor-parent-links.c
+ *
+ * Common Trace Format Metadata Parent Link Creator.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/list.h>
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+
+#define fprintf_dbg(fd, fmt, args...) fprintf(fd, "%s: " fmt, __func__, ## args)
+
+static
+int ctf_visitor_unary_expression(FILE *fd, int depth, struct ctf_node *node)
+{
+ int ret = 0;
+
+ switch (node->u.unary_expression.link) {
+ case UNARY_LINK_UNKNOWN:
+ case UNARY_DOTLINK:
+ case UNARY_ARROWLINK:
+ case UNARY_DOTDOTDOT:
+ break;
+ default:
+ fprintf(fd, "[error] %s: unknown expression link type %d\n", __func__,
+ (int) 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(fd, depth + 1,
+ node->u.unary_expression.u.sbrac_exp);
+ if (ret)
+ return ret;
+ break;
+
+ case UNARY_UNKNOWN:
+ default:
+ fprintf(fd, "[error] %s: unknown expression type %d\n", __func__,
+ (int) node->u.unary_expression.type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+int ctf_visitor_type_specifier(FILE *fd, int depth, struct ctf_node *node)
+{
+ int ret;
+
+ switch (node->u.type_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.type_specifier.node->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, node->u.type_specifier.node);
+ if (ret)
+ return ret;
+ break;
+
+ case TYPESPEC_UNKNOWN:
+ default:
+ fprintf(fd, "[error] %s: unknown type specifier %d\n", __func__,
+ (int) node->u.type_specifier.type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+int ctf_visitor_type_declarator(FILE *fd, int depth, struct ctf_node *node)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+
+ depth++;
+
+ bt_list_for_each_entry(iter, &node->u.type_declarator.pointers,
+ siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+
+ switch (node->u.type_declarator.type) {
+ case TYPEDEC_ID:
+ break;
+ case TYPEDEC_NESTED:
+ if (node->u.type_declarator.u.nested.type_declarator) {
+ node->u.type_declarator.u.nested.type_declarator->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1,
+ node->u.type_declarator.u.nested.type_declarator);
+ if (ret)
+ return ret;
+ }
+ if (!node->u.type_declarator.u.nested.abstract_array) {
+ bt_list_for_each_entry(iter, &node->u.type_declarator.u.nested.length,
+ siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ }
+ if (node->u.type_declarator.bitfield_len) {
+ node->u.type_declarator.bitfield_len = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1,
+ node->u.type_declarator.bitfield_len);
+ if (ret)
+ return ret;
+ }
+ break;
+ case TYPEDEC_UNKNOWN:
+ default:
+ fprintf(fd, "[error] %s: unknown type declarator %d\n", __func__,
+ (int) node->u.type_declarator.type);
+ return -EINVAL;
+ }
+ depth--;
+ return 0;
+}
+
+int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node)
+{
+ 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(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ depth--;
+ break;
+ case NODE_UNARY_EXPRESSION:
+ return ctf_visitor_unary_expression(fd, depth, node);
+
+ case NODE_TYPEDEF:
+ depth++;
+ node->u._typedef.type_specifier_list->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, node->u._typedef.type_specifier_list);
+ if (ret)
+ return ret;
+ bt_list_for_each_entry(iter, &node->u._typedef.type_declarators, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ depth--;
+ break;
+ case NODE_TYPEALIAS_TARGET:
+ depth++;
+ node->u.typealias_target.type_specifier_list->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias_target.type_specifier_list);
+ if (ret)
+ return ret;
+ bt_list_for_each_entry(iter, &node->u.typealias_target.type_declarators, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ depth--;
+ break;
+ case NODE_TYPEALIAS_ALIAS:
+ depth++;
+ node->u.typealias_alias.type_specifier_list->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias_alias.type_specifier_list);
+ if (ret)
+ return ret;
+ bt_list_for_each_entry(iter, &node->u.typealias_alias.type_declarators, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ depth--;
+ break;
+ case NODE_TYPEALIAS:
+ node->u.typealias.target->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias.target);
+ if (ret)
+ return ret;
+ node->u.typealias.alias->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias.alias);
+ if (ret)
+ return ret;
+ break;
+
+ case NODE_TYPE_SPECIFIER_LIST:
+ bt_list_for_each_entry(iter, &node->u.type_specifier_list.head, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case NODE_TYPE_SPECIFIER:
+ ret = ctf_visitor_type_specifier(fd, depth, node);
+ if (ret)
+ return ret;
+ break;
+ case NODE_POINTER:
+ break;
+ case NODE_TYPE_DECLARATOR:
+ ret = ctf_visitor_type_declarator(fd, depth, node);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ break;
+ case NODE_ENUM:
+ depth++;
+ if (node->u._enum.container_type) {
+ ret = ctf_visitor_parent_links(fd, depth + 1, node->u._enum.container_type);
+ if (ret)
+ return ret;
+ }
+
+ bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ depth--;
+ break;
+ case NODE_STRUCT_OR_VARIANT_DECLARATION:
+ node->u.struct_or_variant_declaration.type_specifier_list->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1,
+ node->u.struct_or_variant_declaration.type_specifier_list);
+ if (ret)
+ return ret;
+ bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.type_declarators, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u._struct.min_align,
+ siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case NODE_UNKNOWN:
+ default:
+ fprintf(fd, "[error] %s: unknown node type %d\n", __func__,
+ (int) node->type);
+ return -EINVAL;
+ }
+ return ret;
+}
--- /dev/null
+/*
+ * ctf-visitor-semantic-validator.c
+ *
+ * Common Trace Format Metadata Semantic Validator.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/list.h>
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+
+#define _bt_list_first_entry(ptr, type, member) \
+ bt_list_entry((ptr)->next, type, member)
+
+#define fprintf_dbg(fd, fmt, args...) fprintf(fd, "%s: " fmt, __func__, ## args)
+
+static
+int _ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node);
+
+static
+int ctf_visitor_unary_expression(FILE *fd, int depth, struct ctf_node *node)
+{
+ 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) {
+ fprintf(fd, "[error]: semantic error (left child of a ctf expression is only allowed to be a string)\n");
+
+ 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:
+ fprintf(fd, "[error]: semantic error (children of type declarator and enum can only be unsigned numeric constants or references to fields (a.b.c))\n");
+ 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:
+ fprintf(fd, "[error]: semantic error (structure alignment attribute can only be unsigned numeric constants)\n");
+ 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.
+ */
+ fprintf(fd, "[error]: semantic error (nested unary expressions not allowed ( () and [] ))\n");
+ 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) {
+ fprintf(fd, "[error]: semantic error (empty link not allowed except on first node of unary expression (need to separate nodes with \".\" or \"->\")\n");
+ 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) {
+ fprintf(fd, "[error]: semantic error (links \".\" and \"->\" are only allowed as children of ctf expression)\n");
+ goto errperm;
+ }
+ /*
+ * Only strings can be separated linked by . or ->.
+ * This includes "", '' and non-quoted identifiers.
+ */
+ if (node->u.unary_expression.type != UNARY_STRING) {
+ fprintf(fd, "[error]: semantic error (links \".\" and \"->\" are only allowed to separate strings and identifiers)\n");
+ 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) {
+ fprintf(fd, "[error]: semantic error (links \".\" and \"->\" are not allowed before first node of the unary expression list)\n");
+ goto errperm;
+ }
+ break;
+ case UNARY_DOTDOTDOT:
+ /* We only allow ... link between children of enumerator. */
+ if (node->parent->type != NODE_ENUMERATOR) {
+ fprintf(fd, "[error]: semantic error (link \"...\" is only allowed within enumerator)\n");
+ 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) {
+ fprintf(fd, "[error]: semantic error (link \"...\" is not allowed on the first node of the unary expression list)\n");
+ goto errperm;
+ }
+ break;
+ default:
+ fprintf(fd, "[error] %s: unknown expression link type %d\n", __func__,
+ (int) node->u.unary_expression.link);
+ return -EINVAL;
+ }
+ return 0;
+
+errinval:
+ fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EINVAL; /* Incoherent structure */
+
+errperm:
+ fprintf(fd, "[error] %s: semantic error (parent type %s for node type %s)\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EPERM; /* Structure not allowed */
+}
+
+static
+int ctf_visitor_type_specifier_list(FILE *fd, int depth, struct ctf_node *node)
+{
+ 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:
+ fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EINVAL; /* Incoherent structure */
+}
+
+static
+int ctf_visitor_type_specifier(FILE *fd, int depth, struct ctf_node *node)
+{
+ 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:
+ fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EINVAL; /* Incoherent structure */
+}
+
+static
+int ctf_visitor_type_declarator(FILE *fd, int depth, struct ctf_node *node)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+
+ depth++;
+
+ switch (node->parent->type) {
+ case NODE_TYPE_DECLARATOR:
+ /*
+ * A nested type declarator is not allowed to contain pointers.
+ */
+ if (!bt_list_empty(&node->u.type_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 typealias).
+ * NOT accepting alias with identifier. The declarator should
+ * be either empty or contain pointer(s).
+ */
+ if (node->u.type_declarator.type == TYPEDEC_NESTED)
+ goto errperm;
+ bt_list_for_each_entry(iter, &node->parent->u.typealias_alias.type_specifier_list->u.type_specifier_list.head,
+ siblings) {
+ switch (iter->u.type_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.type_declarator.pointers))
+ goto errperm;
+ break;
+ default:
+ break;
+ }
+ }
+ if (node->u.type_declarator.type == TYPEDEC_ID &&
+ node->u.type_declarator.u.id != NULL)
+ 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.type_declarator.pointers,
+ siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+
+ switch (node->u.type_declarator.type) {
+ case TYPEDEC_ID:
+ break;
+ case TYPEDEC_NESTED:
+ {
+ if (node->u.type_declarator.u.nested.type_declarator) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1,
+ node->u.type_declarator.u.nested.type_declarator);
+ if (ret)
+ return ret;
+ }
+ if (!node->u.type_declarator.u.nested.abstract_array) {
+ bt_list_for_each_entry(iter, &node->u.type_declarator.u.nested.length,
+ siblings) {
+ if (iter->type != NODE_UNARY_EXPRESSION) {
+ fprintf(fd, "[error] %s: expecting unary expression as length\n", __func__);
+ return -EINVAL;
+ }
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ } else {
+ if (node->parent->type == NODE_TYPEALIAS_TARGET) {
+ fprintf(fd, "[error] %s: abstract array declarator not permitted as target of typealias\n", __func__);
+ return -EINVAL;
+ }
+ }
+ if (node->u.type_declarator.bitfield_len) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1,
+ node->u.type_declarator.bitfield_len);
+ if (ret)
+ return ret;
+ }
+ break;
+ }
+ case TYPEDEC_UNKNOWN:
+ default:
+ fprintf(fd, "[error] %s: unknown type declarator %d\n", __func__,
+ (int) node->u.type_declarator.type);
+ return -EINVAL;
+ }
+ depth--;
+ return 0;
+
+errinval:
+ fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EINVAL; /* Incoherent structure */
+
+errperm:
+ fprintf(fd, "[error] %s: semantic error (parent type %s for node type %s)\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EPERM; /* Structure not allowed */
+}
+
+static
+int _ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node)
+{
+ 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(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ depth--;
+ break;
+ case NODE_UNARY_EXPRESSION:
+ return ctf_visitor_unary_expression(fd, depth, node);
+
+ 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(fd, depth + 1,
+ node->u._typedef.type_specifier_list);
+ if (ret)
+ return ret;
+ bt_list_for_each_entry(iter, &node->u._typedef.type_declarators, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ 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(fd, depth + 1,
+ node->u.typealias_target.type_specifier_list);
+ if (ret)
+ return ret;
+ nr_declarators = 0;
+ bt_list_for_each_entry(iter, &node->u.typealias_target.type_declarators, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ nr_declarators++;
+ }
+ if (nr_declarators > 1) {
+ fprintf(fd, "[error] %s: Too many declarators in typealias alias (%d, max is 1)\n", __func__, 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(fd, depth + 1,
+ node->u.typealias_alias.type_specifier_list);
+ if (ret)
+ return ret;
+ nr_declarators = 0;
+ bt_list_for_each_entry(iter, &node->u.typealias_alias.type_declarators, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ nr_declarators++;
+ }
+ if (nr_declarators > 1) {
+ fprintf(fd, "[error] %s: Too many declarators in typealias alias (%d, max is 1)\n", __func__, 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(fd, depth + 1, node->u.typealias.target);
+ if (ret)
+ return ret;
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, node->u.typealias.alias);
+ if (ret)
+ return ret;
+ break;
+
+ case NODE_TYPE_SPECIFIER_LIST:
+ ret = ctf_visitor_type_specifier_list(fd, depth, node);
+ if (ret)
+ return ret;
+ break;
+ case NODE_TYPE_SPECIFIER:
+ ret = ctf_visitor_type_specifier(fd, depth, node);
+ 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_type_declarator(fd, depth, node);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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) {
+ fprintf(fd, "[error]: semantic error (first unary expression of enumerator is unexpected)\n");
+ 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) {
+ fprintf(fd, "[error]: semantic error (second unary expression of enumerator is unexpected)\n");
+ goto errperm;
+ }
+ break;
+ default:
+ goto errperm;
+ }
+ }
+ }
+
+ bt_list_for_each_entry(iter, &node->u.enumerator.values, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ 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(fd, depth + 1, node->u._enum.container_type);
+ if (ret)
+ return ret;
+
+ bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ 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(fd, depth + 1,
+ node->u.struct_or_variant_declaration.type_specifier_list);
+ if (ret)
+ return ret;
+ bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.type_declarators, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ 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(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case NODE_UNKNOWN:
+ default:
+ fprintf(fd, "[error] %s: unknown node type %d\n", __func__,
+ (int) node->type);
+ return -EINVAL;
+ }
+ return ret;
+
+errinval:
+ fprintf(fd, "[error] %s: incoherent parent type %s for node type %s\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EINVAL; /* Incoherent structure */
+
+errperm:
+ fprintf(fd, "[error] %s: semantic error (parent type %s for node type %s)\n", __func__,
+ node_type(node->parent), node_type(node));
+ return -EPERM; /* Structure not allowed */
+}
+
+int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node)
+{
+ 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.
+ */
+ printf_verbose("CTF visitor: parent links creation... ");
+ ret = ctf_visitor_parent_links(fd, depth, node);
+ if (ret)
+ return ret;
+ printf_verbose("done.\n");
+ printf_verbose("CTF visitor: semantic check... ");
+ ret = _ctf_visitor_semantic_check(fd, depth, node);
+ if (ret)
+ return ret;
+ printf_verbose("done.\n");
+ return ret;
+}
--- /dev/null
+AM_CFLAGS = $(PACKAGE_CFLAGS)
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libctf-notif-iter.la
+
+libctf_notif_iter_la_SOURCES = notif-iter.c
--- /dev/null
+/*
+ * Babeltrace - CTF notification iterator
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <string.h>
+#include <babeltrace/ctf-ir/field-types.h>
+#include <babeltrace/ctf-ir/field-path.h>
+#include <babeltrace/ctf-ir/fields.h>
+#include <babeltrace/ctf-ir/stream-class.h>
+#include <babeltrace/ctf-ir/packet.h>
+#include <babeltrace/ctf-ir/stream.h>
+#include <babeltrace/ctf-ir/clock.h>
+#include <babeltrace/ctf-ir/event-class.h>
+#include <babeltrace/ref.h>
+#include <glib.h>
+
+#define PRINT_ERR_STREAM notit->err_stream
+#define PRINT_PREFIX "ctf-notif-iter"
+#include "print.h"
+
+#include "notif-iter.h"
+#include "../btr/btr.h"
+
+#define BYTES_TO_BITS(x) ((x) * 8)
+
+struct bt_ctf_notif_iter;
+
+/* A visit stack entry */
+struct stack_entry {
+ /*
+ * Current base field, one of:
+ *
+ * * string
+ * * structure
+ * * array
+ * * sequence
+ * * variant
+ *
+ * Field is owned by this.
+ */
+ struct bt_ctf_field *base;
+
+ /* index of next field to set */
+ size_t index;
+};
+
+/* Visit stack */
+struct stack {
+ /* Entries (struct stack_entry *) (top is last element) */
+ GPtrArray *entries;
+
+ /* Link to owner */
+ struct bt_ctf_notif_iter *notit;
+};
+
+/* State */
+enum state {
+ STATE_INIT,
+ 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_NOTIF_NEW_PACKET,
+ STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN,
+ STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
+ STATE_AFTER_STREAM_EVENT_HEADER,
+ STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN,
+ STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
+ STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
+ STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
+ STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
+ STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
+ STATE_EMIT_NOTIF_EVENT,
+ STATE_EMIT_NOTIF_END_OF_PACKET,
+ STATE_SKIP_PACKET_PADDING,
+};
+
+/* CTF notification iterator */
+struct bt_ctf_notif_iter {
+ /* Visit stack */
+ struct stack *stack;
+
+ /* Error stream (may be NULL) */
+ FILE *err_stream;
+
+ /*
+ * Current dynamic scope field pointer.
+ *
+ * This is set when a dynamic scope field is first created by
+ * btr_compound_begin_cb(). It points to one of the fields in
+ * dscopes below.
+ */
+ struct bt_ctf_field **cur_dscope_field;
+
+ /* Trace and classes (owned by this) */
+ struct {
+ struct bt_ctf_trace *trace;
+ struct bt_ctf_stream_class *stream_class;
+ struct bt_ctf_event_class *event_class;
+ } meta;
+
+ /* Current packet (NULL if not created yet) */
+ struct bt_ctf_packet *packet;
+
+ /* Database of current dynamic scopes (owned by this) */
+ struct {
+ struct bt_ctf_field *trace_packet_header;
+ struct bt_ctf_field *stream_packet_context;
+ struct bt_ctf_field *stream_event_header;
+ struct bt_ctf_field *stream_event_context;
+ struct bt_ctf_field *event_context;
+ struct bt_ctf_field *event_payload;
+ } dscopes;
+
+ /* Current state */
+ enum state state;
+
+ /* User buffer stuff */
+ 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;
+ } buf;
+
+ /* Binary type reader */
+ struct bt_ctf_btr *btr;
+
+ /* Medium stuff */
+ struct {
+ struct bt_ctf_notif_iter_medium_ops medops;
+ size_t max_request_sz;
+ void *data;
+ } medium;
+
+ /* Current packet size (bits) (-1 if unknown) */
+ size_t cur_packet_size;
+
+ /* Current content size (bits) (-1 if unknown) */
+ size_t cur_content_size;
+};
+
+static
+void stack_entry_free_func(gpointer data)
+{
+ struct stack_entry *entry = data;
+
+ bt_put(entry->base);
+ g_free(entry);
+}
+
+static
+struct stack *stack_new(struct bt_ctf_notif_iter *notit)
+{
+ struct stack *stack = NULL;
+
+ stack = g_new0(struct stack, 1);
+ if (!stack) {
+ goto error;
+ }
+
+ stack->entries = g_ptr_array_new_with_free_func(stack_entry_free_func);
+ if (!stack->entries) {
+ goto error;
+ }
+
+ stack->notit = notit;
+
+ return stack;
+
+error:
+ g_free(stack);
+
+ return NULL;
+}
+
+static
+void stack_destroy(struct stack *stack)
+{
+ assert(stack);
+ g_ptr_array_free(stack->entries, TRUE);
+ g_free(stack);
+}
+
+static
+int stack_push(struct stack *stack, struct bt_ctf_field *base)
+{
+ int ret = 0;
+ struct stack_entry *entry;
+ struct bt_ctf_notif_iter *notit;
+
+ assert(stack);
+ assert(base);
+ notit = stack->notit;
+ entry = g_new0(struct stack_entry, 1);
+ if (!entry) {
+ PERR("Cannot create new stack entry\n");
+ ret = -1;
+ goto end;
+ }
+
+ entry->base = bt_get(base);
+ g_ptr_array_add(stack->entries, entry);
+
+end:
+ return ret;
+}
+
+static inline
+unsigned int stack_size(struct stack *stack)
+{
+ assert(stack);
+
+ return stack->entries->len;
+}
+
+static
+void stack_pop(struct stack *stack)
+{
+ assert(stack);
+ assert(stack_size(stack));
+ g_ptr_array_remove_index(stack->entries, stack->entries->len - 1);
+}
+
+static inline
+struct stack_entry *stack_top(struct stack *stack)
+{
+ assert(stack);
+ assert(stack_size(stack));
+
+ return g_ptr_array_index(stack->entries, stack->entries->len - 1);
+}
+
+static inline
+bool stack_empty(struct stack *stack)
+{
+ return stack_size(stack) == 0;
+}
+
+static
+void stack_clear(struct stack *stack)
+{
+ assert(stack);
+
+ if (!stack_empty(stack)) {
+ g_ptr_array_remove_range(stack->entries, 0, stack_size(stack));
+ }
+
+ assert(stack_empty(stack));
+}
+
+static inline
+enum bt_ctf_notif_iter_status notif_iter_status_from_m_status(
+ enum bt_ctf_notif_iter_medium_status m_status)
+{
+ return m_status;
+}
+
+static inline
+size_t buf_size_bits(struct bt_ctf_notif_iter *notit)
+{
+ return BYTES_TO_BITS(notit->buf.sz);
+}
+
+static inline
+size_t buf_available_bits(struct bt_ctf_notif_iter *notit)
+{
+ return buf_size_bits(notit) - notit->buf.at;
+}
+
+static inline
+size_t packet_at(struct bt_ctf_notif_iter *notit)
+{
+ return notit->buf.packet_offset + notit->buf.at;
+}
+
+static inline
+size_t remaining_content_bits(struct bt_ctf_notif_iter *notit)
+{
+ if (notit->cur_content_size == -1) {
+ return -1;
+ }
+
+ return notit->cur_content_size - packet_at(notit);
+}
+
+static inline
+size_t remaining_packet_bits(struct bt_ctf_notif_iter *notit)
+{
+ if (notit->cur_packet_size == -1) {
+ return -1;
+ }
+
+ return notit->cur_packet_size - packet_at(notit);
+}
+
+static inline
+void buf_consume_bits(struct bt_ctf_notif_iter *notit, size_t incr)
+{
+ notit->buf.at += incr;
+}
+
+static inline
+bool buf_has_enough_bits(struct bt_ctf_notif_iter *notit, size_t sz)
+{
+ return buf_available_bits(notit) >= sz;
+}
+
+static
+enum bt_ctf_notif_iter_status request_medium_bytes(struct bt_ctf_notif_iter *notit)
+{
+ uint8_t *buffer_addr;
+ size_t buffer_sz;
+ enum bt_ctf_notif_iter_medium_status m_status;
+
+ m_status = notit->medium.medops.request_bytes(
+ notit->medium.max_request_sz, &buffer_addr,
+ &buffer_sz, notit->medium.data);
+ if (m_status == BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK) {
+ assert(buffer_sz != 0);
+
+ /* New packet offset is old one + old size (in bits) */
+ notit->buf.packet_offset += buf_size_bits(notit);
+
+ /* Restart at the beginning of the new medium buffer */
+ notit->buf.at = 0;
+
+ /* New medium buffer size */
+ notit->buf.sz = buffer_sz;
+
+ /* New medium buffer address */
+ notit->buf.addr = buffer_addr;
+ }
+
+ return notif_iter_status_from_m_status(m_status);
+}
+
+static inline
+enum bt_ctf_notif_iter_status buf_ensure_available_bits(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+
+ if (buf_available_bits(notit) == 0) {
+ /*
+ * This _cannot_ return BT_CTF_NOTIF_ITER_STATUS_OK
+ * _and_ no bits.
+ */
+ status = request_medium_bytes(notit);
+ }
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_dscope_begin_state(
+ struct bt_ctf_notif_iter *notit,
+ struct bt_ctf_field_type *dscope_field_type,
+ enum state done_state, enum state continue_state,
+ struct bt_ctf_field **dscope_field)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ enum bt_ctf_btr_status btr_status;
+ size_t consumed_bits;
+
+ status = buf_ensure_available_bits(notit);
+ if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
+ goto end;
+ }
+
+ bt_put(*dscope_field);
+ notit->cur_dscope_field = dscope_field;
+ consumed_bits = bt_ctf_btr_start(notit->btr, dscope_field_type,
+ notit->buf.addr, notit->buf.at, packet_at(notit),
+ notit->buf.sz, &btr_status);
+
+ switch (btr_status) {
+ case BT_CTF_BTR_STATUS_OK:
+ /* type was read completely */
+ notit->state = done_state;
+ break;
+ case BT_CTF_BTR_STATUS_EOF:
+ notit->state = continue_state;
+ break;
+ default:
+ PERR("Binary type reader failed to start\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ /* Consume bits now since we know we're not in an error state */
+ buf_consume_bits(notit, consumed_bits);
+
+end:
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_dscope_continue_state(
+ struct bt_ctf_notif_iter *notit, enum state done_state)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ enum bt_ctf_btr_status btr_status;
+ size_t consumed_bits;
+
+ status = buf_ensure_available_bits(notit);
+ if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
+ goto end;
+ }
+
+ consumed_bits = bt_ctf_btr_continue(notit->btr, notit->buf.addr,
+ notit->buf.sz, &btr_status);
+
+ switch (btr_status) {
+ case BT_CTF_BTR_STATUS_OK:
+ /* Type was read completely */
+ notit->state = done_state;
+ break;
+ case BT_CTF_BTR_STATUS_EOF:
+ /* Stay in this continue state */
+ break;
+ default:
+ PERR("Binary type reader failed to continue\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ /* Consume bits now since we know we're not in an error state */
+ buf_consume_bits(notit, consumed_bits);
+
+end:
+ return status;
+}
+
+static
+void put_event_dscopes(struct bt_ctf_notif_iter *notit)
+{
+ BT_PUT(notit->dscopes.stream_event_header);
+ BT_PUT(notit->dscopes.stream_event_context);
+ BT_PUT(notit->dscopes.event_context);
+ BT_PUT(notit->dscopes.event_payload);
+}
+
+static
+void put_all_dscopes(struct bt_ctf_notif_iter *notit)
+{
+ BT_PUT(notit->dscopes.trace_packet_header);
+ BT_PUT(notit->dscopes.stream_packet_context);
+ put_event_dscopes(notit);
+}
+
+static
+enum bt_ctf_notif_iter_status read_packet_header_begin_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *packet_header_type;
+
+ /* Reset all dynamic scopes since we're reading a new packet */
+ put_all_dscopes(notit);
+ BT_PUT(notit->packet);
+ BT_PUT(notit->meta.stream_class);
+ BT_PUT(notit->meta.event_class);
+
+ /* Packet header type is common to the whole trace */
+ packet_header_type = bt_ctf_trace_get_packet_header_type(
+ notit->meta.trace);
+ if (!packet_header_type) {
+ PERR("Failed to retrieve trace's packet header type\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ status = read_dscope_begin_state(notit, packet_header_type,
+ STATE_AFTER_TRACE_PACKET_HEADER,
+ STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
+ ¬it->dscopes.trace_packet_header);
+
+end:
+ BT_PUT(packet_header_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_packet_header_continue_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ return read_dscope_continue_state(notit,
+ STATE_AFTER_TRACE_PACKET_HEADER);
+}
+
+static inline
+bool is_struct_type(struct bt_ctf_field_type *field_type)
+{
+ return bt_ctf_field_type_get_type_id(field_type) == BT_CTF_TYPE_ID_STRUCT;
+}
+
+static inline
+bool is_variant_type(struct bt_ctf_field_type *field_type)
+{
+ return bt_ctf_field_type_get_type_id(field_type) == BT_CTF_TYPE_ID_VARIANT;
+}
+
+static inline
+enum bt_ctf_notif_iter_status set_current_stream_class(struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *packet_header_type;
+ struct bt_ctf_field_type *stream_id_field_type = NULL;
+ uint64_t stream_id;
+
+ /* Is there any "stream_id" field in the packet header? */
+ packet_header_type = bt_ctf_trace_get_packet_header_type(
+ notit->meta.trace);
+ if (!packet_header_type) {
+ PERR("Failed to retrieve trace's packet header type\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ assert(is_struct_type(packet_header_type));
+
+ // TODO: optimalize!
+ stream_id_field_type =
+ bt_ctf_field_type_structure_get_field_type_by_name(
+ packet_header_type, "stream_id");
+ if (stream_id_field_type) {
+ /* Find appropriate stream class using current stream ID */
+ struct bt_ctf_field *stream_id_field = NULL;
+ int ret;
+
+ assert(notit->dscopes.trace_packet_header);
+
+ // TODO: optimalize!
+ stream_id_field = bt_ctf_field_structure_get_field(
+ notit->dscopes.trace_packet_header, "stream_id");
+ assert(stream_id_field);
+ ret = bt_ctf_field_unsigned_integer_get_value(
+ stream_id_field, &stream_id);
+ assert(!ret);
+ BT_PUT(stream_id_field);
+ } else {
+ /* Only one stream: pick the first stream class */
+ assert(bt_ctf_trace_get_stream_class_count(
+ notit->meta.trace) == 1);
+ stream_id = 0;
+ }
+
+ BT_PUT(notit->meta.stream_class);
+
+ // TODO: get by ID
+ notit->meta.stream_class = bt_ctf_trace_get_stream_class(
+ notit->meta.trace, stream_id);
+ if (!notit->meta.stream_class) {
+ PERR("Cannot find stream class with ID %" PRIu64 "\n",
+ stream_id);
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+end:
+ BT_PUT(packet_header_type);
+ BT_PUT(stream_id_field_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status after_packet_header_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status;
+
+ status = set_current_stream_class(notit);
+ if (status == BT_CTF_NOTIF_ITER_STATUS_OK) {
+ notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
+ }
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_packet_context_begin_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *packet_context_type;
+
+ assert(notit->meta.stream_class);
+ packet_context_type = bt_ctf_stream_class_get_packet_context_type(
+ notit->meta.stream_class);
+ if (!packet_context_type) {
+ PERR("Failed to retrieve stream class's packet context\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ status = read_dscope_begin_state(notit, packet_context_type,
+ STATE_AFTER_STREAM_PACKET_CONTEXT,
+ STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
+ ¬it->dscopes.stream_packet_context);
+
+end:
+ BT_PUT(packet_context_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_packet_context_continue_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ return read_dscope_continue_state(notit,
+ STATE_AFTER_STREAM_PACKET_CONTEXT);
+}
+
+static inline
+enum bt_ctf_notif_iter_status set_current_packet_content_sizes(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field *packet_size_field = NULL;
+ struct bt_ctf_field *content_size_field = NULL;
+ uint64_t content_size = -1, packet_size = -1;
+
+ assert(notit->dscopes.stream_packet_context);
+
+ // TODO: optimalize!
+ packet_size_field = bt_ctf_field_structure_get_field(
+ notit->dscopes.stream_packet_context, "packet_size");
+ content_size_field = bt_ctf_field_structure_get_field(
+ notit->dscopes.stream_packet_context, "content_size");
+ if (packet_size_field) {
+ int ret = bt_ctf_field_unsigned_integer_get_value(
+ packet_size_field, &packet_size);
+ assert(!ret);
+
+ if (packet_size == 0) {
+ PERR("Decoded packet size is 0\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ } else if ((packet_size % 8) != 0) {
+ PERR("Decoded packet size is not a multiple of 8\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+ }
+ if (content_size_field) {
+ int ret = bt_ctf_field_unsigned_integer_get_value(
+ content_size_field, &content_size);
+ assert(!ret);
+ } else {
+ content_size = packet_size;
+ }
+
+ notit->cur_packet_size = packet_size;
+ notit->cur_content_size = content_size;
+
+end:
+ BT_PUT(packet_size_field);
+ BT_PUT(content_size_field);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status after_packet_context_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status;
+
+ status = set_current_packet_content_sizes(notit);
+ if (status == BT_CTF_NOTIF_ITER_STATUS_OK) {
+ notit->state = STATE_EMIT_NOTIF_NEW_PACKET;
+ }
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_event_header_begin_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *event_header_type = NULL;
+
+ /* Check if we have some content left */
+ if (notit->cur_content_size >= 0) {
+ if (packet_at(notit) == notit->cur_content_size) {
+ /* No more events! */
+ notit->state = STATE_EMIT_NOTIF_END_OF_PACKET;
+ goto end;
+ } else if (packet_at(notit) > notit->cur_content_size) {
+ /* That's not supposed to happen */
+ PERR("Cursor passed packet's content size:\n");
+ PERR(" Decoded content size: %zu\n",
+ notit->cur_content_size);
+ PERR(" Cursor position: %zu\n", packet_at(notit));
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+ }
+
+ event_header_type = bt_ctf_stream_class_get_event_header_type(
+ notit->meta.stream_class);
+ if (!event_header_type) {
+ PERR("Failed to retrieve stream class's event header type\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ put_event_dscopes(notit);
+ status = read_dscope_begin_state(notit, event_header_type,
+ STATE_AFTER_STREAM_EVENT_HEADER,
+ STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
+ ¬it->dscopes.stream_event_header);
+
+end:
+ BT_PUT(event_header_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_event_header_continue_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ return read_dscope_continue_state(notit,
+ STATE_AFTER_STREAM_EVENT_HEADER);
+}
+
+static inline
+enum bt_ctf_notif_iter_status set_current_event_class(struct bt_ctf_notif_iter *notit)
+{
+ /*
+ * The assert() calls in this function are okay because it is
+ * assumed here that all the metadata objects have been
+ * validated for CTF correctness before decoding actual streams.
+ */
+
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *event_header_type;
+ struct bt_ctf_field_type *id_field_type = NULL;
+ struct bt_ctf_field_type *v_field_type = NULL;
+ uint64_t event_id = -1ULL;
+ int ret;
+
+ event_header_type = bt_ctf_stream_class_get_event_header_type(
+ notit->meta.stream_class);
+ if (!event_header_type) {
+ PERR("Failed to retrieve stream class's event header type\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ /* Is there any "id"/"v" field in the event header? */
+ assert(is_struct_type(event_header_type));
+ id_field_type = bt_ctf_field_type_structure_get_field_type_by_name(
+ event_header_type, "id");
+ v_field_type = bt_ctf_field_type_structure_get_field_type_by_name(
+ event_header_type, "v");
+ assert(notit->dscopes.stream_event_header);
+ if (v_field_type) {
+ /*
+ * _ _____ _____
+ * | | |_ _|_ _| __ __ _
+ * | | | | | || '_ \ / _` |
+ * | |___| | | || | | | (_| | S P E C I A L
+ * |_____|_| |_||_| |_|\__, | C A S E ™
+ * |___/
+ */
+ struct bt_ctf_field *v_field = NULL;
+ struct bt_ctf_field *v_struct_field = NULL;
+ struct bt_ctf_field *v_struct_id_field = NULL;
+
+ // TODO: optimalize!
+ v_field = bt_ctf_field_structure_get_field(
+ notit->dscopes.stream_event_header, "v");
+ assert(v_field);
+
+ v_struct_field =
+ bt_ctf_field_variant_get_current_field(v_field);
+ if (!v_struct_field) {
+ goto end_v_field_type;
+ }
+
+ // TODO: optimalize!
+ v_struct_id_field =
+ bt_ctf_field_structure_get_field(v_struct_field, "id");
+ if (!v_struct_id_field) {
+ goto end_v_field_type;
+ }
+
+ ret = bt_ctf_field_unsigned_integer_get_value(
+ v_struct_id_field, &event_id);
+ if (ret) {
+ event_id = -1ULL;
+ }
+
+end_v_field_type:
+ BT_PUT(v_field);
+ BT_PUT(v_struct_field);
+ BT_PUT(v_struct_id_field);
+ }
+
+ if (id_field_type && event_id == -1ULL) {
+ /* Check "id" field */
+ struct bt_ctf_field *id_field = NULL;
+ int ret;
+
+ // TODO: optimalize!
+ id_field = bt_ctf_field_structure_get_field(
+ notit->dscopes.stream_event_header, "id");
+ assert(id_field);
+ assert(bt_ctf_field_is_integer(id_field) ||
+ bt_ctf_field_is_enumeration(id_field));
+
+ if (bt_ctf_field_is_integer(id_field)) {
+ ret = bt_ctf_field_unsigned_integer_get_value(
+ id_field, &event_id);
+ } else {
+ struct bt_ctf_field *container;
+
+ container = bt_ctf_field_enumeration_get_container(
+ id_field);
+ assert(container);
+ ret = bt_ctf_field_unsigned_integer_get_value(
+ container, &event_id);
+ BT_PUT(container);
+ }
+ assert(!ret);
+ BT_PUT(id_field);
+ }
+
+ if (event_id == -1ULL) {
+ /* Event ID not found: single event? */
+ assert(bt_ctf_stream_class_get_event_class_count(
+ notit->meta.stream_class) == 1);
+ event_id = 0;
+ }
+
+ BT_PUT(notit->meta.event_class);
+ notit->meta.event_class = bt_ctf_stream_class_get_event_class_by_id(
+ notit->meta.stream_class, event_id);
+ if (!notit->meta.event_class) {
+ PERR("Cannot find event class with ID %" PRIu64 "\n", event_id);
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+end:
+ BT_PUT(event_header_type);
+ BT_PUT(id_field_type);
+ BT_PUT(v_field_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status after_event_header_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status;
+
+ status = set_current_packet_content_sizes(notit);
+ if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
+ PERR("Failed to set current packet and content sizes\n");
+ goto end;
+ }
+
+ status = set_current_event_class(notit);
+ if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
+ PERR("Failed to set current event class\n");
+ goto end;
+ }
+
+ notit->state = STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN;
+
+end:
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_stream_event_context_begin_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *stream_event_context_type;
+
+ stream_event_context_type = bt_ctf_stream_class_get_event_context_type(
+ notit->meta.stream_class);
+ if (!stream_event_context_type) {
+ PERR("Failed to retrieve stream class's event context type\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ status = read_dscope_begin_state(notit, stream_event_context_type,
+ STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
+ STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
+ ¬it->dscopes.stream_event_context);
+
+end:
+ BT_PUT(stream_event_context_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_stream_event_context_continue_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ return read_dscope_continue_state(notit,
+ STATE_DSCOPE_EVENT_CONTEXT_BEGIN);
+}
+
+static
+enum bt_ctf_notif_iter_status read_event_context_begin_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *event_context_type;
+
+ event_context_type = bt_ctf_event_class_get_context_type(
+ notit->meta.event_class);
+ if (!event_context_type) {
+ PERR("Failed to retrieve event class's context type\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ status = read_dscope_begin_state(notit, event_context_type,
+ STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
+ STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
+ ¬it->dscopes.event_context);
+
+end:
+ BT_PUT(event_context_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_event_context_continue_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ return read_dscope_continue_state(notit,
+ STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
+}
+
+static
+enum bt_ctf_notif_iter_status read_event_payload_begin_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ struct bt_ctf_field_type *event_payload_type;
+
+ event_payload_type = bt_ctf_event_class_get_payload_type(
+ notit->meta.event_class);
+ if (!event_payload_type) {
+ PERR("Failed to retrieve event class's payload type\n");
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ goto end;
+ }
+
+ status = read_dscope_begin_state(notit, event_payload_type,
+ STATE_EMIT_NOTIF_EVENT,
+ STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
+ ¬it->dscopes.event_payload);
+
+end:
+ BT_PUT(event_payload_type);
+
+ return status;
+}
+
+static
+enum bt_ctf_notif_iter_status read_event_payload_continue_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ return read_dscope_continue_state(notit, STATE_EMIT_NOTIF_EVENT);
+}
+
+static
+enum bt_ctf_notif_iter_status skip_packet_padding_state(
+ struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+ size_t bits_to_skip;
+
+ assert(notit->cur_packet_size > 0);
+ bits_to_skip = notit->cur_packet_size - packet_at(notit);
+ if (bits_to_skip == 0) {
+ notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
+ goto end;
+ } else {
+ size_t bits_to_consume;
+ status = buf_ensure_available_bits(notit);
+ if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
+ goto end;
+ }
+
+ bits_to_consume = MIN(buf_available_bits(notit), bits_to_skip);
+ buf_consume_bits(notit, bits_to_consume);
+ bits_to_skip = notit->cur_packet_size - packet_at(notit);
+ if (bits_to_skip == 0) {
+ notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
+ goto end;
+ }
+ }
+
+end:
+ return status;
+}
+
+static inline
+enum bt_ctf_notif_iter_status handle_state(struct bt_ctf_notif_iter *notit)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+
+ PDBG("Handling state %d\n", notit->state);
+
+ // TODO: optimalize!
+ switch (notit->state) {
+ case STATE_INIT:
+ notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
+ break;
+ case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
+ status = read_packet_header_begin_state(notit);
+ break;
+ case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
+ status = read_packet_header_continue_state(notit);
+ break;
+ case STATE_AFTER_TRACE_PACKET_HEADER:
+ status = after_packet_header_state(notit);
+ break;
+ case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
+ status = read_packet_context_begin_state(notit);
+ break;
+ case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
+ status = read_packet_context_continue_state(notit);
+ break;
+ case STATE_AFTER_STREAM_PACKET_CONTEXT:
+ status = after_packet_context_state(notit);
+ break;
+ case STATE_EMIT_NOTIF_NEW_PACKET:
+ notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
+ break;
+ case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN:
+ status = read_event_header_begin_state(notit);
+ break;
+ case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE:
+ status = read_event_header_continue_state(notit);
+ break;
+ case STATE_AFTER_STREAM_EVENT_HEADER:
+ status = after_event_header_state(notit);
+ break;
+ case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN:
+ status = read_stream_event_context_begin_state(notit);
+ break;
+ case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE:
+ status = read_stream_event_context_continue_state(notit);
+ break;
+ case STATE_DSCOPE_EVENT_CONTEXT_BEGIN:
+ status = read_event_context_begin_state(notit);
+ break;
+ case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE:
+ status = read_event_context_continue_state(notit);
+ break;
+ case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
+ status = read_event_payload_begin_state(notit);
+ break;
+ case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
+ status = read_event_payload_continue_state(notit);
+ break;
+ case STATE_EMIT_NOTIF_EVENT:
+ notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
+ break;
+ case STATE_SKIP_PACKET_PADDING:
+ status = skip_packet_padding_state(notit);
+ break;
+ case STATE_EMIT_NOTIF_END_OF_PACKET:
+ notit->state = STATE_SKIP_PACKET_PADDING;
+ break;
+ }
+
+ return status;
+}
+
+void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notit)
+{
+ assert(notit);
+ stack_clear(notit->stack);
+ BT_PUT(notit->meta.stream_class);
+ BT_PUT(notit->meta.event_class);
+ BT_PUT(notit->packet);
+ put_all_dscopes(notit);
+ notit->buf.addr = NULL;
+ notit->buf.sz = 0;
+ notit->buf.at = 0;
+ notit->buf.packet_offset = 0;
+ notit->state = STATE_INIT;
+ notit->cur_content_size = -1;
+ notit->cur_packet_size = -1;
+}
+
+static
+struct bt_ctf_field *get_next_field(struct bt_ctf_notif_iter *notit)
+{
+ struct bt_ctf_field *next_field = NULL;
+ struct bt_ctf_field *base_field;
+ struct bt_ctf_field_type *base_type;
+ size_t index;
+
+ assert(!stack_empty(notit->stack));
+ index = stack_top(notit->stack)->index;
+ base_field = stack_top(notit->stack)->base;
+ base_type = bt_ctf_field_get_type(base_field);
+ if (!base_type) {
+ PERR("Failed to get base field's type\n");
+ goto end;
+ }
+
+ switch (bt_ctf_field_type_get_type_id(base_type)) {
+ case BT_CTF_TYPE_ID_STRUCT:
+ next_field = bt_ctf_field_structure_get_field_by_index(
+ base_field, index);
+ break;
+ case BT_CTF_TYPE_ID_ARRAY:
+ next_field = bt_ctf_field_array_get_field(base_field, index);
+ break;
+ case BT_CTF_TYPE_ID_SEQUENCE:
+ next_field = bt_ctf_field_sequence_get_field(base_field, index);
+ break;
+ case BT_CTF_TYPE_ID_VARIANT:
+ next_field = bt_ctf_field_variant_get_current_field(base_field);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+end:
+ BT_PUT(base_type);
+
+ return next_field;
+}
+
+static
+enum bt_ctf_btr_status btr_signed_int_cb(int64_t value,
+ struct bt_ctf_field_type *type, void *data)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+ struct bt_ctf_field *field = NULL;
+ struct bt_ctf_field *int_field = NULL;
+ struct bt_ctf_notif_iter *notit = data;
+ int ret;
+
+ /* create next field */
+ field = get_next_field(notit);
+ if (!field) {
+ PERR("Failed to get next field (signed int)\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ switch(bt_ctf_field_type_get_type_id(type)) {
+ case BT_CTF_TYPE_ID_INTEGER:
+ /* Integer field is created field */
+ BT_MOVE(int_field, field);
+ break;
+ case BT_CTF_TYPE_ID_ENUM:
+ int_field = bt_ctf_field_enumeration_get_container(field);
+ break;
+ default:
+ break;
+ }
+
+ if (!int_field) {
+ PERR("Failed to get integer field\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ ret = bt_ctf_field_signed_integer_set_value(int_field, value);
+ assert(!ret);
+ stack_top(notit->stack)->index++;
+
+end:
+ BT_PUT(field);
+ BT_PUT(int_field);
+
+ return status;
+}
+
+static
+enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value,
+ struct bt_ctf_field_type *type, void *data)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+ struct bt_ctf_field *field = NULL;
+ struct bt_ctf_field *int_field = NULL;
+ struct bt_ctf_notif_iter *notit = data;
+ int ret;
+
+ /* Create next field */
+ field = get_next_field(notit);
+ if (!field) {
+ PERR("Failed to get next field (unsigned int)\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ switch(bt_ctf_field_type_get_type_id(type)) {
+ case BT_CTF_TYPE_ID_INTEGER:
+ /* Integer field is created field */
+ BT_MOVE(int_field, field);
+ break;
+ case BT_CTF_TYPE_ID_ENUM:
+ int_field = bt_ctf_field_enumeration_get_container(field);
+ break;
+ default:
+ break;
+ }
+
+ if (!int_field) {
+ PERR("Failed to get integer field\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ ret = bt_ctf_field_unsigned_integer_set_value(int_field, value);
+ assert(!ret);
+ stack_top(notit->stack)->index++;
+
+end:
+ BT_PUT(field);
+ BT_PUT(int_field);
+
+ return status;
+}
+
+static
+enum bt_ctf_btr_status btr_floating_point_cb(double value,
+ struct bt_ctf_field_type *type, void *data)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+ struct bt_ctf_field *field = NULL;
+ struct bt_ctf_notif_iter *notit = data;
+ int ret;
+
+ /* Create next field */
+ field = get_next_field(notit);
+ if (!field) {
+ PERR("Failed to get next field (floating point number)\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ ret = bt_ctf_field_floating_point_set_value(field, value);
+ assert(!ret);
+ stack_top(notit->stack)->index++;
+
+end:
+ BT_PUT(field);
+
+ return status;
+}
+
+static
+enum bt_ctf_btr_status btr_string_begin_cb(
+ struct bt_ctf_field_type *type, void *data)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+ struct bt_ctf_field *field = NULL;
+ struct bt_ctf_notif_iter *notit = data;
+ int ret;
+
+ /* Create next field */
+ field = get_next_field(notit);
+ if (!field) {
+ PERR("Failed to get next field (string)\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ /*
+ * Push on stack. Not a compound type per se, but we know that only
+ * btr_string_cb() may be called between this call and a subsequent
+ * call to btr_string_end_cb().
+ */
+ ret = stack_push(notit->stack, field);
+ if (ret) {
+ PERR("Failed to push string field onto the stack\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+end:
+ BT_PUT(field);
+
+ return status;
+}
+
+static
+enum bt_ctf_btr_status btr_string_cb(const char *value,
+ size_t len, struct bt_ctf_field_type *type, void *data)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+ struct bt_ctf_field *field = NULL;
+ struct bt_ctf_notif_iter *notit = data;
+ int ret;
+
+ /* Get string field */
+ field = stack_top(notit->stack)->base;
+ assert(field);
+
+ /* Append current string */
+ ret = bt_ctf_field_string_append_len(field, value, len);
+ if (ret) {
+ PERR("Failed to append a string to a string field\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+end:
+ return status;
+}
+
+static
+enum bt_ctf_btr_status btr_string_end_cb(
+ struct bt_ctf_field_type *type, void *data)
+{
+ struct bt_ctf_notif_iter *notit = data;
+
+ /* Pop string field */
+ stack_pop(notit->stack);
+
+ /* Go to next field */
+ stack_top(notit->stack)->index++;
+
+ return BT_CTF_BTR_STATUS_OK;
+}
+
+enum bt_ctf_btr_status btr_compound_begin_cb(
+ struct bt_ctf_field_type *type, void *data)
+{
+ enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
+ struct bt_ctf_notif_iter *notit = data;
+ struct bt_ctf_field *field;
+ int ret;
+
+ /* Create field */
+ if (stack_empty(notit->stack)) {
+ /* Root: create dynamic scope field */
+ *notit->cur_dscope_field = bt_ctf_field_create(type);
+ field = *notit->cur_dscope_field;
+
+ /*
+ * Field will be put at the end of this function
+ * (stack_push() will take one reference, but this
+ * reference is lost upon the equivalent stack_pop()
+ * later), so also get it for our context to own it.
+ */
+ bt_get(*notit->cur_dscope_field);
+ } else {
+ field = get_next_field(notit);
+ }
+
+ if (!field) {
+ PERR("Failed to get next field or create dynamic scope field\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+ /* Push field */
+ ret = stack_push(notit->stack, field);
+ if (ret) {
+ PERR("Failed to push compound field onto the stack\n");
+ status = BT_CTF_BTR_STATUS_ERROR;
+ goto end;
+ }
+
+end:
+ BT_PUT(field);
+
+ return status;
+}
+
+enum bt_ctf_btr_status btr_compound_end_cb(
+ struct bt_ctf_field_type *type, void *data)
+{
+ struct bt_ctf_notif_iter *notit = data;
+
+ assert(!stack_empty(notit->stack));
+
+ /* Pop stack */
+ stack_pop(notit->stack);
+
+ /* If the stack is not empty, increment the base's index */
+ if (!stack_empty(notit->stack)) {
+ stack_top(notit->stack)->index++;
+ }
+
+ return BT_CTF_BTR_STATUS_OK;
+}
+
+static
+struct bt_ctf_field *resolve_field(struct bt_ctf_notif_iter *notit,
+ struct bt_ctf_field_path *path)
+{
+ struct bt_ctf_field *field = NULL;
+ unsigned int i;
+
+ switch (bt_ctf_field_path_get_root_scope(path)) {
+ case BT_CTF_SCOPE_TRACE_PACKET_HEADER:
+ field = notit->dscopes.trace_packet_header;
+ break;
+ case BT_CTF_SCOPE_STREAM_PACKET_CONTEXT:
+ field = notit->dscopes.stream_packet_context;
+ break;
+ case BT_CTF_SCOPE_STREAM_EVENT_HEADER:
+ field = notit->dscopes.stream_event_header;
+ break;
+ case BT_CTF_SCOPE_STREAM_EVENT_CONTEXT:
+ field = notit->dscopes.stream_event_context;
+ break;
+ case BT_CTF_SCOPE_EVENT_CONTEXT:
+ field = notit->dscopes.event_context;
+ break;
+ case BT_CTF_SCOPE_EVENT_FIELDS:
+ field = notit->dscopes.event_payload;
+ break;
+ default:
+ break;
+ }
+
+ if (!field) {
+ goto end;
+ }
+
+ bt_get(field);
+
+ for (i = 0; i < bt_ctf_field_path_get_index_count(path); ++i) {
+ struct bt_ctf_field *next_field = NULL;
+ struct bt_ctf_field_type *field_type;
+ int index = bt_ctf_field_path_get_index(path, i);
+
+ field_type = bt_ctf_field_get_type(field);
+ if (!field_type) {
+ BT_PUT(field);
+ goto end;
+ }
+
+ if (is_struct_type(field_type)) {
+ next_field = bt_ctf_field_structure_get_field_by_index(
+ field, index);
+ } else if (is_variant_type(field_type)) {
+ next_field =
+ bt_ctf_field_variant_get_current_field(field);
+ }
+
+ BT_PUT(field);
+ BT_PUT(field_type);
+
+ if (!next_field) {
+ goto end;
+ }
+
+ /* Move next field -> field */
+ BT_MOVE(field, next_field);
+ }
+
+end:
+ return field;
+}
+
+static
+int64_t btr_get_sequence_length_cb(struct bt_ctf_field_type *type, void *data)
+{
+ int64_t ret = -1;
+ int iret;
+ struct bt_ctf_field_path *field_path;
+ struct bt_ctf_notif_iter *notit = data;
+ struct bt_ctf_field *field = NULL;
+ uint64_t length;
+
+ field_path = bt_ctf_field_type_sequence_get_length_field_path(type);
+ if (!field_path) {
+ goto end;
+ }
+
+ field = resolve_field(notit, field_path);
+ if (!field) {
+ goto end;
+ }
+
+ iret = bt_ctf_field_unsigned_integer_get_value(field, &length);
+ if (iret) {
+ goto end;
+ }
+
+ ret = (int64_t) length;
+
+end:
+ BT_PUT(field);
+ BT_PUT(field_path);
+
+ return ret;
+}
+
+static
+struct bt_ctf_field_type *btr_get_variant_type_cb(
+ struct bt_ctf_field_type *type, void *data)
+{
+ struct bt_ctf_field_path *path;
+ struct bt_ctf_notif_iter *notit = data;
+ struct bt_ctf_field *tag_field = NULL;
+ struct bt_ctf_field *selected_field = NULL;
+ struct bt_ctf_field_type *selected_field_type = NULL;
+
+ path = bt_ctf_field_type_variant_get_tag_field_path(type);
+ if (!path) {
+ goto end;
+ }
+
+ tag_field = resolve_field(notit, path);
+ if (!tag_field) {
+ goto end;
+ }
+
+ /*
+ * We found the enumeration tag field instance which should be
+ * able to select a current field for this variant. This
+ * callback function we're in is called _after_
+ * compound_begin(), so the current stack top's base field is
+ * the variant field in question. We get the selected field here
+ * thanks to this tag field (thus creating the selected field),
+ * which will also provide us with its type. Then, this field
+ * will remain the current selected one until the next callback
+ * function call which is used to fill the current selected
+ * field.
+ */
+ selected_field = bt_ctf_field_variant_get_field(
+ stack_top(notit->stack)->base, tag_field);
+ if (!selected_field) {
+ goto end;
+ }
+
+ selected_field_type = bt_ctf_field_get_type(selected_field);
+
+end:
+ BT_PUT(tag_field);
+ BT_PUT(selected_field);
+
+ return selected_field_type;
+}
+
+static struct bt_ctf_event *create_event(struct bt_ctf_notif_iter *notit)
+{
+ struct bt_ctf_event *event;
+ int ret;
+
+ /* Create event object */
+ event = bt_ctf_event_create(notit->meta.event_class);
+ if (!event) {
+ goto error;
+ }
+
+ /* Set header, stream event context, context, and payload fields */
+ ret = bt_ctf_event_set_header(event,
+ notit->dscopes.stream_event_header);
+ if (ret) {
+ goto error;
+ }
+
+ ret = bt_ctf_event_set_stream_event_context(event,
+ notit->dscopes.stream_event_context);
+ if (ret) {
+ goto error;
+ }
+
+ ret = bt_ctf_event_set_event_context(event,
+ notit->dscopes.event_context);
+ if (ret) {
+ goto error;
+ }
+
+ ret = bt_ctf_event_set_payload_field(event,
+ notit->dscopes.event_payload);
+ if (ret) {
+ goto error;
+ }
+
+ /* Associate with current packet */
+ assert(notit->packet);
+ ret = bt_ctf_event_set_packet(event, notit->packet);
+ if (ret) {
+ goto error;
+ }
+
+ goto end;
+
+error:
+ BT_PUT(event);
+
+end:
+ return event;
+}
+
+static void create_packet(struct bt_ctf_notif_iter *notit)
+{
+ int ret;
+ struct bt_ctf_stream *stream = NULL;
+ struct bt_ctf_packet *packet = NULL;
+
+ /* Ask the user for the stream */
+ stream = notit->medium.medops.get_stream(notit->meta.stream_class,
+ notit->medium.data);
+ if (!stream) {
+ goto error;
+ }
+
+ /* Create packet */
+ packet = bt_ctf_packet_create(stream);
+ if (!packet) {
+ goto error;
+ }
+
+ /* Set packet's context and header fields */
+ if (notit->dscopes.trace_packet_header) {
+ ret = bt_ctf_packet_set_header(packet,
+ notit->dscopes.trace_packet_header);
+ if (ret) {
+ goto error;
+ }
+ }
+
+ if (notit->dscopes.stream_packet_context) {
+ ret = bt_ctf_packet_set_context(packet,
+ notit->dscopes.stream_packet_context);
+ if (ret) {
+ goto error;
+ }
+ }
+
+ goto end;
+
+error:
+ BT_PUT(packet);
+
+end:
+ BT_MOVE(notit->packet, packet);
+}
+
+static void notify_new_packet(struct bt_ctf_notif_iter *notit,
+ struct bt_ctf_notif_iter_notif **notification)
+{
+ struct bt_ctf_notif_iter_notif_new_packet *rnotif;
+
+ rnotif = g_new0(struct bt_ctf_notif_iter_notif_new_packet, 1);
+ if (!rnotif) {
+ goto error;
+ }
+
+ rnotif->base.type = BT_CTF_NOTIF_ITER_NOTIF_NEW_PACKET;
+
+ /* Create packet */
+ create_packet(notit);
+ if (!notit->packet) {
+ goto error;
+ }
+
+ rnotif->packet = bt_get(notit->packet);
+ *notification = (struct bt_ctf_notif_iter_notif *) rnotif;
+ return;
+
+error:
+ bt_ctf_notif_iter_notif_destroy(rnotif);
+}
+
+static void notify_end_of_packet(struct bt_ctf_notif_iter *notit,
+ struct bt_ctf_notif_iter_notif **notification)
+{
+ struct bt_ctf_notif_iter_notif_end_of_packet *rnotif;
+
+ rnotif = g_new0(struct bt_ctf_notif_iter_notif_end_of_packet, 1);
+ if (!rnotif) {
+ goto error;
+ }
+
+ rnotif->base.type = BT_CTF_NOTIF_ITER_NOTIF_END_OF_PACKET;
+
+ /* Create packet */
+ create_packet(notit);
+ if (!notit->packet) {
+ goto error;
+ }
+
+ rnotif->packet = bt_get(notit->packet);
+ *notification = (struct bt_ctf_notif_iter_notif *) rnotif;
+ return;
+
+error:
+ bt_ctf_notif_iter_notif_destroy(rnotif);
+}
+
+static void notify_event(struct bt_ctf_notif_iter *notit,
+ struct bt_ctf_notif_iter_notif **notification)
+{
+ struct bt_ctf_notif_iter_notif_event *rnotif;
+ struct bt_ctf_event *event = NULL;
+
+ rnotif = g_new0(struct bt_ctf_notif_iter_notif_event, 1);
+ if (!rnotif) {
+ goto error;
+ }
+
+ rnotif->base.type = BT_CTF_NOTIF_ITER_NOTIF_EVENT;
+
+ /* Create event */
+ event = create_event(notit);
+ if (!event) {
+ goto error;
+ }
+
+ BT_MOVE(rnotif->event, event);
+ *notification = (struct bt_ctf_notif_iter_notif *) rnotif;
+ return;
+
+error:
+ BT_PUT(event);
+ bt_ctf_notif_iter_notif_destroy(rnotif);
+}
+
+void bt_ctf_notif_iter_notif_destroy(void *vnotif)
+{
+ struct bt_ctf_notif_iter_notif *notif = vnotif;
+
+ switch (notif->type) {
+ case BT_CTF_NOTIF_ITER_NOTIF_NEW_PACKET:
+ {
+ struct bt_ctf_notif_iter_notif_new_packet *rnotif =
+ (struct bt_ctf_notif_iter_notif_new_packet *) notif;
+
+ BT_PUT(rnotif->packet);
+ break;
+ }
+ case BT_CTF_NOTIF_ITER_NOTIF_END_OF_PACKET:
+ {
+ struct bt_ctf_notif_iter_notif_end_of_packet *rnotif =
+ (struct bt_ctf_notif_iter_notif_end_of_packet *) notif;
+
+ BT_PUT(rnotif->packet);
+ break;
+ }
+ case BT_CTF_NOTIF_ITER_NOTIF_EVENT:
+ {
+ struct bt_ctf_notif_iter_notif_event *rnotif =
+ (struct bt_ctf_notif_iter_notif_event *) notif;
+
+ BT_PUT(rnotif->event);
+ break;
+ }
+ default:
+ assert(false);
+ }
+
+ g_free(notif);
+}
+
+struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
+ size_t max_request_sz,
+ struct bt_ctf_notif_iter_medium_ops medops,
+ void *data, FILE *err_stream)
+{
+ struct bt_ctf_notif_iter *notit = NULL;
+ struct bt_ctf_btr_cbs cbs = {
+ .types = {
+ .signed_int = btr_signed_int_cb,
+ .unsigned_int = btr_unsigned_int_cb,
+ .floating_point = btr_floating_point_cb,
+ .string_begin = btr_string_begin_cb,
+ .string = btr_string_cb,
+ .string_end = btr_string_end_cb,
+ .compound_begin = btr_compound_begin_cb,
+ .compound_end = btr_compound_end_cb,
+ },
+ .query = {
+ .get_sequence_length = btr_get_sequence_length_cb,
+ .get_variant_type = btr_get_variant_type_cb,
+ },
+ };
+
+ assert(trace);
+ assert(medops.request_bytes);
+ notit = g_new0(struct bt_ctf_notif_iter, 1);
+ if (!notit) {
+ PERR("Failed to allocate memory for CTF notification iterator\n");
+ goto end;
+ }
+
+ notit->meta.trace = trace;
+ bt_get(notit->meta.trace);
+ notit->medium.medops = medops;
+ notit->medium.max_request_sz = max_request_sz;
+ notit->medium.data = data;
+ notit->err_stream = err_stream;
+ notit->stack = stack_new(notit);
+ if (!notit->stack) {
+ PERR("Failed to create stack\n");
+ bt_ctf_notif_iter_destroy(notit);
+ notit = NULL;
+ goto end;
+ }
+
+ notit->btr = bt_ctf_btr_create(cbs, notit, err_stream);
+ if (!notit->btr) {
+ PERR("Failed to create binary type reader\n");
+ bt_ctf_notif_iter_destroy(notit);
+ notit = NULL;
+ goto end;
+ }
+
+ bt_ctf_notif_iter_reset(notit);
+
+end:
+ return notit;
+}
+
+void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notit)
+{
+ BT_PUT(notit->meta.trace);
+ BT_PUT(notit->meta.stream_class);
+ BT_PUT(notit->meta.event_class);
+ BT_PUT(notit->packet);
+ put_all_dscopes(notit);
+
+ if (notit->stack) {
+ stack_destroy(notit->stack);
+ }
+
+ if (notit->btr) {
+ bt_ctf_btr_destroy(notit->btr);
+ }
+
+ g_free(notit);
+}
+
+enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification(
+ struct bt_ctf_notif_iter *notit,
+ struct bt_ctf_notif_iter_notif **notification)
+{
+ enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
+
+ assert(notit);
+ assert(notification);
+
+ while (true) {
+ status = handle_state(notit);
+ if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
+ if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
+ PDBG("Medium operation reported end of file\n");
+ } else {
+ PERR("Failed to handle state:\n");
+ PERR(" State: %d\n", notit->state);
+ }
+ goto end;
+ }
+
+ switch (notit->state) {
+ case STATE_EMIT_NOTIF_NEW_PACKET:
+ PDBG("Emitting new packet notification\n");
+ notify_new_packet(notit, notification);
+ if (!*notification) {
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ }
+ goto end;
+ case STATE_EMIT_NOTIF_EVENT:
+ PDBG("Emitting event notification\n");
+ notify_event(notit, notification);
+ if (!*notification) {
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ }
+ goto end;
+ case STATE_EMIT_NOTIF_END_OF_PACKET:
+ PDBG("Emitting end of packet notification\n");
+ notify_end_of_packet(notit, notification);
+ if (!*notification) {
+ status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
+ }
+ goto end;
+ default:
+ /* Non-emitting state: continue */
+ break;
+ }
+ }
+
+end:
+ return status;
+}
--- /dev/null
+#ifndef CTF_NOTIF_ITER_H
+#define CTF_NOTIF_ITER_H
+
+/*
+ * Babeltrace - CTF notification iterator
+ * ¯¯¯¯¯ ¯¯¯¯
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <babeltrace/ctf-ir/trace.h>
+#include <babeltrace/ctf-ir/fields.h>
+#include <babeltrace/ctf-ir/event.h>
+#include <babeltrace/babeltrace-internal.h>
+
+/**
+ * @file ctf-notif-iter.h
+ *
+ * CTF notification iterator
+ * ¯¯¯¯¯ ¯¯¯¯
+ * This is a common internal API used by CTF source plugins. It allows
+ * one to get notifications from a user-provided medium.
+ */
+
+/**
+ * Medium operations status codes.
+ */
+enum bt_ctf_notif_iter_medium_status {
+ /**
+ * End of file.
+ *
+ * The medium function called by the notification iterator
+ * function reached the end of the file.
+ */
+ BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF = -4,
+
+ /**
+ * There is no data available right now, try again later.
+ */
+ BT_CTF_NOTIF_ITER_MEDIUM_STATUS_AGAIN = -3,
+
+ /** Invalid argument. */
+ BT_CTF_NOTIF_ITER_MEDIUM_STATUS_INVAL = -2,
+
+ /** General error. */
+ BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR = -1,
+
+ /** Everything okay. */
+ BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK = 0,
+};
+
+/**
+ * CTF notification iterator API status code.
+ */
+enum bt_ctf_notif_iter_status {
+ /**
+ * End of file.
+ *
+ * The medium function called by the notification iterator
+ * function reached the end of the file.
+ */
+ BT_CTF_NOTIF_ITER_STATUS_EOF = -4,
+
+ /**
+ * There is no data available right now, try again later.
+ *
+ * Some condition resulted in the
+ * bt_ctf_notif_iter_medium_ops::request_bytes() user function not
+ * having access to any data now. You should retry calling the
+ * last called notification iterator function once the situation
+ * is resolved.
+ */
+ BT_CTF_NOTIF_ITER_STATUS_AGAIN = -3,
+
+ /** Invalid argument. */
+ BT_CTF_NOTIF_ITER_STATUS_INVAL = -2,
+
+ /** General error. */
+ BT_CTF_NOTIF_ITER_STATUS_ERROR = -1,
+
+ /** Everything okay. */
+ BT_CTF_NOTIF_ITER_STATUS_OK = 0,
+};
+
+/**
+ * Medium operations.
+ *
+ * Those user functions are called by the notification iterator
+ * functions to request medium actions.
+ */
+struct bt_ctf_notif_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 notification 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 notification iterator functions. The
+ * returned buffer won't be modified by the notification
+ * 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:
+ *
+ * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK</b>: 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.
+ * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_AGAIN</b>: No data is
+ * available right now. In this case, the notification
+ * iterator function called by the user returns
+ * #BT_CTF_NOTIF_ITER_STATUS_AGAIN, and it is the user's
+ * responsibility to make sure enough data becomes available
+ * before calling the \em same notification iterator
+ * function again to continue the decoding process.
+ * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF</b>: The end of
+ * the file was reached, and no more data will ever be
+ * available for this file. In this case, the notification
+ * iterator function called by the user returns
+ * #BT_CTF_NOTIF_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
+ * #BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF on the \em following
+ * call.
+ * - <b>#BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR</b>: A fatal
+ * error occured during this operation. In this case, the
+ * notification iterator function called by the user returns
+ * #BT_CTF_NOTIF_ITER_STATUS_ERROR.
+ *
+ * If #BT_CTF_NOTIF_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 bt_ctf_notif_iter_medium_status (* request_bytes)(
+ size_t request_sz, uint8_t **buffer_addr,
+ size_t *buffer_sz, 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 notification
+ * iterator.
+ *
+ * @param stream_class Stream class associated to the stream
+ * @param data User data
+ * @returns Stream instance (weak reference) or
+ * \c NULL on error
+ */
+ struct bt_ctf_stream * (* get_stream)(
+ struct bt_ctf_stream_class *stream_class, void *data);
+};
+
+/** CTF notification iterator. */
+struct bt_ctf_notif_iter;
+
+// TODO: Replace by the real thing
+enum bt_ctf_notif_iter_notif_type {
+ BT_CTF_NOTIF_ITER_NOTIF_NEW_PACKET,
+ BT_CTF_NOTIF_ITER_NOTIF_END_OF_PACKET,
+ BT_CTF_NOTIF_ITER_NOTIF_EVENT,
+};
+
+struct bt_ctf_notif_iter_notif {
+ enum bt_ctf_notif_iter_notif_type type;
+};
+
+struct bt_ctf_notif_iter_notif_new_packet {
+ struct bt_ctf_notif_iter_notif base;
+ struct bt_ctf_packet *packet;
+};
+
+struct bt_ctf_notif_iter_notif_end_of_packet {
+ struct bt_ctf_notif_iter_notif base;
+ struct bt_ctf_packet *packet;
+};
+
+struct bt_ctf_notif_iter_notif_event {
+ struct bt_ctf_notif_iter_notif base;
+ struct bt_ctf_event *event;
+};
+
+void bt_ctf_notif_iter_notif_destroy(void *notif);
+
+/**
+ * Creates a CTF notification 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
+ * bt_ctf_notif_iter_medium_ops::request_bytes()
+ * at a time
+ * @param medops Medium operations
+ * @param medops_data User data (passed to medium operations)
+ * @param err_stream Error stream (can be \c NULL to disable)
+ * @returns New CTF notification iterator on
+ * success, or \c NULL on error
+ */
+struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
+ size_t max_request_sz, struct bt_ctf_notif_iter_medium_ops medops,
+ void *medops_data, FILE *err_stream);
+
+/**
+ * Destroys a CTF notification iterator, freeing all internal resources.
+ *
+ * The registered trace's reference count is decremented.
+ *
+ * @param notif_iter CTF notification iterator
+ */
+void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notif_iter);
+
+/**
+ * Resets the internal state of a CTF notification iterator.
+ *
+ * This function can be used when it is desired to seek to the beginning
+ * of another packet. It is expected that the next call to
+ * bt_ctf_notif_iter_medium_ops::request_bytes() made by this
+ * notification iterator will return the \em first bytes of a \em
+ * packet.
+ *
+ * @param notif_iter CTF notification iterator
+ */
+void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notif_iter);
+
+/**
+ * Returns the next notification from a CTF notification iterator.
+ *
+ * Upon successful completion, #BT_CTF_NOTIF_ITER_STATUS_OK is
+ * returned, and the next notification is written to \p notif.
+ * In this case, the caller is responsible for calling
+ * bt_notification_put() on the returned notification.
+ *
+ * If this function returns #BT_CTF_NOTIF_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 notif_iter CTF notification iterator
+ * @param notification Returned notification if the function's
+ * return value is #BT_CTF_NOTIF_ITER_STATUS_OK
+ * @returns One of #bt_ctf_notif_iter_status values
+ */
+enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification(
+ struct bt_ctf_notif_iter *notif_iter,
+ struct bt_ctf_notif_iter_notif **notification);
+
+#endif /* CTF_NOTIF_ITER_H */
--- /dev/null
+#ifndef CTF_NOTIF_ITER_PRINT_H
+#define CTF_NOTIF_ITER_PRINT_H
+
+/*
+ * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <babeltrace/babeltrace-internal.h>
+
+#define PERR(fmt, ...) \
+ do { \
+ if (PRINT_ERR_STREAM) { \
+ fprintf(PRINT_ERR_STREAM, \
+ "Error: " PRINT_PREFIX ": " fmt, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PWARN(fmt, ...) \
+ do { \
+ if (PRINT_ERR_STREAM) { \
+ fprintf(PRINT_ERR_STREAM, \
+ "Warning: " PRINT_PREFIX ": " fmt, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PDBG(fmt, ...) \
+ do { \
+ if (babeltrace_debug) { \
+ fprintf(stderr, \
+ "Debug: " PRINT_PREFIX ": " fmt, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#endif /* CTF_NOTIF_ITER_PRINT_H */