/* 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
/* 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
}
}
/* 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
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);
}
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
#include <babeltrace/context-internal.h>
#include <babeltrace/compat/uuid.h>
#include <babeltrace/endian.h>
+#include <babeltrace/ctf/ctf-index.h>
#include <inttypes.h>
#include <stdio.h>
#include <sys/mman.h>
#define NSEC_PER_SEC 1000000000ULL
+#define INDEX_PATH "./index/%s.idx"
+
int opt_clock_cycles,
opt_clock_seconds,
opt_clock_date,
*/
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 */
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;
}
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 */
}
} 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 */
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;
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).
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) {
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';
* 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) {
struct dirent *dirent;
struct dirent *diriter;
size_t dirent_len;
+ char *ext;
td->flags = flags;
|| !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) {
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;
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().
+ */
}
}
}
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;
}
}
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:
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;
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:
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;
assert(0);
}
}
- ctf_move_pos(pos, integer_declaration->len);
+ if (!ctf_move_pos(pos, integer_declaration->len))
+ return -EFAULT;
return 0;
}
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;
}
}
end:
- ctf_move_pos(pos, integer_declaration->len);
+ if (!ctf_move_pos(pos, integer_declaration->len))
+ return -EFAULT;
return 0;
}
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;
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;
}
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;
integer_definition->value._signed);
}
end:
- ctf_move_pos(pos, integer_declaration->len);
+ if (!ctf_move_pos(pos, integer_declaration->len))
+ return -EFAULT;
return 0;
}
&& 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;
}
}
&& 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;
}
}
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;
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;
}
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;
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;
}
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);
}
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);
}
}
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;
}
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;
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:
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(
break;
}
}
-
+end:
return ret;
}
#include <babeltrace/endian.h>
#include <float.h>
#include <inttypes.h>
+#include <stdlib.h>
struct range_overlap_query {
int64_t range_start, range_end;
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;
}
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 =
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 ||
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,
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;
}
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;
}
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;
}
{
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;
}
{
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;
}
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) {
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);
}
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;
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(
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);
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;
}
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;
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 \
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 */
--- /dev/null
+/*
+ * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
+ * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * David Goulet <dgoulet@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.
+ */
+
+#ifndef LTTNG_INDEX_H
+#define LTTNG_INDEX_H
+
+#include <limits.h>
+
+#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 */
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 */
/*
* 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
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
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;
if (ret == EOF) {
ret = 0;
continue;
- } else if (ret) {
+ } else if (ret != 0 && ret != EAGAIN) {
goto error;
}
/* Add to heap */
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;
}
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");
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");
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,
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;
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,
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);
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,