From: Mathieu Desnoyers Date: Fri, 29 Nov 2013 06:19:33 +0000 (+0100) Subject: Merge branch 'master' into bindings/python X-Git-Tag: v1.2.0-rc1~39 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=024e61817685a20caceb4e3ef3bdc019a7af6b6e;hp=13ec125abb88a60fc5e11ff904b525e1f00a331b Merge branch 'master' into bindings/python Signed-off-by: Mathieu Desnoyers --- diff --git a/converter/babeltrace-log.c b/converter/babeltrace-log.c index b6d798f7..5a8b26a8 100644 --- a/converter/babeltrace-log.c +++ b/converter/babeltrace-log.c @@ -124,23 +124,36 @@ void write_packet_header(struct ctf_stream_pos *pos, unsigned char *uuid) /* magic */ ctf_dummy_pos(pos, &dummy); - ctf_align_pos(&dummy, sizeof(uint32_t) * CHAR_BIT); - ctf_move_pos(&dummy, sizeof(uint32_t) * CHAR_BIT); + if (!ctf_align_pos(&dummy, sizeof(uint32_t) * CHAR_BIT)) + goto error; + if (!ctf_move_pos(&dummy, sizeof(uint32_t) * CHAR_BIT)) + goto error; assert(!ctf_pos_packet(&dummy)); - ctf_align_pos(pos, sizeof(uint32_t) * CHAR_BIT); + if (!ctf_align_pos(pos, sizeof(uint32_t) * CHAR_BIT)) + goto error; *(uint32_t *) ctf_get_pos_addr(pos) = 0xC1FC1FC1; - ctf_move_pos(pos, sizeof(uint32_t) * CHAR_BIT); + if (!ctf_move_pos(pos, sizeof(uint32_t) * CHAR_BIT)) + goto error; /* uuid */ ctf_dummy_pos(pos, &dummy); - ctf_align_pos(&dummy, sizeof(uint8_t) * CHAR_BIT); - ctf_move_pos(&dummy, 16 * CHAR_BIT); + if (!ctf_align_pos(&dummy, sizeof(uint8_t) * CHAR_BIT)) + goto error; + if (!ctf_move_pos(&dummy, 16 * CHAR_BIT)) + goto error; assert(!ctf_pos_packet(&dummy)); - ctf_align_pos(pos, sizeof(uint8_t) * CHAR_BIT); + if (!ctf_align_pos(pos, sizeof(uint8_t) * CHAR_BIT)) + goto error; memcpy(ctf_get_pos_addr(pos), uuid, BABELTRACE_UUID_LEN); - ctf_move_pos(pos, BABELTRACE_UUID_LEN * CHAR_BIT); + if (!ctf_move_pos(pos, BABELTRACE_UUID_LEN * CHAR_BIT)) + goto error; + return; + +error: + fprintf(stderr, "[error] Out of packet bounds when writing packet header\n"); + abort(); } static @@ -150,24 +163,37 @@ void write_packet_context(struct ctf_stream_pos *pos) /* content_size */ ctf_dummy_pos(pos, &dummy); - ctf_align_pos(&dummy, sizeof(uint64_t) * CHAR_BIT); - ctf_move_pos(&dummy, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_align_pos(&dummy, sizeof(uint64_t) * CHAR_BIT)) + goto error; + if (!ctf_move_pos(&dummy, sizeof(uint64_t) * CHAR_BIT)) + goto error; assert(!ctf_pos_packet(&dummy)); - ctf_align_pos(pos, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_align_pos(pos, sizeof(uint64_t) * CHAR_BIT)) + goto error; *(uint64_t *) ctf_get_pos_addr(pos) = ~0ULL; /* Not known yet */ pos->content_size_loc = (uint64_t *) ctf_get_pos_addr(pos); - ctf_move_pos(pos, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_move_pos(pos, sizeof(uint64_t) * CHAR_BIT)) + goto error; /* packet_size */ ctf_dummy_pos(pos, &dummy); - ctf_align_pos(&dummy, sizeof(uint64_t) * CHAR_BIT); - ctf_move_pos(&dummy, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_align_pos(&dummy, sizeof(uint64_t) * CHAR_BIT)) + goto error; + if (!ctf_move_pos(&dummy, sizeof(uint64_t) * CHAR_BIT)) + goto error; assert(!ctf_pos_packet(&dummy)); - ctf_align_pos(pos, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_align_pos(pos, sizeof(uint64_t) * CHAR_BIT)) + goto error; *(uint64_t *) ctf_get_pos_addr(pos) = pos->packet_size; - ctf_move_pos(pos, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_move_pos(pos, sizeof(uint64_t) * CHAR_BIT)) + goto error; + return; + +error: + fprintf(stderr, "[error] Out of packet bounds when writing packet context\n"); + abort(); } static @@ -225,10 +251,17 @@ void write_event_header(struct ctf_stream_pos *pos, char *line, } } /* timestamp */ - ctf_align_pos(pos, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_align_pos(pos, sizeof(uint64_t) * CHAR_BIT)) + goto error; if (!pos->dummy) *(uint64_t *) ctf_get_pos_addr(pos) = *ts; - ctf_move_pos(pos, sizeof(uint64_t) * CHAR_BIT); + if (!ctf_move_pos(pos, sizeof(uint64_t) * CHAR_BIT)) + goto error; + return; + +error: + fprintf(stderr, "[error] Out of packet bounds when writing event header\n"); + abort(); } static @@ -245,8 +278,10 @@ void trace_string(char *line, struct ctf_stream_pos *pos, size_t len) for (;;) { ctf_dummy_pos(pos, &dummy); write_event_header(&dummy, line, &tline, len, &tlen, &ts); - ctf_align_pos(&dummy, sizeof(uint8_t) * CHAR_BIT); - ctf_move_pos(&dummy, tlen * CHAR_BIT); + if (!ctf_align_pos(&dummy, sizeof(uint8_t) * CHAR_BIT)) + goto error; + if (!ctf_move_pos(&dummy, tlen * CHAR_BIT)) + goto error; if (ctf_pos_packet(&dummy)) { ctf_pos_pad_packet(pos); write_packet_header(pos, s_uuid); @@ -263,9 +298,16 @@ void trace_string(char *line, struct ctf_stream_pos *pos, size_t len) } write_event_header(pos, line, &tline, len, &tlen, &ts); - ctf_align_pos(pos, sizeof(uint8_t) * CHAR_BIT); + if (!ctf_align_pos(pos, sizeof(uint8_t) * CHAR_BIT)) + goto error; memcpy(ctf_get_pos_addr(pos), tline, tlen); - ctf_move_pos(pos, tlen * CHAR_BIT); + if (!ctf_move_pos(pos, tlen * CHAR_BIT)) + goto error; + return; + +error: + fprintf(stderr, "[error] Out of packet bounds when writing event payload\n"); + abort(); } static diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c index 60d9c9f9..5cf8097c 100644 --- a/formats/ctf/ctf.c +++ b/formats/ctf/ctf.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,8 @@ #define NSEC_PER_SEC 1000000000ULL +#define INDEX_PATH "./index/%s.idx" + int opt_clock_cycles, opt_clock_seconds, opt_clock_date, @@ -468,6 +471,15 @@ int ctf_read_event(struct bt_stream_pos *ppos, struct ctf_stream_definition *str */ if (unlikely(pos->offset == EOF)) return EOF; + + if (pos->content_size == 0) { + /* Stream is inactive for now (live reading). */ + return EAGAIN; + } + /* Packet only contains headers */ + if (pos->offset == pos->content_size) + return EAGAIN; + assert(pos->offset < pos->content_size); /* Read event header */ @@ -548,10 +560,15 @@ int ctf_read_event(struct bt_stream_pos *ppos, struct ctf_stream_definition *str goto error; } + if (pos->last_offset == pos->offset) { + fprintf(stderr, "[error] Invalid 0 byte event encountered.\n"); + return -EINVAL; + } + return 0; error: - fprintf(stderr, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n"); + fprintf(stderr, "[error] Unexpected end of packet. Either the trace data stream is corrupted or metadata description does not match data layout.\n"); return ret; } @@ -1481,28 +1498,28 @@ begin: fprintf(stderr, "[error] Unable to read packet context: %s\n", strerror(-ret)); return ret; } - /* read content size from header */ - len_index = bt_struct_declaration_lookup_field_index(file_stream->parent.stream_packet_context->declaration, g_quark_from_static_string("content_size")); + /* read packet size from header */ + len_index = bt_struct_declaration_lookup_field_index(file_stream->parent.stream_packet_context->declaration, g_quark_from_static_string("packet_size")); if (len_index >= 0) { struct bt_definition *field; field = bt_struct_definition_get_field_from_index(file_stream->parent.stream_packet_context, len_index); - packet_index.content_size = bt_get_unsigned_int(field); + packet_index.packet_size = bt_get_unsigned_int(field); } else { /* Use file size for packet size */ - packet_index.content_size = filesize * CHAR_BIT; + packet_index.packet_size = filesize * CHAR_BIT; } - /* read packet size from header */ - len_index = bt_struct_declaration_lookup_field_index(file_stream->parent.stream_packet_context->declaration, g_quark_from_static_string("packet_size")); + /* read content size from header */ + len_index = bt_struct_declaration_lookup_field_index(file_stream->parent.stream_packet_context->declaration, g_quark_from_static_string("content_size")); if (len_index >= 0) { struct bt_definition *field; field = bt_struct_definition_get_field_from_index(file_stream->parent.stream_packet_context, len_index); - packet_index.packet_size = bt_get_unsigned_int(field); + packet_index.content_size = bt_get_unsigned_int(field); } else { - /* Use content size if non-zero, else file size */ - packet_index.packet_size = packet_index.content_size ? : filesize * CHAR_BIT; + /* Use packet size if non-zero, else file size */ + packet_index.content_size = packet_index.packet_size ? : filesize * CHAR_BIT; } /* read timestamp begin from header */ @@ -1546,9 +1563,9 @@ begin: } } else { /* Use file size for packet size */ - packet_index.content_size = filesize * CHAR_BIT; - /* Use content size if non-zero, else file size */ - packet_index.packet_size = packet_index.content_size ? : filesize * CHAR_BIT; + packet_index.packet_size = filesize * CHAR_BIT; + /* Use packet size if non-zero, else file size */ + packet_index.content_size = packet_index.packet_size ? : filesize * CHAR_BIT; } /* Validate content size and packet size values */ @@ -1564,6 +1581,16 @@ begin: return -EINVAL; } + if (packet_index.content_size < pos->offset) { + fprintf(stderr, "[error] Invalid CTF stream: content size is smaller than packet headers.\n"); + return -EINVAL; + } + + if ((packet_index.packet_size >> LOG2_CHAR_BIT) == 0) { + fprintf(stderr, "[error] Invalid CTF stream: packet size needs to be at least one byte\n"); + return -EINVAL; + } + /* Save position after header and context */ packet_index.data_offset = pos->offset; @@ -1666,6 +1693,93 @@ error: return ret; } +static +int import_stream_packet_index(struct ctf_trace *td, + struct ctf_file_stream *file_stream) +{ + struct ctf_stream_declaration *stream; + struct ctf_stream_pos *pos; + struct ctf_packet_index ctf_index; + struct ctf_packet_index_file_hdr index_hdr; + struct packet_index index; + int index_read; + int ret = 0; + int first_packet = 1; + size_t len; + + pos = &file_stream->pos; + + len = fread(&index_hdr, sizeof(index_hdr), 1, pos->index_fp); + if (len != 1) { + perror("read index file header"); + goto error; + } + + /* Check the index header */ + if (be32toh(index_hdr.magic) != CTF_INDEX_MAGIC) { + fprintf(stderr, "[error] wrong index magic\n"); + ret = -1; + goto error; + } + if (be32toh(index_hdr.index_major) != CTF_INDEX_MAJOR) { + fprintf(stderr, "[error] Incompatible index file %" PRIu64 + ".%" PRIu64 ", supported %d.%d\n", + be64toh(index_hdr.index_major), + be64toh(index_hdr.index_minor), CTF_INDEX_MAJOR, + CTF_INDEX_MINOR); + ret = -1; + goto error; + } + if (index_hdr.packet_index_len == 0) { + fprintf(stderr, "[error] Packet index length cannot be 0.\n"); + ret = -1; + goto error; + } + + while ((index_read = fread(&ctf_index, index_hdr.packet_index_len, 1, + pos->index_fp)) == 1) { + uint64_t stream_id; + + memset(&index, 0, sizeof(index)); + index.offset = be64toh(ctf_index.offset); + index.packet_size = be64toh(ctf_index.packet_size); + index.content_size = be64toh(ctf_index.content_size); + index.timestamp_begin = be64toh(ctf_index.timestamp_begin); + index.timestamp_end = be64toh(ctf_index.timestamp_end); + index.events_discarded = be64toh(ctf_index.events_discarded); + index.events_discarded_len = 64; + stream_id = be64toh(ctf_index.stream_id); + + if (!first_packet) { + /* add index to packet array */ + g_array_append_val(file_stream->pos.packet_cycles_index, index); + continue; + } + + file_stream->parent.stream_id = stream_id; + stream = g_ptr_array_index(td->streams, stream_id); + if (!stream) { + fprintf(stderr, "[error] Stream %" PRIu64 + " is not declared in metadata.\n", + stream_id); + ret = -EINVAL; + goto error; + } + file_stream->parent.stream_class = stream; + ret = create_stream_definitions(td, &file_stream->parent); + if (ret) + goto error; + first_packet = 0; + /* add index to packet array */ + g_array_append_val(file_stream->pos.packet_cycles_index, index); + } + + ret = 0; + +error: + return ret; +} + /* * Note: many file streams can inherit from the same stream class * description (metadata). @@ -1678,6 +1792,7 @@ int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags, int ret, fd, closeret; struct ctf_file_stream *file_stream; struct stat statbuf; + char *index_name; fd = openat(td->dirfd, path, flags); if (fd < 0) { @@ -1693,13 +1808,18 @@ int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags, goto fstat_error; } if (S_ISDIR(statbuf.st_mode)) { - fprintf(stderr, "[warning] Skipping directory '%s' found in trace\n", path); + if (strncmp(path, "index", 5) != 0) { + fprintf(stderr, "[warning] Skipping directory '%s' " + "found in trace\n", path); + } ret = 0; goto fd_is_dir_ok; } file_stream = g_new0(struct ctf_file_stream, 1); file_stream->pos.last_offset = LAST_OFFSET_POISON; + file_stream->pos.fd = -1; + file_stream->pos.index_fp = NULL; strncpy(file_stream->parent.path, path, PATH_MAX); file_stream->parent.path[PATH_MAX - 1] = '\0'; @@ -1722,19 +1842,65 @@ int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags, * For now, only a single clock per trace is supported. */ file_stream->parent.current_clock = td->parent.single_clock; - ret = create_stream_packet_index(td, file_stream); - if (ret) { - fprintf(stderr, "[error] Stream index creation error.\n"); - goto error_index; + + /* + * Allocate the index name for this stream and try to open it. + */ + index_name = malloc((strlen(path) + sizeof(INDEX_PATH)) * sizeof(char)); + if (!index_name) { + fprintf(stderr, "[error] Cannot allocate index filename\n"); + goto error_def; } + snprintf(index_name, strlen(path) + sizeof(INDEX_PATH), + INDEX_PATH, path); + + if (faccessat(td->dirfd, index_name, O_RDONLY, flags) < 0) { + ret = create_stream_packet_index(td, file_stream); + if (ret) { + fprintf(stderr, "[error] Stream index creation error.\n"); + goto error_index; + } + } else { + ret = openat(td->dirfd, index_name, flags); + if (ret < 0) { + perror("Index file openat()"); + ret = -1; + goto error_free; + } + file_stream->pos.index_fp = fdopen(ret, "r"); + if (!file_stream->pos.index_fp) { + perror("fdopen() error"); + goto error_free; + } + ret = import_stream_packet_index(td, file_stream); + if (ret) { + ret = -1; + goto error_index; + } + ret = fclose(file_stream->pos.index_fp); + if (ret < 0) { + perror("close index"); + goto error_free; + } + } + free(index_name); + /* Add stream file to stream class */ g_ptr_array_add(file_stream->parent.stream_class->streams, &file_stream->parent); return 0; error_index: + if (file_stream->pos.index_fp) { + ret = fclose(file_stream->pos.index_fp); + if (ret < 0) { + perror("close index"); + } + } if (file_stream->parent.trace_packet_header) bt_definition_unref(&file_stream->parent.trace_packet_header->p); +error_free: + free(index_name); error_def: closeret = ctf_fini_pos(&file_stream->pos); if (closeret) { @@ -1761,6 +1927,7 @@ int ctf_open_trace_read(struct ctf_trace *td, struct dirent *dirent; struct dirent *diriter; size_t dirent_len; + char *ext; td->flags = flags; @@ -1816,6 +1983,13 @@ int ctf_open_trace_read(struct ctf_trace *td, || !strcmp(diriter->d_name, "..") || !strcmp(diriter->d_name, "metadata")) continue; + + /* Ignore index files : *.idx */ + ext = strrchr(diriter->d_name, '.'); + if (ext && (!strcmp(ext, ".idx"))) { + continue; + } + ret = ctf_open_file_stream_read(td, diriter->d_name, flags, packet_seek); if (ret) { diff --git a/formats/ctf/types/array.c b/formats/ctf/types/array.c index 04801d4f..979f7a3d 100644 --- a/formats/ctf/types/array.c +++ b/formats/ctf/types/array.c @@ -48,7 +48,8 @@ int ctf_array_read(struct bt_stream_pos *ppos, struct bt_definition *definition) if (integer_declaration->len == CHAR_BIT && integer_declaration->p.alignment == CHAR_BIT) { - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, array_declaration->len * CHAR_BIT)) return -EFAULT; @@ -56,6 +57,11 @@ int ctf_array_read(struct bt_stream_pos *ppos, struct bt_definition *definition) g_string_insert_len(array_definition->string, 0, (char *) ctf_get_pos_addr(pos), array_declaration->len); + /* + * We want to populate both the string + * and the underlying values, so carry + * on calling bt_array_rw(). + */ } } } @@ -82,14 +88,16 @@ int ctf_array_write(struct bt_stream_pos *ppos, struct bt_definition *definition if (integer_declaration->len == CHAR_BIT && integer_declaration->p.alignment == CHAR_BIT) { - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, array_declaration->len * CHAR_BIT)) return -EFAULT; memcpy((char *) ctf_get_pos_addr(pos), array_definition->string->str, array_declaration->len); - ctf_move_pos(pos, array_declaration->len * CHAR_BIT); + if (!ctf_move_pos(pos, array_declaration->len * CHAR_BIT)) + return -EFAULT; return 0; } } diff --git a/formats/ctf/types/float.c b/formats/ctf/types/float.c index 9c60b737..b82f68db 100644 --- a/formats/ctf/types/float.c +++ b/formats/ctf/types/float.c @@ -200,8 +200,11 @@ int ctf_float_read(struct bt_stream_pos *ppos, struct bt_definition *definition) ctf_init_pos(&destp, NULL, -1, O_RDWR); mmap_align_set_addr(&mma, (char *) u.bits); destp.base_mma = &mma; - destp.packet_size = sizeof(u) * CHAR_BIT; - ctf_align_pos(pos, float_declaration->p.alignment); + destp.content_size = destp.packet_size = sizeof(u) * CHAR_BIT; + if (!ctf_align_pos(pos, float_declaration->p.alignment)) { + ret = -EFAULT; + goto end_unref; + } ret = _ctf_float_copy(&destp.parent, tmpfloat, ppos, float_definition); switch (float_declaration->mantissa->len + 1) { case FLT_MANT_DIG: @@ -256,7 +259,7 @@ int ctf_float_write(struct bt_stream_pos *ppos, struct bt_definition *definition ctf_init_pos(&srcp, NULL, -1, O_RDONLY); mmap_align_set_addr(&mma, (char *) u.bits); srcp.base_mma = &mma; - srcp.packet_size = sizeof(u) * CHAR_BIT; + srcp.content_size = srcp.packet_size = sizeof(u) * CHAR_BIT; switch (float_declaration->mantissa->len + 1) { case FLT_MANT_DIG: u.vf = float_definition->value; @@ -268,7 +271,10 @@ int ctf_float_write(struct bt_stream_pos *ppos, struct bt_definition *definition ret = -EINVAL; goto end_unref; } - ctf_align_pos(pos, float_declaration->p.alignment); + if (!ctf_align_pos(pos, float_declaration->p.alignment)) { + ret = -EFAULT; + goto end_unref; + } ret = _ctf_float_copy(ppos, float_definition, &srcp.parent, tmpfloat); end_unref: diff --git a/formats/ctf/types/integer.c b/formats/ctf/types/integer.c index 257341ad..189943e6 100644 --- a/formats/ctf/types/integer.c +++ b/formats/ctf/types/integer.c @@ -49,7 +49,8 @@ int _aligned_integer_read(struct bt_stream_pos *ppos, struct ctf_stream_pos *pos = ctf_pos(ppos); int rbo = (integer_declaration->byte_order != BYTE_ORDER); /* reverse byte order */ - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, integer_declaration->len)) return -EFAULT; @@ -136,7 +137,8 @@ int _aligned_integer_read(struct bt_stream_pos *ppos, assert(0); } } - ctf_move_pos(pos, integer_declaration->len); + if (!ctf_move_pos(pos, integer_declaration->len)) + return -EFAULT; return 0; } @@ -151,7 +153,8 @@ int _aligned_integer_write(struct bt_stream_pos *ppos, struct ctf_stream_pos *pos = ctf_pos(ppos); int rbo = (integer_declaration->byte_order != BYTE_ORDER); /* reverse byte order */ - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, integer_declaration->len)) return -EFAULT; @@ -207,7 +210,8 @@ int _aligned_integer_write(struct bt_stream_pos *ppos, } } end: - ctf_move_pos(pos, integer_declaration->len); + if (!ctf_move_pos(pos, integer_declaration->len)) + return -EFAULT; return 0; } @@ -224,7 +228,8 @@ int ctf_integer_read(struct bt_stream_pos *ppos, struct bt_definition *definitio return _aligned_integer_read(ppos, definition); } - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, integer_declaration->len)) return -EFAULT; @@ -252,7 +257,8 @@ int ctf_integer_read(struct bt_stream_pos *ppos, struct bt_definition *definitio pos->offset, integer_declaration->len, &integer_definition->value._signed); } - ctf_move_pos(pos, integer_declaration->len); + if (!ctf_move_pos(pos, integer_declaration->len)) + return -EFAULT; return 0; } @@ -269,7 +275,8 @@ int ctf_integer_write(struct bt_stream_pos *ppos, struct bt_definition *definiti return _aligned_integer_write(ppos, definition); } - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, integer_declaration->len)) return -EFAULT; @@ -300,6 +307,7 @@ int ctf_integer_write(struct bt_stream_pos *ppos, struct bt_definition *definiti integer_definition->value._signed); } end: - ctf_move_pos(pos, integer_declaration->len); + if (!ctf_move_pos(pos, integer_declaration->len)) + return -EFAULT; return 0; } diff --git a/formats/ctf/types/sequence.c b/formats/ctf/types/sequence.c index 898c3672..5dae7d02 100644 --- a/formats/ctf/types/sequence.c +++ b/formats/ctf/types/sequence.c @@ -48,14 +48,16 @@ int ctf_sequence_read(struct bt_stream_pos *ppos, struct bt_definition *definiti && integer_declaration->p.alignment == CHAR_BIT) { uint64_t len = bt_sequence_len(sequence_definition); - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, len * CHAR_BIT)) return -EFAULT; g_string_assign(sequence_definition->string, ""); g_string_insert_len(sequence_definition->string, 0, (char *) ctf_get_pos_addr(pos), len); - ctf_move_pos(pos, len * CHAR_BIT); + if (!ctf_move_pos(pos, len * CHAR_BIT)) + return -EFAULT; return 0; } } @@ -83,13 +85,15 @@ int ctf_sequence_write(struct bt_stream_pos *ppos, struct bt_definition *definit && integer_declaration->p.alignment == CHAR_BIT) { uint64_t len = bt_sequence_len(sequence_definition); - ctf_align_pos(pos, integer_declaration->p.alignment); + if (!ctf_align_pos(pos, integer_declaration->p.alignment)) + return -EFAULT; if (!ctf_pos_access_ok(pos, len * CHAR_BIT)) return -EFAULT; memcpy((char *) ctf_get_pos_addr(pos), sequence_definition->string->str, len); - ctf_move_pos(pos, len * CHAR_BIT); + if (!ctf_move_pos(pos, len * CHAR_BIT)) + return -EFAULT; return 0; } } diff --git a/formats/ctf/types/string.c b/formats/ctf/types/string.c index a2433bf5..002f1b4f 100644 --- a/formats/ctf/types/string.c +++ b/formats/ctf/types/string.c @@ -39,19 +39,21 @@ int ctf_string_read(struct bt_stream_pos *ppos, struct bt_definition *definition string_definition->declaration; struct ctf_stream_pos *pos = ctf_pos(ppos); size_t len; - ssize_t max_len; + ssize_t max_len_bits; char *srcaddr; - ctf_align_pos(pos, string_declaration->p.alignment); + if (!ctf_align_pos(pos, string_declaration->p.alignment)) + return -EFAULT; srcaddr = ctf_get_pos_addr(pos); if (pos->offset == EOF) return -EFAULT; - /* Not counting \0 */ - max_len = pos->packet_size - pos->offset - 1; - if (max_len < 0) + /* Not counting \0. Counting in bits. */ + max_len_bits = pos->packet_size - pos->offset - CHAR_BIT; + if (max_len_bits < 0) return -EFAULT; - len = strnlen(srcaddr, max_len) + 1; /* Add \0 */ + /* Add \0, counting in bytes. */ + len = strnlen(srcaddr, (size_t) max_len_bits / CHAR_BIT) + 1; /* Truncated string, unexpected. Trace probably corrupted. */ if (srcaddr[len - 1] != '\0') return -EFAULT; @@ -64,7 +66,8 @@ int ctf_string_read(struct bt_stream_pos *ppos, struct bt_definition *definition printf_debug("CTF string read %s\n", srcaddr); memcpy(string_definition->value, srcaddr, len); string_definition->len = len; - ctf_move_pos(pos, len * CHAR_BIT); + if (!ctf_move_pos(pos, len * CHAR_BIT)) + return -EFAULT; return 0; } @@ -79,7 +82,8 @@ int ctf_string_write(struct bt_stream_pos *ppos, size_t len; char *destaddr; - ctf_align_pos(pos, string_declaration->p.alignment); + if (!ctf_align_pos(pos, string_declaration->p.alignment)) + return -EFAULT; assert(string_definition->value != NULL); len = string_definition->len; @@ -91,6 +95,7 @@ int ctf_string_write(struct bt_stream_pos *ppos, destaddr = ctf_get_pos_addr(pos); memcpy(destaddr, string_definition->value, len); end: - ctf_move_pos(pos, len * CHAR_BIT); + if (!ctf_move_pos(pos, len * CHAR_BIT)) + return -EFAULT; return 0; } diff --git a/formats/ctf/types/struct.c b/formats/ctf/types/struct.c index 106f682c..cbf53c1e 100644 --- a/formats/ctf/types/struct.c +++ b/formats/ctf/types/struct.c @@ -33,6 +33,7 @@ int ctf_struct_rw(struct bt_stream_pos *ppos, struct bt_definition *definition) struct bt_declaration *declaration = definition->declaration; struct ctf_stream_pos *pos = ctf_pos(ppos); - ctf_align_pos(pos, declaration->alignment); + if (!ctf_align_pos(pos, declaration->alignment)) + return -EFAULT; return bt_struct_rw(ppos, definition); } diff --git a/formats/ctf/types/variant.c b/formats/ctf/types/variant.c index b3d6396a..fc7b7ad4 100644 --- a/formats/ctf/types/variant.c +++ b/formats/ctf/types/variant.c @@ -33,6 +33,7 @@ int ctf_variant_rw(struct bt_stream_pos *ppos, struct bt_definition *definition) struct bt_declaration *declaration = definition->declaration; struct ctf_stream_pos *pos = ctf_pos(ppos); - ctf_align_pos(pos, declaration->alignment); + if (!ctf_align_pos(pos, declaration->alignment)) + return -EFAULT; return bt_variant_rw(ppos, definition); } diff --git a/formats/ctf/writer/event-fields.c b/formats/ctf/writer/event-fields.c index 7a37aaf9..c4d1b968 100644 --- a/formats/ctf/writer/event-fields.c +++ b/formats/ctf/writer/event-fields.c @@ -179,8 +179,8 @@ struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type) } type_id = bt_ctf_field_type_get_type_id(type); - if (type_id <= CTF_TYPE_UNKNOWN || - type_id >= NR_CTF_TYPES) { + if (type_id <= CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES || + bt_ctf_field_type_validate(type)) { goto error; } @@ -247,13 +247,14 @@ int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field, bt_ctf_field_put(sequence->length); } - sequence->elements = g_ptr_array_new_full((size_t)sequence_length, - (GDestroyNotify)bt_ctf_field_put); + sequence->elements = g_ptr_array_sized_new((size_t)sequence_length); if (!sequence->elements) { ret = -1; goto end; } + g_ptr_array_set_free_func(sequence->elements, + (GDestroyNotify)bt_ctf_field_put); g_ptr_array_set_size(sequence->elements, (size_t)sequence_length); bt_ctf_field_get(length_field); sequence->length = length_field; @@ -768,12 +769,13 @@ struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type) array_type = container_of(type, struct bt_ctf_field_type_array, parent); array_length = array_type->length; - array->elements = g_ptr_array_new_full(array_length, - (GDestroyNotify)bt_ctf_field_put); + array->elements = g_ptr_array_sized_new(array_length); if (!array->elements) { goto error; } + g_ptr_array_set_free_func(array->elements, + (GDestroyNotify)bt_ctf_field_put); g_ptr_array_set_size(array->elements, array_length); return &array->parent; error: @@ -1123,10 +1125,16 @@ int bt_ctf_field_structure_serialize(struct bt_ctf_field *field, while (!ctf_pos_access_ok(pos, offset_align(pos->offset, field->type->declaration->alignment))) { - increase_packet_size(pos); + ret = increase_packet_size(pos); + if (ret) { + goto end; + } } - ctf_align_pos(pos, field->type->declaration->alignment); + if (!ctf_align_pos(pos, field->type->declaration->alignment)) { + ret = -1; + goto end; + } for (i = 0; i < structure->fields->len; i++) { struct bt_ctf_field *field = g_ptr_array_index( @@ -1137,7 +1145,7 @@ int bt_ctf_field_structure_serialize(struct bt_ctf_field *field, break; } } - +end: return ret; } diff --git a/formats/ctf/writer/event-types.c b/formats/ctf/writer/event-types.c index 091b3209..7f7fa762 100644 --- a/formats/ctf/writer/event-types.c +++ b/formats/ctf/writer/event-types.c @@ -33,6 +33,7 @@ #include #include #include +#include struct range_overlap_query { int64_t range_start, range_end; @@ -214,8 +215,8 @@ int add_structure_field(GPtrArray *fields, struct structure_field *field; /* Make sure structure does not contain a field of the same name */ - if (g_hash_table_contains(field_name_to_index, - GUINT_TO_POINTER(name_quark))) { + if (g_hash_table_lookup_extended(field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, NULL)) { ret = -1; goto end; } @@ -238,6 +239,27 @@ end: return ret; } +BT_HIDDEN +int bt_ctf_field_type_validate(struct bt_ctf_field_type *type) +{ + int ret = 0; + + if (!type) { + ret = -1; + goto end; + } + + if (type->declaration->id == CTF_TYPE_ENUM) { + struct bt_ctf_field_type_enumeration *enumeration = + container_of(type, struct bt_ctf_field_type_enumeration, + parent); + + ret = enumeration->entries->len ? 0 : -1; + } +end: + return ret; +} + struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size) { struct bt_ctf_field_type_integer *integer = @@ -364,6 +386,7 @@ int bt_ctf_field_type_enumeration_add_mapping( struct enumeration_mapping *mapping; struct bt_ctf_field_type_enumeration *enumeration; struct range_overlap_query query; + char *escaped_string; if (!type || (type->declaration->id != CTF_TYPE_ENUM) || type->frozen || @@ -372,12 +395,18 @@ int bt_ctf_field_type_enumeration_add_mapping( goto end; } - if (validate_identifier(string)) { + if (!string || strlen(string) == 0) { ret = -1; goto end; } - mapping_name = g_quark_from_string(string); + escaped_string = g_strescape(string, NULL); + if (!escaped_string) { + ret = -1; + goto end; + } + + mapping_name = g_quark_from_string(escaped_string); query = (struct range_overlap_query) { .range_start = range_start, .range_end = range_end, .mapping_name = mapping_name, @@ -389,18 +418,20 @@ int bt_ctf_field_type_enumeration_add_mapping( g_ptr_array_foreach(enumeration->entries, check_ranges_overlap, &query); if (query.overlaps) { ret = -1; - goto end; + goto error_free; } mapping = g_new(struct enumeration_mapping, 1); if (!mapping) { ret = -1; - goto end; + goto error_free; } *mapping = (struct enumeration_mapping) {.range_start = range_start, .range_end = range_end, .string = mapping_name}; g_ptr_array_add(enumeration->entries, mapping); +error_free: + free(escaped_string); end: return ret; } @@ -517,7 +548,8 @@ int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *type, if (!type || !field_type || type->frozen || validate_identifier(field_name) || - (type->declaration->id != CTF_TYPE_STRUCT)) { + (type->declaration->id != CTF_TYPE_STRUCT) || + bt_ctf_field_type_validate(field_type)) { goto end; } @@ -579,7 +611,8 @@ int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type, if (!type || !field_type || type->frozen || validate_identifier(field_name) || - (type->declaration->id != CTF_TYPE_VARIANT)) { + (type->declaration->id != CTF_TYPE_VARIANT) || + bt_ctf_field_type_validate(field_type)) { ret = -1; goto end; } @@ -611,7 +644,8 @@ struct bt_ctf_field_type *bt_ctf_field_type_array_create( { struct bt_ctf_field_type_array *array = NULL; - if (!element_type || length == 0) { + if (!element_type || length == 0 || + bt_ctf_field_type_validate(element_type)) { goto error; } @@ -639,7 +673,8 @@ struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( { struct bt_ctf_field_type_sequence *sequence = NULL; - if (!element_type || validate_identifier(length_field_name)) { + if (!element_type || validate_identifier(length_field_name) || + bt_ctf_field_type_validate(element_type)) { goto error; } @@ -1154,10 +1189,15 @@ int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, struct metadata_context *context) { size_t entry; - int ret = 0; + int ret; struct bt_ctf_field_type_enumeration *enumeration = container_of(type, struct bt_ctf_field_type_enumeration, parent); + ret = bt_ctf_field_type_validate(type); + if (ret) { + goto end; + } + g_string_append(context->string, "enum : "); ret = bt_ctf_field_type_serialize(enumeration->container, context); if (ret) { @@ -1170,12 +1210,13 @@ int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, enumeration->entries->pdata[entry]; if (mapping->range_start == mapping->range_end) { - g_string_append_printf(context->string, "%s = %" PRId64, + g_string_append_printf(context->string, + "\"%s\" = %" PRId64, g_quark_to_string(mapping->string), mapping->range_start); } else { g_string_append_printf(context->string, - "%s = %" PRId64 " ... %" PRId64, + "\"%s\" = %" PRId64 " ... %" PRId64, g_quark_to_string(mapping->string), mapping->range_start, mapping->range_end); } diff --git a/formats/ctf/writer/stream.c b/formats/ctf/writer/stream.c index f03f170d..ac894297 100644 --- a/formats/ctf/writer/stream.c +++ b/formats/ctf/writer/stream.c @@ -368,7 +368,7 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) int ret = 0; size_t i; uint64_t timestamp_begin, timestamp_end; - struct bt_ctf_stream_class *stream_class = stream->stream_class; + struct bt_ctf_stream_class *stream_class; struct bt_ctf_field *integer = NULL; struct ctf_stream_pos packet_context_pos; @@ -385,6 +385,7 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream) stream->flush.func(stream, stream->flush.data); } + stream_class = stream->stream_class; timestamp_begin = ((struct bt_ctf_event *) g_ptr_array_index( stream->events, 0))->timestamp; timestamp_end = ((struct bt_ctf_event *) g_ptr_array_index( @@ -518,7 +519,9 @@ void bt_ctf_stream_destroy(struct bt_ctf_ref *ref) stream = container_of(ref, struct bt_ctf_stream, ref_count); ctf_fini_pos(&stream->pos); - close(stream->pos.fd); + if (close(stream->pos.fd)) { + perror("close"); + } bt_ctf_stream_class_put(stream->stream_class); g_ptr_array_free(stream->events, TRUE); g_free(stream); diff --git a/formats/ctf/writer/writer.c b/formats/ctf/writer/writer.c index 5600a92a..a3ca263a 100644 --- a/formats/ctf/writer/writer.c +++ b/formats/ctf/writer/writer.c @@ -560,8 +560,9 @@ int validate_identifier(const char *input_string) token = strtok_r(string, " ", &save_ptr); while (token) { - if (g_hash_table_contains(reserved_keywords_set, - GINT_TO_POINTER(g_quark_from_string(token)))) { + if (g_hash_table_lookup_extended(reserved_keywords_set, + GINT_TO_POINTER(g_quark_from_string(token)), + NULL, NULL)) { ret = -1; goto end; } @@ -737,8 +738,10 @@ void writer_init(void) reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal); for (i = 0; i < reserved_keywords_count; i++) { - g_hash_table_add(reserved_keywords_set, - GINT_TO_POINTER(g_quark_from_string(reserved_keywords_str[i]))); + gpointer quark = GINT_TO_POINTER(g_quark_from_string( + reserved_keywords_str[i])); + + g_hash_table_insert(reserved_keywords_set, quark, quark); } init_done = 1; diff --git a/include/Makefile.am b/include/Makefile.am index ec927b91..d9996a7b 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -38,6 +38,7 @@ noinst_HEADERS = \ babeltrace/ctf-text/types.h \ babeltrace/ctf/types.h \ babeltrace/ctf/callbacks-internal.h \ + babeltrace/ctf/ctf-index.h \ babeltrace/ctf-writer/ref-internal.h \ babeltrace/ctf-writer/writer-internal.h \ babeltrace/ctf-writer/event-types-internal.h \ diff --git a/include/babeltrace/ctf-writer/event-types-internal.h b/include/babeltrace/ctf-writer/event-types-internal.h index d9acdd35..a937c780 100644 --- a/include/babeltrace/ctf-writer/event-types-internal.h +++ b/include/babeltrace/ctf-writer/event-types-internal.h @@ -147,4 +147,7 @@ BT_HIDDEN int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, struct metadata_context *context); +BT_HIDDEN +int bt_ctf_field_type_validate(struct bt_ctf_field_type *type); + #endif /* BABELTRACE_CTF_WRITER_EVENT_TYPES_INTERNAL_H */ diff --git a/include/babeltrace/ctf/ctf-index.h b/include/babeltrace/ctf/ctf-index.h new file mode 100644 index 00000000..0efa8887 --- /dev/null +++ b/include/babeltrace/ctf/ctf-index.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 - Julien Desfossez + * Mathieu Desnoyers + * David Goulet + * + * 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. + */ + +#ifndef LTTNG_INDEX_H +#define LTTNG_INDEX_H + +#include + +#define CTF_INDEX_MAGIC 0xC1F1DCC1 +#define CTF_INDEX_MAJOR 1 +#define CTF_INDEX_MINOR 0 + +/* + * Header at the beginning of each index file. + * All integer fields are stored in big endian. + */ +struct ctf_packet_index_file_hdr { + uint32_t magic; + uint32_t index_major; + uint32_t index_minor; + /* struct packet_index_len, in bytes */ + uint32_t packet_index_len; +} __attribute__((__packed__)); + +/* + * Packet index generated for each trace packet store in a trace file. + * All integer fields are stored in big endian. + */ +struct ctf_packet_index { + uint64_t offset; /* offset of the packet in the file, in bytes */ + uint64_t packet_size; /* packet size, in bits */ + uint64_t content_size; /* content size, in bits */ + uint64_t timestamp_begin; + uint64_t timestamp_end; + uint64_t events_discarded; + uint64_t stream_id; +} __attribute__((__packed__)); + +#endif /* LTTNG_INDEX_H */ diff --git a/include/babeltrace/ctf/types.h b/include/babeltrace/ctf/types.h index 96c5083c..e90464dc 100644 --- a/include/babeltrace/ctf/types.h +++ b/include/babeltrace/ctf/types.h @@ -61,6 +61,7 @@ struct packet_index { struct ctf_stream_pos { struct bt_stream_pos parent; int fd; /* backing file fd. -1 if unset. */ + FILE *index_fp; /* backing index file fp. NULL if unset. */ GArray *packet_cycles_index; /* contains struct packet_index in cycles */ GArray *packet_real_index; /* contains struct packet_index in ns */ int prot; /* mmap protection */ @@ -128,28 +129,41 @@ int ctf_fini_pos(struct ctf_stream_pos *pos); /* * move_pos - move position of a relative bit offset * + * Return 1 if OK, 0 if out-of-bound. + * * TODO: allow larger files by updating base too. */ static inline -void ctf_move_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) +int ctf_move_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) { + uint64_t max_len; + printf_debug("ctf_move_pos test EOF: %" PRId64 "\n", pos->offset); if (unlikely(pos->offset == EOF)) - return; + return 0; + if (pos->prot == PROT_READ) + max_len = pos->content_size; + else + max_len = pos->packet_size; + if (unlikely(pos->offset + bit_offset > max_len)) + return 0; pos->offset += bit_offset; printf_debug("ctf_move_pos after increment: %" PRId64 "\n", pos->offset); + return 1; } /* * align_pos - align position on a bit offset (> 0) * + * Return 1 if OK, 0 if out-of-bound. + * * TODO: allow larger files by updating base too. */ static inline -void ctf_align_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) +int ctf_align_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) { - ctf_move_pos(pos, offset_align(pos->offset, bit_offset)); + return ctf_move_pos(pos, offset_align(pos->offset, bit_offset)); } static inline @@ -190,15 +204,21 @@ void ctf_pos_pad_packet(struct ctf_stream_pos *pos) static inline int ctf_pos_access_ok(struct ctf_stream_pos *pos, uint64_t bit_len) { + uint64_t max_len; + if (unlikely(pos->offset == EOF)) return 0; - if (unlikely(pos->offset + bit_len > pos->packet_size)) + if (pos->prot == PROT_READ) + max_len = pos->content_size; + else + max_len = pos->packet_size; + if (unlikely(pos->offset + bit_len > max_len)) return 0; return 1; } /* - * Update the stream position for to the current event. This moves to + * Update the stream position to the current event. This moves to * the next packet if we are located at the end of the current packet. */ static inline diff --git a/lib/iterator.c b/lib/iterator.c index 966a0001..a2a7bb57 100644 --- a/lib/iterator.c +++ b/lib/iterator.c @@ -65,6 +65,9 @@ static int stream_read_event(struct ctf_file_stream *sin) ret = sin->pos.parent.event_cb(&sin->pos.parent, &sin->parent); if (ret == EOF) return EOF; + else if (ret == EAGAIN) + /* Stream is inactive for now (live reading). */ + return EAGAIN; else if (ret) { fprintf(stderr, "[error] Reading event failed.\n"); return ret; @@ -716,7 +719,7 @@ int bt_iter_init(struct bt_iter *iter, if (ret == EOF) { ret = 0; continue; - } else if (ret) { + } else if (ret != 0 && ret != EAGAIN) { goto error; } /* Add to heap */ @@ -801,13 +804,28 @@ int bt_iter_next(struct bt_iter *iter) assert(removed == file_stream); ret = 0; goto end; + } else if (ret == EAGAIN) { + /* + * The stream is inactive for now, we just updated the timestamp_end + * to skip over this stream up to a certain point in time. + */ + goto reinsert; } else if (ret) { goto end; } + +reinsert: /* Reinsert the file stream into the heap, and rebalance. */ removed = bt_heap_replace_max(iter->stream_heap, file_stream); assert(removed == file_stream); + file_stream = bt_heap_maximum(iter->stream_heap); + if (file_stream->pos.content_size == 0) { + ret = EAGAIN; + } else { + ret = 0; + } + end: return ret; } diff --git a/tests/lib/test_ctf_writer.c b/tests/lib/test_ctf_writer.c index d55c6297..0927a325 100644 --- a/tests/lib/test_ctf_writer.c +++ b/tests/lib/test_ctf_writer.c @@ -254,13 +254,30 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, bt_ctf_field_type_integer_create(12); struct bt_ctf_field_type *float_type = bt_ctf_field_type_floating_point_create(); + struct bt_ctf_field_type *enum_type = + bt_ctf_field_type_enumeration_create(uint_12_type); struct bt_ctf_event *simple_event; struct bt_ctf_field *integer_field; struct bt_ctf_field *float_field; + struct bt_ctf_field *enum_field; + struct bt_ctf_field *enum_container_field; bt_ctf_field_type_set_alignment(float_type, 32); bt_ctf_field_type_floating_point_set_exponent_digits(float_type, 11); bt_ctf_field_type_floating_point_set_mantissa_digits(float_type, 53); + + ok(bt_ctf_field_type_enumeration_add_mapping(enum_type, + "escaping; \"test\"", 0, 0) == 0, + "Accept enumeration mapping strings containing quotes"); + ok(bt_ctf_field_type_enumeration_add_mapping(enum_type, + "\tanother \'escaping\'\n test\"", 1, 4) == 0, + "Accept enumeration mapping strings containing special characters"); + ok(bt_ctf_field_type_enumeration_add_mapping(enum_type, + "event clock int float", 5, 22) == 0, + "Accept enumeration mapping strings containing reserved keywords"); + ok(bt_ctf_event_class_add_field(simple_event_class, enum_type, + "enum_field") == 0, "Add enumeration field to event"); + ok(uint_12_type, "Create an unsigned integer type"); bt_ctf_event_class_add_field(simple_event_class, uint_12_type, "integer_field"); @@ -281,6 +298,13 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, float_field = bt_ctf_event_get_payload(simple_event, "float_field"); bt_ctf_field_floating_point_set_value(float_field, 3.1415); + enum_field = bt_ctf_field_create(enum_type); + enum_container_field = bt_ctf_field_enumeration_get_container( + enum_field); + ok(bt_ctf_field_unsigned_integer_set_value( + enum_container_field, 1) == 0, + "Set enumeration container value"); + bt_ctf_event_set_payload(simple_event, "enum_field", enum_field); ok(bt_ctf_clock_set_time(clock, current_time) == 0, "Set clock time"); @@ -294,8 +318,11 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, bt_ctf_event_put(simple_event); bt_ctf_field_type_put(uint_12_type); bt_ctf_field_type_put(float_type); + bt_ctf_field_type_put(enum_type); bt_ctf_field_put(integer_field); bt_ctf_field_put(float_field); + bt_ctf_field_put(enum_field); + bt_ctf_field_put(enum_container_field); } void append_complex_event(struct bt_ctf_stream_class *stream_class, @@ -469,6 +496,7 @@ void type_field_tests() struct bt_ctf_field *uint_12; struct bt_ctf_field *int_16; struct bt_ctf_field *string; + struct bt_ctf_field *enumeration; struct bt_ctf_field_type *composite_structure_type; struct bt_ctf_field_type *structure_seq_type; struct bt_ctf_field_type *string_type; @@ -477,6 +505,9 @@ void type_field_tests() struct bt_ctf_field_type *int_16_type; struct bt_ctf_field_type *uint_12_type = bt_ctf_field_type_integer_create(12); + struct bt_ctf_field_type *enumeration_type; + struct bt_ctf_field_type *enumeration_sequence_type; + struct bt_ctf_field_type *enumeration_array_type; ok(uint_12_type, "Create an unsigned integer type"); ok(bt_ctf_field_type_integer_set_base(uint_12_type, @@ -578,9 +609,28 @@ void type_field_tests() ok(bt_ctf_field_string_set_value(string, "A value") == 0, "Set a string's value"); + enumeration_type = bt_ctf_field_type_enumeration_create(uint_12_type); + ok(enumeration_type, + "Create an enumeration type with an unsigned 12-bit integer as container"); + enumeration_sequence_type = bt_ctf_field_type_sequence_create( + enumeration_type, "count"); + ok(!enumeration_sequence_type, + "Check enumeration types are validated when creating a sequence"); + enumeration_array_type = bt_ctf_field_type_array_create( + enumeration_type, 10); + ok(!enumeration_array_type, + "Check enumeration types are validated when creating an array"); + ok(bt_ctf_field_type_structure_add_field(composite_structure_type, + enumeration_type, "enumeration") == 0, + "Check enumeration types are validated when adding them as structure members"); + enumeration = bt_ctf_field_create(enumeration_type); + ok(!enumeration, + "Check enumeration types are validated before instantiation"); + bt_ctf_field_put(string); bt_ctf_field_put(uint_12); bt_ctf_field_put(int_16); + bt_ctf_field_put(enumeration); bt_ctf_field_type_put(composite_structure_type); bt_ctf_field_type_put(structure_seq_type); bt_ctf_field_type_put(string_type); @@ -588,6 +638,9 @@ void type_field_tests() bt_ctf_field_type_put(uint_8_type); bt_ctf_field_type_put(int_16_type); bt_ctf_field_type_put(uint_12_type); + bt_ctf_field_type_put(enumeration_type); + bt_ctf_field_type_put(enumeration_sequence_type); + bt_ctf_field_type_put(enumeration_array_type); } void packet_resize_test(struct bt_ctf_stream_class *stream_class,