From: Julien Desfossez Date: Tue, 14 Feb 2017 17:03:00 +0000 (-0500) Subject: Override clock fields in copied traces X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=b2f1f465086eb82ac6b1a57538b643fdced00ac5;p=deliverable%2Fbabeltrace.git Override clock fields in copied traces Some tracers like LTTng use a compression scheme on the timestamp field to avoid writing the full 64-bit timestamp at every event. When the trace is complete, the reader has all the information to understand this compression, but if a trace is filtered or truncated, there might be some state information missing. Since we don't know in advance if a compression scheme is used in a trace, we now force the copied traces to have a full 64-bit timestamp. The user of this library can decide whether or not to override the type of the clock fields. Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- diff --git a/plugins/libctfcopytrace/Makefile.am b/plugins/libctfcopytrace/Makefile.am index 2b2b813f3..3fe8a1204 100644 --- a/plugins/libctfcopytrace/Makefile.am +++ b/plugins/libctfcopytrace/Makefile.am @@ -4,7 +4,7 @@ SUBDIRS = . lib_LTLIBRARIES = libctfcopytrace.la -libctfcopytrace_la_SOURCES = ctfcopytrace.c +libctfcopytrace_la_SOURCES = ctfcopytrace.c clock-fields.c libctfcopytrace_la_LDFLAGS = -version-info $(BABELTRACE_LIBRARY_VERSION) @@ -12,4 +12,4 @@ libctfcopytrace_la_LIBADD = \ $(top_builddir)/lib/libbabeltrace.la \ $(top_builddir)/formats/ctf/libbabeltrace-ctf.la -noinst_HEADERS = ctfcopytrace.h +noinst_HEADERS = ctfcopytrace.h clock-fields.h diff --git a/plugins/libctfcopytrace/clock-fields.c b/plugins/libctfcopytrace/clock-fields.c new file mode 100644 index 000000000..86f4f28bd --- /dev/null +++ b/plugins/libctfcopytrace/clock-fields.c @@ -0,0 +1,925 @@ +/* + * clock-fields.c + * + * Babeltrace - Update clock fields to write uint64 values + * + * Copyright 2017 Julien Desfossez + * + * Author: Julien Desfossez + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clock-fields.h" + +static +int find_update_struct_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class); +static +int find_update_array_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class); +static +int find_update_enum_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class); +static +int find_update_sequence_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class); +static +int find_update_variant_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class); + +static +int copy_find_clock_int_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field); +static +int copy_find_clock_struct_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field); +static +int copy_find_clock_array_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field); +static +int copy_find_clock_sequence_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field); +static +int copy_find_clock_variant_field(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event *writer_event, struct bt_ctf_field *field, + struct bt_ctf_field_type *type, struct bt_ctf_field *copy_field); +static +int copy_find_clock_enum_field(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event *writer_event, struct bt_ctf_field *field, + struct bt_ctf_field_type *type, struct bt_ctf_field *copy_field); + +static +int update_header_clock_int_field_type(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class) +{ + struct bt_ctf_clock_class *clock; + int ret; + + clock = bt_ctf_field_type_integer_get_mapped_clock_class(type); + if (!clock) { + return 0; + } + bt_put(clock); + + ret = bt_ctf_field_type_integer_set_size(type, 64); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_field_type_integer_set_mapped_clock_class(type, + writer_clock_class); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + +end: + return ret; +} + +static +int find_update_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class) +{ + int ret; + + switch (bt_ctf_field_type_get_type_id(type)) { + case BT_CTF_TYPE_ID_INTEGER: + return update_header_clock_int_field_type(err, type, + writer_clock_class); + case BT_CTF_TYPE_ID_STRUCT: + return find_update_struct_clock_fields(err, type, + writer_clock_class); + case BT_CTF_TYPE_ID_ARRAY: + return find_update_array_clock_fields(err, type, + writer_clock_class); + case BT_CTF_TYPE_ID_SEQUENCE: + return find_update_sequence_clock_fields(err, type, + writer_clock_class); + case BT_CTF_TYPE_ID_UNTAGGED_VARIANT: + case BT_CTF_TYPE_ID_VARIANT: + return find_update_variant_clock_fields(err, type, + writer_clock_class); + case BT_CTF_TYPE_ID_ENUM: + return find_update_enum_clock_fields(err, type, + writer_clock_class); + break; + default: + break; + } + + ret = 0; + + return ret; +} + +static +int find_update_variant_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class) +{ + int count, i, ret; + + count = bt_ctf_field_type_variant_get_field_count(type); + for (i = 0; i < count; i++) { + struct bt_ctf_field_type *entry_type; + const char *entry_name; + + ret = bt_ctf_field_type_variant_get_field(type, + &entry_name, &entry_type, i); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = -1; + goto end; + } + ret = find_update_clock_fields(err, entry_type, + writer_clock_class); + bt_put(entry_type); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = -1; + goto end; + } + } + + ret = 0; + +end: + return ret; +} + +static +int find_update_struct_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class) +{ + int count, i, ret; + + count = bt_ctf_field_type_structure_get_field_count(type); + for (i = 0; i < count; i++) { + struct bt_ctf_field_type *entry_type; + const char *entry_name; + + ret = bt_ctf_field_type_structure_get_field(type, + &entry_name, &entry_type, i); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = -1; + goto end; + } + ret = find_update_clock_fields(err, entry_type, + writer_clock_class); + bt_put(entry_type); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = -1; + goto end; + } + } + + ret = 0; + +end: + return ret; +} + +static +int find_update_sequence_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class) +{ + int ret; + struct bt_ctf_field_type *entry_type; + + entry_type = bt_ctf_field_type_sequence_get_element_type(type); + ret = find_update_clock_fields(err, entry_type, writer_clock_class); + bt_put(entry_type); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = 0; + +end: + return ret; +} + +static +int find_update_array_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class) +{ + int ret; + struct bt_ctf_field_type *entry_type; + + entry_type = bt_ctf_field_type_array_get_element_type(type); + ret = find_update_clock_fields(err, entry_type, writer_clock_class); + bt_put(entry_type); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = 0; + +end: + return ret; +} + +static +int find_update_enum_clock_fields(FILE *err, struct bt_ctf_field_type *type, + struct bt_ctf_clock_class *writer_clock_class) +{ + int ret; + struct bt_ctf_field_type *entry_type; + + entry_type = bt_ctf_field_type_enumeration_get_container_type(type); + ret = find_update_clock_fields(err, entry_type, writer_clock_class); + bt_put(entry_type); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + ret = -1; + goto end; + } + + ret = 0; + +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_field_type *override_header_type(FILE *err, + struct bt_ctf_field_type *type, + struct bt_ctf_trace *writer_trace) +{ + struct bt_ctf_field_type *new_type = NULL; + int ret; + struct bt_ctf_clock_class *writer_clock_class; + + /* FIXME multi-clock? */ + writer_clock_class = bt_ctf_trace_get_clock_class(writer_trace, 0); + if (!writer_clock_class) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + new_type = bt_ctf_field_type_copy(type); + if (!new_type) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put; + } + + if (bt_ctf_field_type_get_type_id(new_type) != BT_CTF_TYPE_ID_STRUCT) { + fprintf(err, "[error] Unexpected header field type\n"); + goto error; + } + + ret = find_update_struct_clock_fields(err, new_type, writer_clock_class); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto error; + } + + goto end_put; + +error: + BT_PUT(new_type); +end_put: + bt_put(writer_clock_class); +end: + return new_type; +} + +static +int copy_float_field(FILE *err, struct bt_ctf_field *field, + struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field) +{ + double value; + int ret; + + ret = bt_ctf_field_floating_point_get_value(field, &value); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + ret = bt_ctf_field_floating_point_set_value(copy_field, value); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + ret = 0; + +end: + return ret; +} + +static +int copy_string_field(FILE *err, struct bt_ctf_field *field, + struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field) +{ + const char *value; + int ret; + + value = bt_ctf_field_string_get_value(field); + if (!value) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + ret = bt_ctf_field_string_set_value(copy_field, value); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + + ret = 0; + +end: + return ret; +} + +BT_HIDDEN +int copy_override_field(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event *writer_event, struct bt_ctf_field *field, + struct bt_ctf_field *copy_field) +{ + struct bt_ctf_field_type *type; + int ret; + + type = bt_ctf_field_get_type(field); + if (!type) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + switch (bt_ctf_field_type_get_type_id(type)) { + case BT_CTF_TYPE_ID_INTEGER: + ret = copy_find_clock_int_field(err, event, writer_event, + field, type, copy_field); + break; + case BT_CTF_TYPE_ID_STRUCT: + ret = copy_find_clock_struct_field(err, event, writer_event, + field, type, copy_field); + break; + case BT_CTF_TYPE_ID_FLOAT: + ret = copy_float_field(err, field, type, copy_field); + break; + case BT_CTF_TYPE_ID_ENUM: + ret = copy_find_clock_enum_field(err, event, writer_event, + field, type, copy_field); + break; + case BT_CTF_TYPE_ID_STRING: + ret = copy_string_field(err, field, type, copy_field); + break; + case BT_CTF_TYPE_ID_ARRAY: + ret = copy_find_clock_array_field(err, event, writer_event, + field, type, copy_field); + break; + case BT_CTF_TYPE_ID_SEQUENCE: + ret = copy_find_clock_sequence_field(err, event, writer_event, + field, type, copy_field); + break; + case BT_CTF_TYPE_ID_UNTAGGED_VARIANT: + case BT_CTF_TYPE_ID_VARIANT: + ret = copy_find_clock_variant_field(err, event, writer_event, + field, type, copy_field); + break; + /* No default, we want to catch missing field types. */ + case BT_CTF_TYPE_ID_UNKNOWN: + case BT_CTF_NR_TYPE_IDS: + break; + } + + ret = 0; + bt_put(type); + +end: + return ret; +} + +static +int copy_find_clock_enum_field(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event *writer_event, struct bt_ctf_field *field, + struct bt_ctf_field_type *type, struct bt_ctf_field *copy_field) +{ + int ret; + struct bt_ctf_field *container, *copy_container; + + container = bt_ctf_field_enumeration_get_container(field); + if (!container) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + copy_container = bt_ctf_field_enumeration_get_container(copy_field); + if (!copy_container) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_container; + } + + ret = copy_override_field(err, event, writer_event, container, + copy_container); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_copy_container; + } + +end_put_copy_container: + bt_put(copy_container); +end_put_container: + bt_put(container); +end: + return ret; +} + +static +int copy_find_clock_variant_field(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event *writer_event, struct bt_ctf_field *field, + struct bt_ctf_field_type *type, struct bt_ctf_field *copy_field) +{ + int ret; + struct bt_ctf_field *tag; + struct bt_ctf_field *variant_field, *copy_variant_field; + + tag = bt_ctf_field_variant_get_tag(field); + if (!tag) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + variant_field = bt_ctf_field_variant_get_field(field, tag); + if (!variant_field) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_tag; + } + + copy_variant_field = bt_ctf_field_variant_get_field(copy_field, tag); + if (!copy_variant_field) { + bt_put(variant_field); + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_variant_field; + } + + ret = copy_override_field(err, event, writer_event, variant_field, + copy_variant_field); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_copy_variand_field; + } + + ret = 0; + +end_put_copy_variand_field: + bt_put(copy_variant_field); +end_put_variant_field: + bt_put(variant_field); +end_put_tag: + bt_put(tag); +end: + return ret; +} + +static +int copy_find_clock_sequence_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field) +{ + int ret; + uint64_t i, count; + struct bt_ctf_field_type *entry_type; + struct bt_ctf_field *length_field; + + entry_type = bt_ctf_field_type_sequence_get_element_type(type); + if (!entry_type) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + length_field = bt_ctf_field_sequence_get_length(field); + if (!length_field) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_field_unsigned_integer_get_value(length_field, &count); + if (ret) { + bt_put(length_field); + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_field_sequence_set_length(copy_field, length_field); + bt_put(length_field); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + for (i = 0; i < count; i++) { + struct bt_ctf_field *entry_field, *entry_copy; + + entry_field = bt_ctf_field_sequence_get_field(field, i); + if (!entry_field) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + entry_copy = bt_ctf_field_sequence_get_field(copy_field, i); + if (!entry_copy) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = copy_override_field(err, event, writer_event, entry_field, + entry_copy); + bt_put(entry_field); + bt_put(entry_copy); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + } + + bt_put(entry_type); + ret = 0; + +end: + return ret; +} + +static +int copy_find_clock_array_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field) +{ + int ret, count, i; + struct bt_ctf_field_type *entry_type; + + count = bt_ctf_field_type_array_get_length(type); + entry_type = bt_ctf_field_type_array_get_element_type(type); + if (!entry_type) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + for (i = 0; i < count; i++) { + struct bt_ctf_field *entry_field, *entry_copy; + + entry_field = bt_ctf_field_array_get_field(field, i); + if (!entry_field) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + entry_copy = bt_ctf_field_array_get_field(copy_field, i); + if (!entry_copy) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = copy_override_field(err, event, writer_event, entry_field, + entry_copy); + bt_put(entry_field); + bt_put(entry_copy); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + } + + bt_put(entry_type); + ret = 0; + +end: + return ret; +} + +static +int copy_find_clock_struct_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field) +{ + int count, i, ret; + + count = bt_ctf_field_type_structure_get_field_count(type); + for (i = 0; i < count; i++) { + struct bt_ctf_field_type *entry_type; + struct bt_ctf_field *entry_field; + const char *entry_name; + struct bt_ctf_field *entry_copy; + + entry_field = bt_ctf_field_structure_get_field_by_index(field, i); + if (!entry_field) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_field_type_structure_get_field(type, &entry_name, + &entry_type, i); + if (ret) { + bt_put(entry_field); + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end; + } + + entry_copy = bt_ctf_field_structure_get_field_by_index(copy_field, i); + if (!entry_copy) { + bt_put(entry_field); + bt_put(entry_type); + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = copy_override_field(err, event, writer_event, entry_field, + entry_copy); + + bt_put(entry_copy); + bt_put(entry_field); + bt_put(entry_type); + if (ret) { + BT_PUT(entry_copy); + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + } + + ret = 0; + +end: + return ret; +} + +static +int set_int_value(FILE *err, struct bt_ctf_field *field, + struct bt_ctf_field *copy_field, + struct bt_ctf_field_type *type) +{ + uint64_t uvalue; + int64_t value; + int ret; + + if (bt_ctf_field_type_integer_get_signed(type)) { + ret = bt_ctf_field_signed_integer_get_value(field, &value); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + printf(" - v(s) = %ld\n", value); + ret = bt_ctf_field_signed_integer_set_value(copy_field, value); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + } else { + ret = bt_ctf_field_unsigned_integer_get_value(field, + &uvalue); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + ret = bt_ctf_field_unsigned_integer_set_value(copy_field, uvalue); + if (ret) { + ret = -1; + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + } + ret = 0; + +end: + return ret; +} + +struct bt_ctf_clock_class *stream_class_get_clock_class(FILE *err, + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_trace *trace; + struct bt_ctf_clock_class *clock_class = NULL; + + trace = bt_ctf_stream_class_get_trace(stream_class); + if (!trace) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + /* FIXME multi-clock? */ + clock_class = bt_ctf_trace_get_clock_class(trace, 0); + + bt_put(trace); +end: + return clock_class; +} + +struct bt_ctf_clock_class *event_get_clock_class(FILE *err, struct bt_ctf_event *event) +{ + struct bt_ctf_event_class *event_class; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock_class *clock_class = NULL; + + event_class = bt_ctf_event_get_class(event); + if (!event_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + stream_class = bt_ctf_event_class_get_stream_class(event_class); + if (!stream_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end_put_event_class; + } + + clock_class = stream_class_get_clock_class(err, stream_class); + bt_put(stream_class); + +end_put_event_class: + bt_put(event_class); +end: + return clock_class; +} + +static +int copy_find_clock_int_field(FILE *err, + struct bt_ctf_event *event, struct bt_ctf_event *writer_event, + struct bt_ctf_field *field, struct bt_ctf_field_type *type, + struct bt_ctf_field *copy_field) +{ + struct bt_ctf_clock_class *clock_class, *writer_clock_class; + struct bt_ctf_clock_value *clock_value, *writer_clock_value; + uint64_t value; + int ret; + + clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(type); + if (!clock_class) { + return set_int_value(err, field, copy_field, type); + } + + clock_value = bt_ctf_event_get_clock_value(event, clock_class); + bt_put(clock_class); + if (!clock_value) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_clock_value_get_value(clock_value, &value); + bt_put(clock_value); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_field_unsigned_integer_set_value(copy_field, value); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + writer_clock_class = event_get_clock_class(err, writer_event); + if (!writer_clock_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + writer_clock_value = bt_ctf_clock_value_create(writer_clock_class, value); + bt_put(writer_clock_class); + if (!writer_clock_value) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = bt_ctf_event_set_clock_value(writer_event, writer_clock_value); + bt_put(writer_clock_value); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto end; + } + + ret = 0; + +end: + return ret; +} + diff --git a/plugins/libctfcopytrace/clock-fields.h b/plugins/libctfcopytrace/clock-fields.h new file mode 100644 index 000000000..607f9c03f --- /dev/null +++ b/plugins/libctfcopytrace/clock-fields.h @@ -0,0 +1,61 @@ +#ifndef BABELTRACE_CLOCK_FIELDS_H +#define BABELTRACE_CLOCK_FIELDS_H + +/* + * BabelTrace - Update clock fields to write uint64 values + * + * Copyright 2017 Julien Desfossez + * + * Author: Julien Desfossez + * + * 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 +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +BT_HIDDEN +struct bt_ctf_field_type *override_header_type(FILE *err, + struct bt_ctf_field_type *type, + struct bt_ctf_trace *writer_trace); + +BT_HIDDEN +int copy_override_field(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event *writer_event, struct bt_ctf_field *field, + struct bt_ctf_field *copy_field); + +BT_HIDDEN +struct bt_ctf_clock_class *stream_class_get_clock_class(FILE *err, + struct bt_ctf_stream_class *stream_class); + +BT_HIDDEN +struct bt_ctf_clock_class *event_get_clock_class(FILE *err, + struct bt_ctf_event *event); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CLOCK_FIELDS_H */ diff --git a/plugins/libctfcopytrace/ctfcopytrace.c b/plugins/libctfcopytrace/ctfcopytrace.c index 56aa7e1dd..bf120baf8 100644 --- a/plugins/libctfcopytrace/ctfcopytrace.c +++ b/plugins/libctfcopytrace/ctfcopytrace.c @@ -37,6 +37,7 @@ #include #include "ctfcopytrace.h" +#include "clock-fields.h" struct bt_ctf_clock_class *ctf_copy_clock_class(FILE *err, struct bt_ctf_clock_class *clock_class) @@ -161,7 +162,6 @@ enum bt_component_status ctf_copy_clock_classes(FILE *err, struct bt_ctf_trace *trace) { enum bt_component_status ret; - int int_ret, clock_class_count, i; clock_class_count = bt_ctf_trace_get_clock_class_count(trace); @@ -196,7 +196,7 @@ enum bt_component_status ctf_copy_clock_classes(FILE *err, } /* - * Ownership transferred to the writer and the stream_class. + * Ownership transferred to the trace. */ bt_put(writer_clock_class); } @@ -355,9 +355,11 @@ end: } struct bt_ctf_stream_class *ctf_copy_stream_class(FILE *err, - struct bt_ctf_stream_class *stream_class) + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_trace *writer_trace, + bool override_ts64) { - struct bt_ctf_field_type *type; + struct bt_ctf_field_type *type, *new_event_header_type; struct bt_ctf_stream_class *writer_stream_class; int ret_int; const char *name = bt_ctf_stream_class_get_name(stream_class); @@ -396,8 +398,22 @@ struct bt_ctf_stream_class *ctf_copy_stream_class(FILE *err, goto error; } + if (override_ts64) { + new_event_header_type = override_header_type(err, type, + writer_trace); + bt_put(type); + if (!new_event_header_type) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + } else { + new_event_header_type = type; + } + ret_int = bt_ctf_stream_class_set_event_header_type( - writer_stream_class, type); + writer_stream_class, new_event_header_type); + bt_put(new_event_header_type); if (ret_int < 0) { fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); @@ -493,19 +509,18 @@ end: return ret; } -enum bt_component_status ctf_copy_packet_context(FILE *err, +struct bt_ctf_field *ctf_copy_packet_context(FILE *err, struct bt_ctf_packet *packet, struct bt_ctf_stream *writer_stream) { enum bt_component_status ret; - struct bt_ctf_field *packet_context, *writer_packet_context; + struct bt_ctf_field *packet_context, *writer_packet_context = NULL; struct bt_ctf_field_type *struct_type, *writer_packet_context_type; struct bt_ctf_stream_class *writer_stream_class; - int nr_fields, i, int_ret; + int nr_fields, i; packet_context = bt_ctf_packet_get_context(packet); if (!packet_context) { - ret = BT_COMPONENT_STATUS_ERROR; fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); goto end; @@ -513,7 +528,6 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, writer_stream_class = bt_ctf_stream_get_class(writer_stream); if (!writer_stream_class) { - ret = BT_COMPONENT_STATUS_ERROR; fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); goto end_put_packet_context; @@ -522,7 +536,6 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, writer_packet_context_type = bt_ctf_stream_class_get_packet_context_type( writer_stream_class); if (!writer_packet_context_type) { - ret = BT_COMPONENT_STATUS_ERROR; fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); goto end_put_writer_stream_class; @@ -530,7 +543,6 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, struct_type = bt_ctf_field_get_type(packet_context); if (!struct_type) { - ret = BT_COMPONENT_STATUS_ERROR; fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); goto end_put_writer_packet_context_type; @@ -538,7 +550,6 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, writer_packet_context = bt_ctf_field_create(writer_packet_context_type); if (!writer_packet_context) { - ret = BT_COMPONENT_STATUS_ERROR; fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); goto end_put_struct_type; @@ -553,18 +564,18 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, field = bt_ctf_field_structure_get_field_by_index( packet_context, i); if (!field) { - ret = BT_COMPONENT_STATUS_ERROR; + BT_PUT(writer_packet_context); fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); - goto end_put_writer_packet_context; + goto end_put_struct_type; } if (bt_ctf_field_type_structure_get_field(struct_type, &field_name, &field_type, i) < 0) { - ret = BT_COMPONENT_STATUS_ERROR; bt_put(field); + BT_PUT(writer_packet_context); fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); - goto end_put_writer_packet_context; + goto end_put_struct_type; } if (!strncmp(field_name, "content_size", strlen("content_size")) || !strncmp(field_name, "packet_size", @@ -577,8 +588,8 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_TYPE_ID_INTEGER) { fprintf(err, "[error] Unexpected packet context field type\n"); bt_put(field); - ret = BT_COMPONENT_STATUS_ERROR; - goto end_put_writer_packet_context; + BT_PUT(writer_packet_context); + goto end_put_struct_type; } ret = ctf_copy_packet_context_field(err, field, field_name, @@ -586,21 +597,13 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, bt_put(field_type); bt_put(field); if (ret != BT_COMPONENT_STATUS_OK) { + BT_PUT(writer_packet_context); fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); - goto end_put_writer_packet_context; + goto end_put_struct_type; } } - int_ret = bt_ctf_stream_set_packet_context(writer_stream, - writer_packet_context); - if (int_ret < 0) { - ret = BT_COMPONENT_STATUS_ERROR; - goto end_put_writer_packet_context; - } - -end_put_writer_packet_context: - bt_put(writer_packet_context); end_put_struct_type: bt_put(struct_type); end_put_writer_packet_context_type: @@ -609,12 +612,75 @@ end_put_writer_stream_class: bt_put(writer_stream_class); end_put_packet_context: bt_put(packet_context); +end: + return writer_packet_context; +} + +static +int copy_event_header(FILE *err, struct bt_ctf_event *event, + struct bt_ctf_event_class *writer_event_class, + struct bt_ctf_event *writer_event, + struct bt_ctf_field *event_header) +{ + struct bt_ctf_clock_class *writer_clock_class; + struct bt_ctf_clock_value *clock_value; + + int ret; + struct bt_ctf_field *writer_event_header; + + writer_event_header = bt_ctf_field_copy(event_header); + if (!writer_event_header) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + ret = -1; + goto end; + } + + writer_clock_class = event_get_clock_class(err, writer_event); + if (!writer_clock_class) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + clock_value = bt_ctf_event_get_clock_value(event, writer_clock_class); + bt_put(writer_clock_class); + if (!clock_value) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = bt_ctf_event_set_clock_value(writer_event, clock_value); + bt_put(clock_value); + if (ret) { + fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, + __LINE__); + goto error; + } + + ret = bt_ctf_event_set_header(writer_event, writer_event_header); + if (ret < 0) { + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto error; + } + bt_put(writer_event_header); + + ret = 0; + + goto end; + +error: + BT_PUT(writer_event_header); + ret = -1; end: return ret; } struct bt_ctf_event *ctf_copy_event(FILE *err, struct bt_ctf_event *event, - struct bt_ctf_event_class *writer_event_class) + struct bt_ctf_event_class *writer_event_class, + bool override_ts64) { struct bt_ctf_event *writer_event; struct bt_ctf_field *field, *copy_field; @@ -635,16 +701,39 @@ struct bt_ctf_event *ctf_copy_event(FILE *err, struct bt_ctf_event *event, goto end; } - copy_field = bt_ctf_field_copy(field); - bt_put(field); - if (copy_field) { - ret = bt_ctf_event_set_header(writer_event, copy_field); - if (ret < 0) { + /* + * If override_ts64, we override all integer fields mapped to a clock + * to a uint64_t field type, otherwise, we just copy it as is. + */ + if (override_ts64) { + copy_field = bt_ctf_event_get_header(writer_event); + if (!copy_field) { + BT_PUT(writer_event); + bt_put(field); fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); - goto error; + goto end; + } + + ret = copy_override_field(err, event, writer_event, field, + copy_field); + bt_put(field); + if (ret) { + BT_PUT(writer_event); + BT_PUT(copy_field); + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; + } + } else { + ret = copy_event_header(err, event, writer_event_class, + writer_event, field); + if (ret) { + BT_PUT(writer_event); + fprintf(err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end; } - bt_put(copy_field); } /* Optional field, so it can fail silently. */ diff --git a/plugins/libctfcopytrace/ctfcopytrace.h b/plugins/libctfcopytrace/ctfcopytrace.h index 344f17272..004e330a0 100644 --- a/plugins/libctfcopytrace/ctfcopytrace.h +++ b/plugins/libctfcopytrace/ctfcopytrace.h @@ -81,7 +81,9 @@ enum bt_component_status ctf_copy_event_classes(FILE *err, * Returns NULL or error. */ struct bt_ctf_stream_class *ctf_copy_stream_class(FILE *err, - struct bt_ctf_stream_class *stream_class); + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_trace *writer_trace, + bool override_ts64); /* * Copy the value of a packet context field and add it to the @@ -104,7 +106,7 @@ enum bt_component_status ctf_copy_packet_context_field(FILE *err, * Returns BT_COMPONENT_STATUS_OK on success, and BT_COMPONENT_STATUS_ERROR on * error. */ -enum bt_component_status ctf_copy_packet_context(FILE *err, +struct bt_ctf_field *ctf_copy_packet_context(FILE *err, struct bt_ctf_packet *packet, struct bt_ctf_stream *writer_stream); @@ -115,7 +117,8 @@ enum bt_component_status ctf_copy_packet_context(FILE *err, * Returns NULL on error. */ struct bt_ctf_event *ctf_copy_event(FILE *err, struct bt_ctf_event *event, - struct bt_ctf_event_class *writer_event_class); + struct bt_ctf_event_class *writer_event_class, + bool override_ts64); /* * Copy the environment and the packet header from the input trace to the diff --git a/plugins/writer/write.c b/plugins/writer/write.c index 0fa472f3f..e6684d15e 100644 --- a/plugins/writer/write.c +++ b/plugins/writer/write.c @@ -46,25 +46,16 @@ struct bt_ctf_stream_class *insert_new_stream_class( struct bt_ctf_writer *ctf_writer, struct bt_ctf_stream_class *stream_class) { - struct bt_ctf_stream_class *writer_stream_class; + struct bt_ctf_stream_class *writer_stream_class = NULL; struct bt_ctf_trace *trace, *writer_trace; enum bt_component_status ret; - writer_stream_class = ctf_copy_stream_class(writer_component->err, - stream_class); - if (!writer_stream_class) { - fprintf(writer_component->err, "[error] Failed to copy stream class\n"); - fprintf(writer_component->err, "[error] %s in %s:%d\n", - __func__, __FILE__, __LINE__); - goto end; - } - trace = bt_ctf_stream_class_get_trace(stream_class); if (!trace) { fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); - goto error; + goto end; } writer_trace = bt_ctf_writer_get_trace(ctf_writer); @@ -74,20 +65,27 @@ struct bt_ctf_stream_class *insert_new_stream_class( "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); ret = BT_COMPONENT_STATUS_ERROR; - goto error; + goto end_put_trace; } ret = ctf_copy_clock_classes(writer_component->err, writer_trace, writer_stream_class, trace); - bt_put(writer_trace); if (ret != BT_COMPONENT_STATUS_OK) { bt_put(trace); fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); - goto error; + goto end_put_writer_trace; + } + + writer_stream_class = ctf_copy_stream_class(writer_component->err, + stream_class, writer_trace, true); + if (!writer_stream_class) { + fprintf(writer_component->err, "[error] Failed to copy stream class\n"); + fprintf(writer_component->err, "[error] %s in %s:%d\n", + __func__, __FILE__, __LINE__); + goto end_put_writer_trace; } - bt_put(trace); ret = ctf_copy_event_classes(writer_component->err, stream_class, writer_stream_class); @@ -101,10 +99,10 @@ struct bt_ctf_stream_class *insert_new_stream_class( g_hash_table_insert(writer_component->stream_class_map, (gpointer) stream_class, writer_stream_class); - goto end; - -error: - BT_PUT(writer_stream_class); +end_put_writer_trace: + bt_put(writer_trace); +end_put_trace: + bt_put(trace); end: return writer_stream_class; } @@ -311,7 +309,9 @@ enum bt_component_status writer_new_packet( struct bt_ctf_packet *packet) { struct bt_ctf_stream *stream, *writer_stream; + struct bt_ctf_field *writer_packet_context; enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + int int_ret; stream = bt_ctf_packet_get_stream(packet); if (!stream) { @@ -329,17 +329,28 @@ enum bt_component_status writer_new_packet( goto end_put; } - ret = ctf_copy_packet_context(writer_component->err, packet, - writer_stream); - if (ret != BT_COMPONENT_STATUS_OK) { + writer_packet_context = ctf_copy_packet_context(writer_component->err, + packet, writer_stream); + if (!writer_packet_context) { ret = BT_COMPONENT_STATUS_ERROR; fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, __FILE__, __LINE__); goto end_put; } + int_ret = bt_ctf_stream_set_packet_context(writer_stream, + writer_packet_context); + if (int_ret < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__, + __FILE__, __LINE__); + goto end_put_writer_packet_context; + } + bt_put(writer_stream); +end_put_writer_packet_context: + bt_put(writer_packet_context); end_put: bt_put(stream); end: @@ -468,7 +479,8 @@ enum bt_component_status writer_output_event( goto end_put_writer_stream_class; } - writer_event = ctf_copy_event(writer_component->err, event, writer_event_class); + writer_event = ctf_copy_event(writer_component->err, event, + writer_event_class, true); if (!writer_event) { ret = BT_COMPONENT_STATUS_ERROR; fprintf(writer_component->err, "[error] %s in %s:%d\n", __func__,