From: Michael Jeanson Date: Fri, 7 Jun 2019 16:25:10 +0000 (-0400) Subject: ctf-writer: externalize libbabeltrace2-ctf-writer X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=67d2ce028c96b6a3b3614b393d8928663bce4490 ctf-writer: externalize libbabeltrace2-ctf-writer Completely split the ctf writer part from the main babeltrace2 library. * Remove the obsolete libbabeltrace2-ctf library * Add a new libbabeltrace2-ctf-writer library * Remove the ctf writer includes from the main include file * Fork an internal copy of assert-pre.h that doesn't use the library structures. * Add a logging context specific to ctf writer Signed-off-by: Michael Jeanson Change-Id: Iff9ab62ee9eeb8abd290fb1d758a73050e21c99b Reviewed-on: https://review.lttng.org/c/babeltrace/+/1410 Tested-by: jenkins Reviewed-by: Philippe Proulx --- diff --git a/.gitignore b/.gitignore index 13fdf958..9c71bb9d 100644 --- a/.gitignore +++ b/.gitignore @@ -88,7 +88,7 @@ core stamp-h1 __pycache__ /babeltrace2.pc -/babeltrace2-ctf.pc +/babeltrace2-ctf-writer.pc TAGS cscope* doc/api/Doxyfile diff --git a/Makefile.am b/Makefile.am index 76ba8249..938dc75b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,6 +8,7 @@ SUBDIRS = include \ logging \ lib \ python-plugin-provider \ + ctf-writer \ plugins \ cli \ bindings \ @@ -24,7 +25,7 @@ dist_doc_DATA = ChangeLog LICENSE mit-license.txt gpl-2.0.txt \ dist_noinst_DATA = CodingStyle pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = babeltrace2.pc babeltrace2-ctf.pc +pkgconfig_DATA = babeltrace2.pc babeltrace2-ctf-writer.pc # This is a convenience target, it's not part of the build process. CONTRIBUTING.html: CONTRIBUTING.adoc diff --git a/babeltrace2-ctf-writer.pc.in b/babeltrace2-ctf-writer.pc.in new file mode 100644 index 00000000..504d8597 --- /dev/null +++ b/babeltrace2-ctf-writer.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Babeltrace CTF parser +Description: libbabeltrace2-ctf provides the specific bits necessary to write a Common Trace Format (CTF) trace. +Version: @PACKAGE_VERSION@ +Requires: +Requires.private: uuid popt +Libs: -L${libdir} -lbabeltrace2-ctf-writer +Cflags: -I${includedir} + diff --git a/babeltrace2-ctf.pc.in b/babeltrace2-ctf.pc.in deleted file mode 100644 index b20d98b1..00000000 --- a/babeltrace2-ctf.pc.in +++ /dev/null @@ -1,13 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: Babeltrace CTF parser -Description: libbabeltrace2-ctf provides the specific bits necessary to read a Common Trace Format (CTF) trace. -Version: @PACKAGE_VERSION@ -Requires: babeltrace -Requires.private: -Libs: -L${libdir} -lbabeltrace2-ctf -Cflags: -I${includedir} - diff --git a/configure.ac b/configure.ac index 3fc2eb94..b4f1e915 100644 --- a/configure.ac +++ b/configure.ac @@ -732,6 +732,7 @@ AC_CONFIG_FILES([ bindings/python/bt2/bt2/__init__.py common/Makefile ctfser/Makefile + ctf-writer/Makefile compat/Makefile cli/Makefile doc/Makefile @@ -749,7 +750,6 @@ AC_CONFIG_FILES([ lib/graph/Makefile lib/graph/message/Makefile lib/trace-ir/Makefile - lib/ctf-writer/Makefile include/Makefile logging/Makefile bindings/Makefile @@ -782,7 +782,7 @@ AC_CONFIG_FILES([ plugins/lttng-utils/Makefile plugins/lttng-utils/debug-info/Makefile babeltrace2.pc - babeltrace2-ctf.pc + babeltrace2-ctf-writer.pc ]) AC_CONFIG_FILES([tests/cli/test_intersection], [chmod +x tests/cli/test_intersection]) diff --git a/ctf-writer/Makefile.am b/ctf-writer/Makefile.am new file mode 100644 index 00000000..7c5d046e --- /dev/null +++ b/ctf-writer/Makefile.am @@ -0,0 +1,36 @@ +lib_LTLIBRARIES = libbabeltrace2-ctf-writer.la + +libbabeltrace2_ctf_writer_la_SOURCES = \ + attributes.c \ + clock.c \ + clock-class.c \ + event.c \ + event-class.c \ + field-path.c \ + fields.c \ + field-types.c \ + field-wrapper.c \ + functor.c \ + logging.c \ + logging.h \ + object.c \ + object-pool.c \ + resolve.c \ + stream.c \ + stream-class.c \ + trace.c \ + utils.c \ + validation.c \ + values.c \ + visitor.c \ + writer.c + +libbabeltrace2_ctf_writer_la_LDFLAGS = $(LT_NO_UNDEFINED) \ + -version-info $(BABELTRACE_LIBRARY_VERSION) + +libbabeltrace2_ctf_writer_la_LIBADD = \ + $(top_builddir)/logging/libbabeltrace2-logging.la \ + $(top_builddir)/common/libbabeltrace2-common.la \ + $(top_builddir)/ctfser/libbabeltrace2-ctfser.la \ + $(top_builddir)/compat/libcompat.la \ + $(UUID_LIBS) diff --git a/ctf-writer/attributes.c b/ctf-writer/attributes.c new file mode 100644 index 00000000..fbb81a03 --- /dev/null +++ b/ctf-writer/attributes.c @@ -0,0 +1,347 @@ +/* + * attributes.c + * + * Babeltrace CTF writer - Attributes + * + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-ATTRS" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BT_CTF_ATTR_NAME_INDEX 0 +#define BT_CTF_ATTR_VALUE_INDEX 1 + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_attributes_create(void) +{ + struct bt_ctf_private_value *attr_obj; + + /* + * Attributes: array value object of array value objects, each one + * containing two entries: a string value object (attributes + * field name), and a value object (attributes field value). + * + * Example (JSON representation): + * + * [ + * ["hostname", "eeppdesk"], + * ["sysname", "Linux"], + * ["tracer_major", 2], + * ["tracer_minor", 5] + * ] + */ + BT_LOGD_STR("Creating attributes object."); + attr_obj = bt_ctf_private_value_array_create(); + if (!attr_obj) { + BT_LOGE_STR("Failed to create array value."); + } else { + BT_LOGD("Created attributes object: addr=%p", + attr_obj); + } + + return attr_obj; +} + +BT_HIDDEN +void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj) +{ + BT_LOGD("Destroying attributes object: addr=%p", attr_obj); + bt_ctf_object_put_ref(attr_obj); +} + +BT_HIDDEN +int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj) +{ + return bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)); +} + +BT_HIDDEN +const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj, + uint64_t index) +{ + const char *ret = NULL; + struct bt_ctf_private_value *attr_field_obj = NULL; + struct bt_ctf_private_value *attr_field_name_obj = NULL; + + if (!attr_obj) { + BT_LOGW_STR("Invalid parameter: attributes object is NULL."); + goto end; + } + + if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) { + BT_LOGW("Invalid parameter: index is out of bounds: " + "index=%" PRIu64 ", count=%" PRId64, + index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))); + goto end; + } + + attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index( + attr_obj, index); + if (!attr_field_obj) { + BT_LOGE("Cannot get attributes object's array value's element by index: " + "value-addr=%p, index=%" PRIu64, attr_obj, index); + goto end; + } + + attr_field_name_obj = + bt_ctf_private_value_array_borrow_element_by_index( + attr_field_obj, BT_CTF_ATTR_NAME_INDEX); + if (!attr_field_name_obj) { + BT_LOGE("Cannot get attribute array value's element by index: " + "value-addr=%p, index=%" PRIu64, attr_field_obj, + (uint64_t) BT_CTF_ATTR_NAME_INDEX); + goto end; + } + + ret = bt_ctf_value_string_get( + bt_ctf_private_value_as_value(attr_field_name_obj)); + +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj, + uint64_t index) +{ + struct bt_ctf_private_value *value_obj = NULL; + struct bt_ctf_private_value *attr_field_obj = NULL; + + if (!attr_obj) { + BT_LOGW_STR("Invalid parameter: attributes object is NULL."); + goto end; + } + + if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) { + BT_LOGW("Invalid parameter: index is out of bounds: " + "index=%" PRIu64 ", count=%" PRId64, + index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))); + goto end; + } + + attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index( + attr_obj, index); + if (!attr_field_obj) { + BT_LOGE("Cannot get attributes object's array value's element by index: " + "value-addr=%p, index=%" PRIu64, attr_obj, index); + goto end; + } + + value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj, + BT_CTF_ATTR_VALUE_INDEX); + if (!value_obj) { + BT_LOGE("Cannot get attribute array value's element by index: " + "value-addr=%p, index=%" PRIu64, attr_field_obj, + (uint64_t) BT_CTF_ATTR_VALUE_INDEX); + } + +end: + return value_obj; +} + +static +struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_by_name( + struct bt_ctf_private_value *attr_obj, const char *name) +{ + uint64_t i; + int64_t attr_size; + struct bt_ctf_private_value *value_obj = NULL; + struct bt_ctf_private_value *attr_field_name_obj = NULL; + + attr_size = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)); + if (attr_size < 0) { + BT_LOGE("Cannot get array value's size: value-addr=%p", + attr_obj); + goto error; + } + + for (i = 0; i < attr_size; ++i) { + const char *field_name; + + value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_obj, i); + if (!value_obj) { + BT_LOGE("Cannot get attributes object's array value's element by index: " + "value-addr=%p, index=%" PRIu64, attr_obj, i); + goto error; + } + + attr_field_name_obj = bt_ctf_private_value_array_borrow_element_by_index(value_obj, + BT_CTF_ATTR_NAME_INDEX); + if (!attr_field_name_obj) { + BT_LOGE("Cannot get attribute array value's element by index: " + "value-addr=%p, index=%" PRIu64, + value_obj, (int64_t) BT_CTF_ATTR_NAME_INDEX); + goto error; + } + + field_name = bt_ctf_value_string_get( + bt_ctf_private_value_as_value(attr_field_name_obj)); + + if (!strcmp(field_name, name)) { + break; + } + + value_obj = NULL; + } + + return value_obj; + +error: + value_obj = NULL; + return value_obj; +} + +BT_HIDDEN +int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj, + const char *name, struct bt_ctf_private_value *value_obj) +{ + int ret = 0; + struct bt_ctf_private_value *attr_field_obj = NULL; + + if (!attr_obj || !name || !value_obj) { + BT_LOGW("Invalid parameter: attributes object, name, or value object is NULL: " + "attr-value-addr=%p, name-addr=%p, value-addr=%p", + attr_obj, name, value_obj); + ret = -1; + goto end; + } + + attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name); + if (attr_field_obj) { + ret = bt_ctf_private_value_array_set_element_by_index( + attr_field_obj, BT_CTF_ATTR_VALUE_INDEX, + bt_ctf_private_value_as_value(value_obj)); + attr_field_obj = NULL; + goto end; + } + + attr_field_obj = bt_ctf_private_value_array_create(); + if (!attr_field_obj) { + BT_LOGE_STR("Failed to create empty array value."); + ret = -1; + goto end; + } + + ret = bt_ctf_private_value_array_append_string_element(attr_field_obj, name); + ret |= bt_ctf_private_value_array_append_element(attr_field_obj, + bt_ctf_private_value_as_value(value_obj)); + if (ret) { + BT_LOGE("Cannot append elements to array value: addr=%p", + attr_field_obj); + goto end; + } + + ret = bt_ctf_private_value_array_append_element(attr_obj, + bt_ctf_private_value_as_value(attr_field_obj)); + if (ret) { + BT_LOGE("Cannot append element to array value: " + "array-value-addr=%p, element-value-addr=%p", + attr_obj, attr_field_obj); + } + +end: + bt_ctf_object_put_ref(attr_field_obj); + return ret; +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name( + struct bt_ctf_private_value *attr_obj, const char *name) +{ + struct bt_ctf_private_value *value_obj = NULL; + struct bt_ctf_private_value *attr_field_obj = NULL; + + if (!attr_obj || !name) { + BT_LOGW("Invalid parameter: attributes object or name is NULL: " + "value-addr=%p, name-addr=%p", attr_obj, name); + goto end; + } + + attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name); + if (!attr_field_obj) { + BT_LOGD("Cannot find attributes object's field by name: " + "value-addr=%p, name=\"%s\"", attr_obj, name); + goto end; + } + + value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj, + BT_CTF_ATTR_VALUE_INDEX); + if (!value_obj) { + BT_LOGE("Cannot get attribute array value's element by index: " + "value-addr=%p, index=%" PRIu64, attr_field_obj, + (uint64_t) BT_CTF_ATTR_VALUE_INDEX); + } + +end: + return value_obj; +} + +BT_HIDDEN +int bt_ctf_attributes_freeze(struct bt_ctf_private_value *attr_obj) +{ + uint64_t i; + int64_t count; + int ret = 0; + + if (!attr_obj) { + BT_LOGW_STR("Invalid parameter: attributes object is NULL."); + ret = -1; + goto end; + } + + BT_LOGD("Freezing attributes object: value-addr=%p", attr_obj); + count = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)); + BT_ASSERT(count >= 0); + + /* + * We do not freeze the array value object itself here, since + * internal stuff could need to modify/add attributes. Each + * attribute is frozen one by one. + */ + for (i = 0; i < count; ++i) { + struct bt_ctf_private_value *obj = NULL; + + obj = bt_ctf_attributes_borrow_field_value(attr_obj, i); + if (!obj) { + BT_LOGE("Cannot get attributes object's field value by index: " + "value-addr=%p, index=%" PRIu64, + attr_obj, i); + ret = -1; + goto end; + } + + bt_ctf_value_freeze(bt_ctf_private_value_as_value(obj)); + } + +end: + return ret; +} diff --git a/ctf-writer/clock-class.c b/ctf-writer/clock-class.c new file mode 100644 index 00000000..1c507e37 --- /dev/null +++ b/ctf-writer/clock-class.c @@ -0,0 +1,704 @@ +/* + * clock-class.c + * + * Babeltrace CTF writer - Clock class + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-CLOCK-CLASS" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj); + +BT_HIDDEN +bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class) +{ + return clock_class && clock_class->name; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class, + const char *name) +{ + int ret = 0; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + ret = -1; + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + if (!bt_ctf_identifier_is_valid(name)) { + BT_LOGW("Clock class's name is not a valid CTF identifier: " + "addr=%p, name=\"%s\"", + clock_class, name); + ret = -1; + goto end; + } + + if (clock_class->name) { + g_string_assign(clock_class->name, name); + } else { + clock_class->name = g_string_new(name); + if (!clock_class->name) { + BT_LOGE_STR("Failed to allocate a GString."); + ret = -1; + goto end; + } + } + + BT_LOGV("Set clock class's name: addr=%p, name=\"%s\"", + clock_class, name); + +end: + return ret; +} + +static +bool validate_freq(struct bt_ctf_clock_class *clock_class, + const char *name, uint64_t freq) +{ + bool is_valid = true; + + if (freq == -1ULL || freq == 0) { + BT_LOGW("Invalid parameter: frequency is invalid: " + "addr=%p, name=\"%s\", freq=%" PRIu64, + clock_class, name, freq); + is_valid = false; + goto end; + } + +end: + return is_valid; +} + +BT_HIDDEN +struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name, + uint64_t freq) +{ + int ret; + struct bt_ctf_clock_class *clock_class = NULL; + + BT_LOGD("Creating default clock class object: name=\"%s\"", + name); + + if (!validate_freq(NULL, name, freq)) { + /* validate_freq() logs errors */ + goto error; + } + + clock_class = g_new0(struct bt_ctf_clock_class, 1); + if (!clock_class) { + BT_LOGE_STR("Failed to allocate one clock class."); + goto error; + } + + clock_class->precision = 1; + clock_class->frequency = freq; + bt_ctf_object_init_shared(&clock_class->base, bt_ctf_clock_class_destroy); + + if (name) { + ret = bt_ctf_clock_class_set_name(clock_class, name); + if (ret) { + /* bt_ctf_clock_class_set_name() logs errors */ + goto error; + } + } + + BT_LOGD("Created clock class object: addr=%p, name=\"%s\"", + clock_class, name); + return clock_class; +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(clock_class); + return clock_class; +} + +BT_HIDDEN +const char *bt_ctf_clock_class_get_name(struct bt_ctf_clock_class *clock_class) +{ + const char *ret = NULL; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + goto end; + } + + if (clock_class->name) { + ret = clock_class->name->str; + } + +end: + return ret; +} + +BT_HIDDEN +const char *bt_ctf_clock_class_get_description( + struct bt_ctf_clock_class *clock_class) +{ + const char *ret = NULL; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + goto end; + } + + if (clock_class->description) { + ret = clock_class->description->str; + } +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class, + const char *desc) +{ + int ret = 0; + + if (!clock_class || !desc) { + BT_LOGW("Invalid parameter: clock class or description is NULL: " + "clock-class-addr=%p, name=\"%s\", desc-addr=%p", + clock_class, bt_ctf_clock_class_get_name(clock_class), + desc); + ret = -1; + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + clock_class->description = g_string_new(desc); + ret = clock_class->description ? 0 : -1; + BT_LOGV("Set clock class's description: addr=%p, " + "name=\"%s\", desc=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class), desc); +end: + return ret; +} + +BT_HIDDEN +uint64_t bt_ctf_clock_class_get_frequency( + struct bt_ctf_clock_class *clock_class) +{ + uint64_t ret = -1ULL; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + goto end; + } + + ret = clock_class->frequency; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class, + uint64_t freq) +{ + int ret = 0; + + if (!clock_class) { + BT_LOGW("Invalid parameter: clock class is NULL or frequency is invalid: " + "addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + if (!validate_freq(clock_class, bt_ctf_clock_class_get_name(clock_class), + freq)) { + /* validate_freq() logs errors */ + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + clock_class->frequency = freq; + BT_LOGV("Set clock class's frequency: addr=%p, name=\"%s\", freq=%" PRIu64, + clock_class, bt_ctf_clock_class_get_name(clock_class), freq); +end: + return ret; +} + +BT_HIDDEN +uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_clock_class *clock_class) +{ + uint64_t ret = -1ULL; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + goto end; + } + + ret = clock_class->precision; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class, + uint64_t precision) +{ + int ret = 0; + + if (!clock_class || precision == -1ULL) { + BT_LOGW("Invalid parameter: clock class is NULL or precision is invalid: " + "addr=%p, name=\"%s\", precision=%" PRIu64, + clock_class, bt_ctf_clock_class_get_name(clock_class), + precision); + ret = -1; + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + clock_class->precision = precision; + BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64, + clock_class, bt_ctf_clock_class_get_name(clock_class), + precision); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class, + int64_t *offset_s) +{ + int ret = 0; + + if (!clock_class || !offset_s) { + BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " + "clock-class-addr=%p, name=\"%s\", offset-addr=%p", + clock_class, bt_ctf_clock_class_get_name(clock_class), + offset_s); + ret = -1; + goto end; + } + + *offset_s = clock_class->offset_s; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class, + int64_t offset_s) +{ + int ret = 0; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + ret = -1; + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + clock_class->offset_s = offset_s; + BT_LOGV("Set clock class's offset (seconds): " + "addr=%p, name=\"%s\", offset-s=%" PRId64, + clock_class, bt_ctf_clock_class_get_name(clock_class), + offset_s); +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_clock_class *clock_class, + int64_t *offset) +{ + int ret = 0; + + if (!clock_class || !offset) { + BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " + "clock-class-addr=%p, name=\"%s\", offset-addr=%p", + clock_class, bt_ctf_clock_class_get_name(clock_class), + offset); + ret = -1; + goto end; + } + + *offset = clock_class->offset; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class, + int64_t offset) +{ + int ret = 0; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + ret = -1; + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + clock_class->offset = offset; + BT_LOGV("Set clock class's offset (cycles): addr=%p, name=\"%s\", offset-cycles=%" PRId64, + clock_class, bt_ctf_clock_class_get_name(clock_class), offset); +end: + return ret; +} + +BT_HIDDEN +bt_bool bt_ctf_clock_class_is_absolute(struct bt_ctf_clock_class *clock_class) +{ + int ret = -1; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + goto end; + } + + ret = clock_class->absolute; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_clock_class *clock_class, + bt_bool is_absolute) +{ + int ret = 0; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + ret = -1; + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + clock_class->absolute = !!is_absolute; + BT_LOGV("Set clock class's absolute flag: addr=%p, name=\"%s\", is-absolute=%d", + clock_class, bt_ctf_clock_class_get_name(clock_class), + is_absolute); +end: + return ret; +} + +BT_HIDDEN +const unsigned char *bt_ctf_clock_class_get_uuid( + struct bt_ctf_clock_class *clock_class) +{ + const unsigned char *ret; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + ret = NULL; + goto end; + } + + if (!clock_class->uuid_set) { + BT_LOGV("Clock class's UUID is not set: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = NULL; + goto end; + } + + ret = clock_class->uuid; +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class, + const unsigned char *uuid) +{ + int ret = 0; + + if (!clock_class || !uuid) { + BT_LOGW("Invalid parameter: clock class or UUID is NULL: " + "clock-class-addr=%p, name=\"%s\", uuid-addr=%p", + clock_class, bt_ctf_clock_class_get_name(clock_class), + uuid); + ret = -1; + goto end; + } + + if (clock_class->frozen) { + BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + memcpy(clock_class->uuid, uuid, BABELTRACE_UUID_LEN); + clock_class->uuid_set = 1; + BT_LOGV("Set clock class's UUID: addr=%p, name=\"%s\", " + "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", + clock_class, bt_ctf_clock_class_get_name(clock_class), + (unsigned int) uuid[0], + (unsigned int) uuid[1], + (unsigned int) uuid[2], + (unsigned int) uuid[3], + (unsigned int) uuid[4], + (unsigned int) uuid[5], + (unsigned int) uuid[6], + (unsigned int) uuid[7], + (unsigned int) uuid[8], + (unsigned int) uuid[9], + (unsigned int) uuid[10], + (unsigned int) uuid[11], + (unsigned int) uuid[12], + (unsigned int) uuid[13], + (unsigned int) uuid[14], + (unsigned int) uuid[15]); +end: + return ret; +} + +BT_HIDDEN +void bt_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class) +{ + if (!clock_class || clock_class->frozen) { + return; + } + + BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"", + clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class->frozen = 1; +} + +static +void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_clock_class *clock_class; + + clock_class = container_of(obj, struct bt_ctf_clock_class, base); + BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"", + obj, bt_ctf_clock_class_get_name(clock_class)); + + if (clock_class->name) { + g_string_free(clock_class->name, TRUE); + } + + if (clock_class->description) { + g_string_free(clock_class->description, TRUE); + } + + g_free(clock_class); +} + +BT_HIDDEN +int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a, + struct bt_ctf_clock_class *clock_class_b) +{ + int ret = 1; + BT_ASSERT(clock_class_a); + BT_ASSERT(clock_class_b); + + /* Name */ + if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) { + BT_LOGV("Clock classes differ: different names: " + "cc-a-name=\"%s\", cc-b-name=\"%s\"", + clock_class_a->name->str, + clock_class_b->name->str); + goto end; + } + + /* Description */ + if (clock_class_a->description) { + if (!clock_class_b->description) { + BT_LOGV_STR("Clock classes differ: clock class A has a " + "description, but clock class B does not."); + goto end; + } + + if (strcmp(clock_class_a->name->str, clock_class_b->name->str) + != 0) { + BT_LOGV("Clock classes differ: different descriptions: " + "cc-a-descr=\"%s\", cc-b-descr=\"%s\"", + clock_class_a->description->str, + clock_class_b->description->str); + goto end; + } + } else { + if (clock_class_b->description) { + BT_LOGV_STR("Clock classes differ: clock class A has " + "no description, but clock class B has one."); + goto end; + } + } + + /* Frequency */ + if (clock_class_a->frequency != clock_class_b->frequency) { + BT_LOGV("Clock classes differ: different frequencies: " + "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, + clock_class_a->frequency, + clock_class_b->frequency); + goto end; + } + + /* Precision */ + if (clock_class_a->precision != clock_class_b->precision) { + BT_LOGV("Clock classes differ: different precisions: " + "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, + clock_class_a->precision, + clock_class_b->precision); + goto end; + } + + /* Offset (seconds) */ + if (clock_class_a->offset_s != clock_class_b->offset_s) { + BT_LOGV("Clock classes differ: different offsets (seconds): " + "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, + clock_class_a->offset_s, + clock_class_b->offset_s); + goto end; + } + + /* Offset (cycles) */ + if (clock_class_a->offset != clock_class_b->offset) { + BT_LOGV("Clock classes differ: different offsets (cycles): " + "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, + clock_class_a->offset, + clock_class_b->offset); + goto end; + } + + /* UUIDs */ + if (clock_class_a->uuid_set) { + if (!clock_class_b->uuid_set) { + BT_LOGV_STR("Clock classes differ: clock class A has a " + "UUID, but clock class B does not."); + goto end; + } + + if (memcmp(clock_class_a->uuid, clock_class_b->uuid, + BABELTRACE_UUID_LEN) != 0) { + BT_LOGV("Clock classes differ: different UUIDs: " + "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", " + "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", + (unsigned int) clock_class_a->uuid[0], + (unsigned int) clock_class_a->uuid[1], + (unsigned int) clock_class_a->uuid[2], + (unsigned int) clock_class_a->uuid[3], + (unsigned int) clock_class_a->uuid[4], + (unsigned int) clock_class_a->uuid[5], + (unsigned int) clock_class_a->uuid[6], + (unsigned int) clock_class_a->uuid[7], + (unsigned int) clock_class_a->uuid[8], + (unsigned int) clock_class_a->uuid[9], + (unsigned int) clock_class_a->uuid[10], + (unsigned int) clock_class_a->uuid[11], + (unsigned int) clock_class_a->uuid[12], + (unsigned int) clock_class_a->uuid[13], + (unsigned int) clock_class_a->uuid[14], + (unsigned int) clock_class_a->uuid[15], + (unsigned int) clock_class_b->uuid[0], + (unsigned int) clock_class_b->uuid[1], + (unsigned int) clock_class_b->uuid[2], + (unsigned int) clock_class_b->uuid[3], + (unsigned int) clock_class_b->uuid[4], + (unsigned int) clock_class_b->uuid[5], + (unsigned int) clock_class_b->uuid[6], + (unsigned int) clock_class_b->uuid[7], + (unsigned int) clock_class_b->uuid[8], + (unsigned int) clock_class_b->uuid[9], + (unsigned int) clock_class_b->uuid[10], + (unsigned int) clock_class_b->uuid[11], + (unsigned int) clock_class_b->uuid[12], + (unsigned int) clock_class_b->uuid[13], + (unsigned int) clock_class_b->uuid[14], + (unsigned int) clock_class_b->uuid[15]); + goto end; + } + } else { + if (clock_class_b->uuid_set) { + BT_LOGV_STR("Clock classes differ: clock class A has " + "no UUID, but clock class B has one."); + goto end; + } + } + + /* Absolute */ + if (!!clock_class_a->absolute != !!clock_class_b->absolute) { + BT_LOGV("Clock classes differ: one is absolute, the other " + "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d", + !!clock_class_a->absolute, + !!clock_class_b->absolute); + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} diff --git a/ctf-writer/clock.c b/ctf-writer/clock.c new file mode 100644 index 00000000..0238c25b --- /dev/null +++ b/ctf-writer/clock.c @@ -0,0 +1,274 @@ +/* + * clock.c + * + * Babeltrace CTF writer - Clock + * + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2017 Philippe Proulx + * + * Author: Jérémie Galarneau + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-CLOCK" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_clock_destroy(struct bt_ctf_object *obj); + +struct bt_ctf_clock *bt_ctf_clock_create(const char *name) +{ + int ret; + struct bt_ctf_clock *clock = NULL; + unsigned char cc_uuid[BABELTRACE_UUID_LEN]; + + BT_CTF_ASSERT_PRE_NON_NULL(name, "Name"); + clock = g_new0(struct bt_ctf_clock, 1); + if (!clock) { + goto error; + } + + bt_ctf_object_init_shared(&clock->base, bt_ctf_clock_destroy); + clock->value = 0; + + /* Pre-2.0.0 backward compatibility: default frequency is 1 GHz */ + clock->clock_class = (void *) bt_ctf_clock_class_create(name, 1000000000); + if (!clock->clock_class) { + goto error; + } + + /* Automatically set clock class's UUID. */ + ret = bt_uuid_generate(cc_uuid); + if (ret) { + goto error; + } + + ret = bt_ctf_clock_class_set_uuid(clock->clock_class, cc_uuid); + BT_ASSERT(ret == 0); + return clock; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(clock); + return clock; +} + +const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_get_name(clock->clock_class); +} + +const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_get_description(clock->clock_class); +} + +int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_set_description(clock->clock_class, + desc); +} + +uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_get_frequency(clock->clock_class); +} + +int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_set_frequency(clock->clock_class, + freq); +} + +uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_get_precision(clock->clock_class); +} + +int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_set_precision(clock->clock_class, + precision); +} + +int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, int64_t *offset_s) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_get_offset_s(clock->clock_class, + offset_s); +} + +int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, int64_t offset_s) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_set_offset_s(clock->clock_class, + offset_s); +} + +int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, int64_t *offset) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_get_offset_cycles(clock->clock_class, + offset); +} + +int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, int64_t offset) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_set_offset_cycles(clock->clock_class, + offset); +} + +int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_is_absolute(clock->clock_class); +} + +int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_set_is_absolute(clock->clock_class, + is_absolute); +} + +const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_get_uuid(clock->clock_class); +} + +int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, const unsigned char *uuid) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + return bt_ctf_clock_class_set_uuid(clock->clock_class, uuid); +} + +int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, int64_t time) +{ + int64_t value; + struct bt_ctf_clock_class *cc; + + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + cc = clock->clock_class; + + /* Common case where cycles are actually nanoseconds */ + if (cc->frequency == 1000000000) { + value = time; + } else { + value = (uint64_t) (((double) time * + (double) cc->frequency) / 1e9); + } + + BT_CTF_ASSERT_PRE(clock->value <= value, + "CTF writer clock value must be updated monotonically: " + "prev-value=%" PRId64 ", new-value=%" PRId64, + clock->value, value); + clock->value = value; + return 0; +} + +BT_HIDDEN +int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value) +{ + BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value"); + *value = clock->value; + return 0; +} + +static +void bt_ctf_clock_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_clock *clock; + + clock = container_of(obj, struct bt_ctf_clock, base); + bt_ctf_object_put_ref(clock->clock_class); + g_free(clock); +} + +BT_HIDDEN +void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class, + struct metadata_context *context) +{ + unsigned char *uuid; + + BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, " + "name=\"%s\", metadata-context-addr=%p", clock_class, + bt_ctf_clock_class_get_name(clock_class), + context); + + if (!clock_class || !context) { + BT_LOGW("Invalid parameter: clock class or metadata context is NULL: " + "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p", + clock_class, + bt_ctf_clock_class_get_name(clock_class), + context); + return; + } + + uuid = clock_class->uuid; + g_string_append(context->string, "clock {\n"); + g_string_append_printf(context->string, "\tname = %s;\n", + clock_class->name->str); + + if (clock_class->uuid_set) { + g_string_append_printf(context->string, + "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + } + + if (clock_class->description) { + g_string_append_printf(context->string, "\tdescription = \"%s\";\n", + clock_class->description->str); + } + + g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n", + clock_class->frequency); + g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n", + clock_class->precision); + g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n", + clock_class->offset_s); + g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n", + clock_class->offset); + g_string_append_printf(context->string, "\tabsolute = %s;\n", + clock_class->absolute ? "true" : "false"); + g_string_append(context->string, "};\n\n"); +} diff --git a/ctf-writer/event-class.c b/ctf-writer/event-class.c new file mode 100644 index 00000000..3d8c1f5c --- /dev/null +++ b/ctf-writer/event-class.c @@ -0,0 +1,586 @@ +/* + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2017-2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-EVENT-CLASS" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BT_HIDDEN +void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj) +{ + struct bt_ctf_event_class_common *event_class; + + event_class = container_of(obj, struct bt_ctf_event_class_common, base); + BT_LOGD("Finalizing common event class: addr=%p, name=\"%s\", id=%" PRId64, + event_class, bt_ctf_event_class_common_get_name(event_class), + bt_ctf_event_class_common_get_id(event_class)); + + if (event_class->name) { + g_string_free(event_class->name, TRUE); + } + + if (event_class->emf_uri) { + g_string_free(event_class->emf_uri, TRUE); + } + + BT_LOGD_STR("Putting context field type."); + bt_ctf_object_put_ref(event_class->context_field_type); + BT_LOGD_STR("Putting payload field type."); + bt_ctf_object_put_ref(event_class->payload_field_type); +} + +BT_HIDDEN +int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class, + const char *name, bt_ctf_object_release_func release_func, + bt_ctf_field_type_structure_create_func ft_struct_create_func) +{ + int ret = 0; + + BT_LOGD("Initializing common event class object: name=\"%s\"", + name); + bt_ctf_object_init_shared_with_parent(&event_class->base, release_func); + event_class->payload_field_type = ft_struct_create_func(); + if (!event_class->payload_field_type) { + BT_LOGE_STR("Cannot create event class's initial payload field type object."); + goto error; + } + + event_class->id = -1; + event_class->name = g_string_new(name); + if (!event_class->name) { + BT_LOGE_STR("Failed to allocate a GString."); + goto error; + } + + event_class->emf_uri = g_string_new(NULL); + if (!event_class->emf_uri) { + BT_LOGE_STR("Failed to allocate a GString."); + goto error; + } + + event_class->log_level = BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED; + BT_LOGD("Initialized common event class object: addr=%p, name=\"%s\"", + event_class, bt_ctf_event_class_common_get_name(event_class)); + return ret; + +error: + ret = -1; + return ret; +} + +BT_HIDDEN +void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *event_class) +{ + BT_ASSERT(event_class); + + if (event_class->frozen) { + return; + } + + BT_LOGD("Freezing event class: addr=%p, name=\"%s\", id=%" PRId64, + event_class, bt_ctf_event_class_common_get_name(event_class), + bt_ctf_event_class_common_get_id(event_class)); + event_class->frozen = 1; + BT_LOGD_STR("Freezing event class's context field type."); + bt_ctf_field_type_common_freeze(event_class->context_field_type); + BT_LOGD_STR("Freezing event class's payload field type."); + bt_ctf_field_type_common_freeze(event_class->payload_field_type); +} + +BT_HIDDEN +int bt_ctf_event_class_common_validate_single_clock_class( + struct bt_ctf_event_class_common *event_class, + struct bt_ctf_clock_class **expected_clock_class) +{ + int ret = 0; + + BT_ASSERT(event_class); + BT_ASSERT(expected_clock_class); + ret = bt_ctf_field_type_common_validate_single_clock_class( + event_class->context_field_type, + expected_clock_class); + if (ret) { + BT_LOGW("Event class's context field type " + "is not recursively mapped to the " + "expected clock class: " + "event-class-addr=%p, " + "event-class-name=\"%s\", " + "event-class-id=%" PRId64 ", " + "ft-addr=%p", + event_class, + bt_ctf_event_class_common_get_name(event_class), + event_class->id, + event_class->context_field_type); + goto end; + } + + ret = bt_ctf_field_type_common_validate_single_clock_class( + event_class->payload_field_type, + expected_clock_class); + if (ret) { + BT_LOGW("Event class's payload field type " + "is not recursively mapped to the " + "expected clock class: " + "event-class-addr=%p, " + "event-class-name=\"%s\", " + "event-class-id=%" PRId64 ", " + "ft-addr=%p", + event_class, + bt_ctf_event_class_common_get_name(event_class), + event_class->id, + event_class->payload_field_type); + goto end; + } + +end: + return ret; +} + +static +void bt_ctf_event_class_destroy(struct bt_ctf_object *obj) +{ + bt_ctf_event_class_common_finalize(obj); + g_free(obj); +} + +struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name) +{ + struct bt_ctf_event_class *ctf_event_class = NULL; + int ret; + + if (!name) { + BT_LOGW_STR("Invalid parameter: name is NULL."); + goto error; + } + + BT_LOGD("Creating event class object: name=\"%s\"", + name); + ctf_event_class = g_new0(struct bt_ctf_event_class, 1); + if (!ctf_event_class) { + BT_LOGE_STR("Failed to allocate one event class."); + goto error; + } + + ret = bt_ctf_event_class_common_initialize(BT_CTF_TO_COMMON(ctf_event_class), + name, bt_ctf_event_class_destroy, + (bt_ctf_field_type_structure_create_func) + bt_ctf_field_type_structure_create); + if (ret) { + goto error; + } + + goto end; + +error: + bt_ctf_object_put_ref(ctf_event_class); + +end: + return ctf_event_class; +} + +const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class) +{ + return bt_ctf_event_class_common_get_name(BT_CTF_TO_COMMON(event_class)); +} + +int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class) +{ + return bt_ctf_event_class_common_get_id(BT_CTF_TO_COMMON(event_class)); +} + +int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class, + uint64_t id) +{ + return bt_ctf_event_class_common_set_id(BT_CTF_TO_COMMON(event_class), id); +} + +enum bt_ctf_event_class_log_level bt_ctf_event_class_get_log_level( + struct bt_ctf_event_class *event_class) +{ + return bt_ctf_event_class_common_get_log_level(BT_CTF_TO_COMMON(event_class)); +} + +int bt_ctf_event_class_set_log_level(struct bt_ctf_event_class *event_class, + enum bt_ctf_event_class_log_level log_level) +{ + return bt_ctf_event_class_common_set_log_level(BT_CTF_TO_COMMON(event_class), + log_level); +} + +const char *bt_ctf_event_class_get_emf_uri( + struct bt_ctf_event_class *event_class) +{ + return bt_ctf_event_class_common_get_emf_uri(BT_CTF_TO_COMMON(event_class)); +} + +int bt_ctf_event_class_set_emf_uri(struct bt_ctf_event_class *event_class, + const char *emf_uri) +{ + return bt_ctf_event_class_common_set_emf_uri(BT_CTF_TO_COMMON(event_class), + emf_uri); +} + +struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class( + struct bt_ctf_event_class *event_class) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); + return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_stream_class( + BT_CTF_TO_COMMON(event_class))); +} + +struct bt_ctf_field_type *bt_ctf_event_class_get_payload_field_type( + struct bt_ctf_event_class *event_class) +{ + return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_payload_field_type( + BT_CTF_TO_COMMON(event_class))); +} + +int bt_ctf_event_class_set_payload_field_type( + struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *field_type) +{ + return bt_ctf_event_class_common_set_payload_field_type( + BT_CTF_TO_COMMON(event_class), (void *) field_type); +} + +struct bt_ctf_field_type *bt_ctf_event_class_get_context_field_type( + struct bt_ctf_event_class *event_class) +{ + return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_context_field_type( + BT_CTF_TO_COMMON(event_class))); +} + +int bt_ctf_event_class_set_context_field_type( + struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *field_type) +{ + return bt_ctf_event_class_common_set_context_field_type( + BT_CTF_TO_COMMON(event_class), (void *) field_type); +} + +int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *type, + const char *name) +{ + int ret = 0; + + if (!event_class || !type) { + BT_LOGW("Invalid parameter: event class or field type is NULL: " + "event-class-addr=%p, field-type-addr=%p", + event_class, type); + ret = -1; + goto end; + } + + if (!bt_ctf_identifier_is_valid(name)) { + BT_LOGW("Invalid parameter: event class's payload field type's field name is not a valid CTF identifier: " + "addr=%p, name=\"%s\", id=%" PRId64 ", field-name=\"%s\"", + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class), + name); + ret = -1; + goto end; + } + + if (event_class->common.frozen) { + BT_LOGW("Invalid parameter: event class is frozen: " + "addr=%p, name=\"%s\", id=%" PRId64, + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class)); + ret = -1; + goto end; + } + + if (!event_class->common.payload_field_type) { + BT_LOGW("Event class has no payload field type: " + "addr=%p, name=\"%s\", id=%" PRId64, + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class)); + ret = -1; + goto end; + } + + BT_ASSERT(bt_ctf_field_type_common_get_type_id( + event_class->common.payload_field_type) == + BT_CTF_FIELD_TYPE_ID_STRUCT); + ret = bt_ctf_field_type_structure_add_field( + (void *) event_class->common.payload_field_type, + (void *) type, name); + BT_LOGV("Added field to event class's payload field type: " + "event-class-addr=%p, event-class-name=\"%s\", " + "event-class-id=%" PRId64 ", field-name=\"%s\", ft-addr=%p", + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class), name, type); +end: + return ret; +} + +int64_t bt_ctf_event_class_get_payload_type_field_count( + struct bt_ctf_event_class *event_class) +{ + int64_t ret; + + if (!event_class) { + BT_LOGW_STR("Invalid parameter: event class is NULL."); + ret = (int64_t) -1; + goto end; + } + + if (!event_class->common.payload_field_type) { + BT_LOGV("Event class has no payload field type: " + "addr=%p, name=\"%s\", id=%" PRId64, + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class)); + ret = (int64_t) -1; + goto end; + } + + BT_ASSERT(bt_ctf_field_type_common_get_type_id( + event_class->common.payload_field_type) == + BT_CTF_FIELD_TYPE_ID_STRUCT); + ret = bt_ctf_field_type_common_structure_get_field_count( + event_class->common.payload_field_type); +end: + return ret; +} + +int bt_ctf_event_class_get_payload_type_field_by_index( + struct bt_ctf_event_class *event_class, + const char **field_name, struct bt_ctf_field_type **field_type, + uint64_t index) +{ + int ret; + + if (!event_class) { + BT_LOGW_STR("Invalid parameter: event class is NULL."); + ret = -1; + goto end; + } + + if (!event_class->common.payload_field_type) { + BT_LOGV("Event class has no payload field type: " + "addr=%p, name=\"%s\", id=%" PRId64 ", index=%" PRIu64, + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class), index); + ret = -1; + goto end; + } + + BT_ASSERT(bt_ctf_field_type_common_get_type_id( + event_class->common.payload_field_type) == + BT_CTF_FIELD_TYPE_ID_STRUCT); + ret = bt_ctf_field_type_structure_get_field_by_index( + (void *) event_class->common.payload_field_type, + field_name, (void *) field_type, index); + +end: + return ret; +} + +struct bt_ctf_field_type * +bt_ctf_event_class_get_payload_type_field_type_by_name( + struct bt_ctf_event_class *event_class, const char *name) +{ + GQuark name_quark; + struct bt_ctf_field_type *field_type = NULL; + + if (!event_class || !name) { + BT_LOGW("Invalid parameter: event class or name is NULL: " + "event-class-addr=%p, name-addr=%p", + event_class, name); + goto end; + } + + if (!event_class->common.payload_field_type) { + BT_LOGV("Event class has no payload field type: " + "addr=%p, name=\"%s\", id=%" PRId64, + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class)); + goto end; + } + + BT_ASSERT(bt_ctf_field_type_common_get_type_id( + event_class->common.payload_field_type) == + BT_CTF_FIELD_TYPE_ID_STRUCT); + name_quark = g_quark_try_string(name); + if (!name_quark) { + BT_LOGE("Cannot get GQuark: string=\"%s\"", name); + goto end; + } + + /* + * No need to increment field_type's reference count since getting it + * from the structure already does. + */ + field_type = (void *) + bt_ctf_field_type_structure_get_field_type_by_name( + (void *) event_class->common.payload_field_type, name); + +end: + return field_type; +} + +BT_HIDDEN +int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class, + struct metadata_context *context) +{ + int ret = 0; + struct bt_ctf_value *attr_value = NULL; + + BT_ASSERT(event_class); + BT_ASSERT(context); + BT_LOGD("Serializing event class's metadata: " + "event-class-addr=%p, event-class-name=\"%s\", " + "event-class-id=%" PRId64 ", metadata-context-addr=%p", + event_class, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class), context); + context->current_indentation_level = 1; + g_string_assign(context->field_name, ""); + g_string_append(context->string, "event {\n"); + + /* Serialize attributes */ + g_string_append_printf(context->string, "\tname = \"%s\";\n", + event_class->common.name->str); + BT_ASSERT(event_class->common.id >= 0); + g_string_append_printf(context->string, "\tid = %" PRId64 ";\n", + event_class->common.id); + g_string_append_printf(context->string, "\tstream_id = %" PRId64 ";\n", + bt_ctf_stream_class_common_get_id( + bt_ctf_event_class_common_borrow_stream_class( + BT_CTF_TO_COMMON(event_class)))); + + if (event_class->common.log_level != + BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) { + g_string_append_printf(context->string, "\tloglevel = %d;\n", + (int) event_class->common.log_level); + } + + if (event_class->common.emf_uri->len > 0) { + g_string_append_printf(context->string, "\tmodel.emf.uri = \"%s\";\n", + event_class->common.emf_uri->str); + } + + /* Serialize context field type */ + if (event_class->common.context_field_type) { + g_string_append(context->string, "\tcontext := "); + BT_LOGD_STR("Serializing event class's context field type metadata."); + ret = bt_ctf_field_type_serialize_recursive( + (void *) event_class->common.context_field_type, + context); + if (ret) { + BT_LOGW("Cannot serialize event class's context field type's metadata: " + "ret=%d", ret); + goto end; + } + g_string_append(context->string, ";\n"); + } + + /* Serialize payload field type */ + if (event_class->common.payload_field_type) { + g_string_append(context->string, "\tfields := "); + BT_LOGD_STR("Serializing event class's payload field type metadata."); + ret = bt_ctf_field_type_serialize_recursive( + (void *) event_class->common.payload_field_type, + context); + if (ret) { + BT_LOGW("Cannot serialize event class's payload field type's metadata: " + "ret=%d", ret); + goto end; + } + g_string_append(context->string, ";\n"); + } + + g_string_append(context->string, "};\n\n"); + +end: + context->current_indentation_level = 0; + BT_CTF_OBJECT_PUT_REF_AND_RESET(attr_value); + return ret; +} + +struct bt_ctf_field_type *bt_ctf_event_class_get_field_by_name( + struct bt_ctf_event_class *event_class, const char *name) +{ + GQuark name_quark; + struct bt_ctf_field_type *field_type = NULL; + + if (!event_class || !name) { + BT_LOGW("Invalid parameter: event class or name is NULL: " + "event-class-addr=%p, name-addr=%p", + event_class, name); + goto end; + } + + if (!event_class->common.payload_field_type) { + BT_LOGV("Event class has no payload field type: " + "addr=%p, name=\"%s\", id=%" PRId64, + event_class, + bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class)); + goto end; + } + + BT_ASSERT(event_class->common.payload_field_type->id == + BT_CTF_FIELD_TYPE_ID_STRUCT); + name_quark = g_quark_try_string(name); + if (!name_quark) { + BT_LOGE("Cannot get GQuark: string=\"%s\"", name); + goto end; + } + + /* + * No need to increment field_type's reference count since getting it + * from the structure already does. + */ + field_type = bt_ctf_object_get_ref( + bt_ctf_field_type_common_structure_borrow_field_type_by_name( + event_class->common.payload_field_type, name)); + +end: + return field_type; +} diff --git a/ctf-writer/event.c b/ctf-writer/event.c new file mode 100644 index 00000000..b074cdb1 --- /dev/null +++ b/ctf-writer/event.c @@ -0,0 +1,900 @@ +/* + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2017-2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-EVENT" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +int bt_ctf_event_common_validate_types_for_create( + struct bt_ctf_event_class_common *event_class, + struct bt_ctf_validation_output *validation_output, + bt_ctf_validation_flag_copy_field_type_func copy_field_type_func) +{ + int ret; + enum bt_ctf_validation_flag validation_flags = + BT_CTF_VALIDATION_FLAG_STREAM | + BT_CTF_VALIDATION_FLAG_EVENT; + struct bt_ctf_trace_common *trace = NULL; + struct bt_ctf_stream_class_common *stream_class = NULL; + struct bt_ctf_field_type_common *packet_header_type = NULL; + struct bt_ctf_field_type_common *packet_context_type = NULL; + struct bt_ctf_field_type_common *event_header_type = NULL; + struct bt_ctf_field_type_common *stream_event_ctx_type = NULL; + struct bt_ctf_field_type_common *event_context_type = NULL; + struct bt_ctf_field_type_common *event_payload_type = NULL; + int trace_valid = 0; + struct bt_ctf_private_value *environment = NULL; + + stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class); + BT_ASSERT(stream_class); + trace = bt_ctf_stream_class_common_borrow_trace(stream_class); + if (trace) { + BT_LOGD_STR("Event class is part of a trace."); + packet_header_type = + bt_ctf_trace_common_borrow_packet_header_field_type(trace); + trace_valid = trace->valid; + BT_ASSERT(trace_valid); + environment = trace->environment; + } + + packet_context_type = + bt_ctf_stream_class_common_borrow_packet_context_field_type( + stream_class); + event_header_type = + bt_ctf_stream_class_common_borrow_event_header_field_type( + stream_class); + stream_event_ctx_type = + bt_ctf_stream_class_common_borrow_event_context_field_type( + stream_class); + event_context_type = + bt_ctf_event_class_common_borrow_context_field_type(event_class); + event_payload_type = + bt_ctf_event_class_common_borrow_payload_field_type(event_class); + ret = bt_ctf_validate_class_types(environment, packet_header_type, + packet_context_type, event_header_type, stream_event_ctx_type, + event_context_type, event_payload_type, trace_valid, + stream_class->valid, event_class->valid, + validation_output, validation_flags, copy_field_type_func); + if (ret) { + /* + * This means something went wrong during the validation + * process, not that the objects are invalid. + */ + BT_LOGE("Failed to validate event and parents: ret=%d", ret); + goto error; + } + + if ((validation_output->valid_flags & validation_flags) != + validation_flags) { + /* Invalid trace/stream class/event class */ + BT_LOGW("Invalid trace, stream class, or event class: " + "valid-flags=0x%x", validation_output->valid_flags); + goto error; + } + + goto end; + +error: + bt_ctf_validation_output_put_types(validation_output); + ret = -1; + +end: + return ret; +} + +static +int bt_ctf_event_common_create_fields( + struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_validation_output *validation_output, + create_field_func create_field_func, + release_field_func release_field_func, + create_header_field_func create_header_field_func, + release_header_field_func release_header_field_func, + struct bt_ctf_field_wrapper **header_field, + struct bt_ctf_field_common **stream_event_context_field, + struct bt_ctf_field_common **context_field, + struct bt_ctf_field_common **payload_field) +{ + int ret = 0; + + if (validation_output->event_header_type) { + BT_LOGD("Creating initial event header field: ft-addr=%p", + validation_output->event_header_type); + *header_field = + create_header_field_func(stream_class, + validation_output->event_header_type); + if (!*header_field) { + BT_LOGE_STR("Cannot create initial event header field object."); + goto error; + } + } + + if (validation_output->stream_event_ctx_type) { + BT_LOGD("Creating initial stream event context field: ft-addr=%p", + validation_output->stream_event_ctx_type); + *stream_event_context_field = create_field_func( + validation_output->stream_event_ctx_type); + if (!*stream_event_context_field) { + BT_LOGE_STR("Cannot create initial stream event context field object."); + goto error; + } + } + + if (validation_output->event_context_type) { + BT_LOGD("Creating initial event context field: ft-addr=%p", + validation_output->event_context_type); + *context_field = create_field_func( + validation_output->event_context_type); + if (!*context_field) { + BT_LOGE_STR("Cannot create initial event context field object."); + goto error; + } + } + + if (validation_output->event_payload_type) { + BT_LOGD("Creating initial event payload field: ft-addr=%p", + validation_output->event_payload_type); + *payload_field = create_field_func( + validation_output->event_payload_type); + if (!*payload_field) { + BT_LOGE_STR("Cannot create initial event payload field object."); + goto error; + } + } + + goto end; + +error: + if (*header_field) { + release_header_field_func(*header_field, stream_class); + } + + if (*stream_event_context_field) { + release_field_func(*stream_event_context_field); + } + + if (*context_field) { + release_field_func(*context_field); + } + + if (*payload_field) { + release_field_func(*payload_field); + } + + ret = -1; + +end: + return ret; +} + +BT_HIDDEN +int _bt_ctf_event_common_validate(struct bt_ctf_event_common *event) +{ + int ret = 0; + struct bt_ctf_stream_class_common *stream_class; + + BT_ASSERT(event); + if (event->header_field) { + ret = bt_ctf_field_common_validate_recursive( + event->header_field->field); + if (ret) { + BT_CTF_ASSERT_PRE_MSG("Invalid event's header field: " + "event-addr=%p, field-addr=%p", + event, event->header_field->field); + goto end; + } + } + + stream_class = bt_ctf_event_class_common_borrow_stream_class(event->class); + + /* + * We should not have been able to create the event without associating + * the event class to a stream class. + */ + BT_ASSERT(stream_class); + + if (stream_class->event_context_field_type) { + ret = bt_ctf_field_common_validate_recursive( + event->stream_event_context_field); + if (ret) { + BT_CTF_ASSERT_PRE_MSG("Invalid event's stream event context field: " + "event-addr=%p, field-addr=%p", + event, event->stream_event_context_field); + goto end; + } + } + + if (event->class->context_field_type) { + ret = bt_ctf_field_common_validate_recursive(event->context_field); + if (ret) { + BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: " + "event-addr=%p, field-addr=%p", + event, event->context_field); + goto end; + } + } + + ret = bt_ctf_field_common_validate_recursive(event->payload_field); + if (ret) { + BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: " + "event-addr=%p, field-addr=%p", + event, event->payload_field); + goto end; + } + +end: + return ret; +} + +BT_HIDDEN +void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event, + bool is_frozen) +{ + BT_ASSERT(event); + BT_LOGD("Freezing event: addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64, + event, bt_ctf_event_class_common_get_name(event->class), + bt_ctf_event_class_common_get_id(event->class)); + + if (event->header_field) { + BT_LOGD_STR("Freezing event's header field."); + bt_ctf_field_common_set_is_frozen_recursive( + event->header_field->field, is_frozen); + } + + if (event->stream_event_context_field) { + BT_LOGD_STR("Freezing event's stream event context field."); + bt_ctf_field_common_set_is_frozen_recursive( + event->stream_event_context_field, is_frozen); + } + + if (event->context_field) { + BT_LOGD_STR("Freezing event's context field."); + bt_ctf_field_common_set_is_frozen_recursive(event->context_field, + is_frozen); + } + + if (event->payload_field) { + BT_LOGD_STR("Freezing event's payload field."); + bt_ctf_field_common_set_is_frozen_recursive(event->payload_field, + is_frozen); + } + + event->frozen = is_frozen; +} + +BT_HIDDEN +int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event, + struct bt_ctf_event_class_common *event_class, + struct bt_ctf_clock_class *init_expected_clock_class, + bool is_shared_with_parent, bt_ctf_object_release_func release_func, + bt_ctf_validation_flag_copy_field_type_func field_type_copy_func, + bool must_be_in_trace, + int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_field_type_common *packet_context_field_type, + struct bt_ctf_field_type_common *event_header_field_type), + create_field_func create_field_func, + release_field_func release_field_func, + create_header_field_func create_header_field_func, + release_header_field_func release_header_field_func) +{ + int ret; + struct bt_ctf_trace_common *trace = NULL; + struct bt_ctf_stream_class_common *stream_class = NULL; + struct bt_ctf_field_wrapper *event_header = NULL; + struct bt_ctf_field_common *stream_event_context = NULL; + struct bt_ctf_field_common *event_context = NULL; + struct bt_ctf_field_common *event_payload = NULL; + struct bt_ctf_validation_output validation_output = { 0 }; + struct bt_ctf_clock_class *expected_clock_class = + init_expected_clock_class ? bt_ctf_object_get_ref(init_expected_clock_class) : + NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_LOGD("Initializing common event object: event-class-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64, + event_class, bt_ctf_event_class_common_get_name(event_class), + bt_ctf_event_class_common_get_id(event_class)); + + stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class); + BT_CTF_ASSERT_PRE(stream_class, + "Event class is not part of a stream class: event-class-addr=%p", + event_class); + + /* The event class was frozen when added to its stream class */ + BT_ASSERT(event_class->frozen); + trace = bt_ctf_stream_class_common_borrow_trace(stream_class); + + if (must_be_in_trace) { + BT_CTF_ASSERT_PRE(trace, + "Event class's stream class is not part of a trace: " + "ec-addr=%p, sc-addr=%p", event_class, stream_class); + } + + /* + * This must be called before anything that can fail because on + * failure, the caller releases the reference to `event` to + * destroy it. + */ + if (is_shared_with_parent) { + bt_ctf_object_init_shared_with_parent(&event->base, release_func); + } else { + bt_ctf_object_init_unique(&event->base); + } + + if (!stream_class->frozen) { + /* + * Because this function freezes the stream class, + * validate that this stream class contains at most a + * single clock class so that we set its expected clock + * class for future checks. + */ + ret = bt_ctf_stream_class_common_validate_single_clock_class( + stream_class, &expected_clock_class); + if (ret) { + BT_LOGW("Event class's stream class or one of its event " + "classes contains a field type which is not " + "recursively mapped to the expected " + "clock class: " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", " + "stream-class-name=\"%s\", " + "expected-clock-class-addr=%p, " + "expected-clock-class-name=\"%s\"", + stream_class, + bt_ctf_stream_class_common_get_id(stream_class), + bt_ctf_stream_class_common_get_name(stream_class), + expected_clock_class, + expected_clock_class ? + bt_ctf_clock_class_get_name(expected_clock_class) : + NULL); + goto error; + } + } + + /* Validate the trace, the stream class, and the event class */ + ret = bt_ctf_event_common_validate_types_for_create( + event_class, &validation_output, field_type_copy_func); + if (ret) { + /* bt_ctf_event_common_validate_types_for_create() logs errors */ + goto error; + } + + if (map_clock_classes_func) { + /* + * Safe to automatically map selected fields to the + * stream's clock's class here because the stream class + * is about to be frozen. + */ + if (map_clock_classes_func(stream_class, + validation_output.packet_context_type, + validation_output.event_header_type)) { + BT_LOGW_STR("Cannot automatically map selected stream class's " + "field types to stream class's clock's class."); + goto error; + } + } + + /* + * event does not share a common ancestor with the event class; it has + * to guarantee its existence by holding a reference. This reference + * shall be released once the event is associated to a stream since, + * from that point, the event and its class will share the same + * lifetime. + */ + event->class = bt_ctf_object_get_ref(event_class); + + ret = bt_ctf_event_common_create_fields(stream_class, + &validation_output, + create_field_func, release_field_func, + create_header_field_func, release_header_field_func, + &event_header, &stream_event_context, &event_context, + &event_payload); + if (ret) { + /* bt_ctf_event_common_create_fields() logs errors */ + goto error; + } + + /* + * At this point all the fields are created, potentially from + * validated copies of field types, so that the field types and + * fields can be replaced in the trace, stream class, + * event class, and created event. + */ + bt_ctf_validation_replace_types(trace, stream_class, event_class, + &validation_output, + BT_CTF_VALIDATION_FLAG_STREAM | BT_CTF_VALIDATION_FLAG_EVENT); + event->header_field = event_header; + event_header = NULL; + event->stream_event_context_field = stream_event_context; + stream_event_context = NULL; + event->context_field = event_context; + event_context = NULL; + event->payload_field = event_payload; + event_payload = NULL; + + /* + * Put what was not moved in bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&validation_output); + + /* + * Freeze the stream class since the event header must not be changed + * anymore. + */ + bt_ctf_stream_class_common_freeze(stream_class); + + /* + * It is safe to set the stream class's unique clock class + * now because the stream class is frozen. + */ + if (expected_clock_class) { + BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class); + } + + /* + * Mark stream class, and event class as valid since + * they're all frozen now. + */ + stream_class->valid = 1; + event_class->valid = 1; + + /* Put stuff we borrowed from the event class */ + BT_LOGD("Initialized event object: addr=%p, event-class-name=\"%s\", " + "event-class-id=%" PRId64, + event, bt_ctf_event_class_common_get_name(event->class), + bt_ctf_event_class_common_get_id(event->class)); + goto end; + +error: + bt_ctf_validation_output_put_types(&validation_output); + bt_ctf_object_put_ref(expected_clock_class); + + if (event_header) { + release_header_field_func(event_header, stream_class); + } + + if (stream_event_context) { + release_field_func(stream_event_context); + } + + if (event_context) { + release_field_func(event_context); + } + + if (event_payload) { + release_field_func(event_payload); + } + + ret = -1; + +end: + return ret; +} + +int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_field_type_common *packet_context_type, + struct bt_ctf_field_type_common *event_header_type) +{ + int ret = bt_ctf_stream_class_map_clock_class( + BT_CTF_FROM_COMMON(stream_class), + BT_CTF_FROM_COMMON(packet_context_type), + BT_CTF_FROM_COMMON(event_header_type)); + + if (ret) { + BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class."); + } + + return ret; +} + +static +void destroy_event_header_field(struct bt_ctf_field_wrapper *field_wrapper) +{ + BT_ASSERT(field_wrapper); + bt_ctf_object_put_ref(field_wrapper->field); + bt_ctf_field_wrapper_destroy(field_wrapper); +} + +static +struct bt_ctf_field_wrapper *create_event_header_field( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_wrapper *field_wrapper = NULL; + struct bt_ctf_field *field = bt_ctf_field_create((void *) ft); + + if (!field) { + goto error; + } + + field_wrapper = bt_ctf_field_wrapper_new(NULL); + if (!field_wrapper) { + goto error; + } + + field_wrapper->field = (void *) field; + field = NULL; + goto end; + +error: + bt_ctf_object_put_ref(field); + + if (field_wrapper) { + destroy_event_header_field(field_wrapper); + field_wrapper = NULL; + } + +end: + return field_wrapper; +} + +static +void release_event_header_field(struct bt_ctf_field_wrapper *field_wrapper, + struct bt_ctf_event_common *event_common) +{ + BT_ASSERT(field_wrapper); + BT_CTF_OBJECT_PUT_REF_AND_RESET(field_wrapper->field); + bt_ctf_field_wrapper_destroy(field_wrapper); +} + +static +void bt_ctf_event_destroy(struct bt_ctf_object *obj) +{ + bt_ctf_event_common_finalize(obj, (void *) bt_ctf_object_put_ref, + (void *) release_event_header_field); + g_free(obj); +} + +struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class) +{ + int ret; + struct bt_ctf_event *event = NULL; + struct bt_ctf_clock_class *expected_clock_class = NULL; + + event = g_new0(struct bt_ctf_event, 1); + if (!event) { + BT_LOGE_STR("Failed to allocate one CTF writer event."); + goto error; + } + + if (event_class) { + struct bt_ctf_stream_class *stream_class = + BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class( + BT_CTF_TO_COMMON(event_class))); + + if (stream_class && stream_class->clock) { + expected_clock_class = stream_class->clock->clock_class; + } + } + + ret = bt_ctf_event_common_initialize(BT_CTF_TO_COMMON(event), + BT_CTF_TO_COMMON(event_class), expected_clock_class, + true, bt_ctf_event_destroy, + (bt_ctf_validation_flag_copy_field_type_func) + bt_ctf_field_type_copy, + false, map_clock_classes_func, + (create_field_func) bt_ctf_field_create, + (release_field_func) bt_ctf_object_put_ref, + (create_header_field_func) create_event_header_field, + (release_header_field_func) destroy_event_header_field); + if (ret) { + /* bt_ctf_event_common_initialize() logs errors */ + goto error; + } + + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(event); + +end: + return event; +} + +struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))); +} + +BT_HIDDEN +struct bt_ctf_stream *bt_ctf_event_borrow_stream(struct bt_ctf_event *event) +{ + BT_ASSERT(event); + return (struct bt_ctf_stream *) + bt_ctf_object_borrow_parent(&BT_CTF_TO_COMMON(event)->base); +} + +struct bt_ctf_stream *bt_ctf_event_get_stream(struct bt_ctf_event *event) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + return bt_ctf_object_get_ref(bt_ctf_event_borrow_stream(event)); +} + +int bt_ctf_event_set_payload(struct bt_ctf_event *event, const char *name, + struct bt_ctf_field *field) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_NON_NULL(field, "Payload field"); + BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); + return bt_ctf_field_structure_set_field_by_name( + (void *) event->common.payload_field, name, field); +} + +struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event, + const char *name) +{ + struct bt_ctf_field *field = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + + if (name) { + field = bt_ctf_field_structure_get_field_by_name( + BT_CTF_FROM_COMMON(event->common.payload_field), name); + } else { + field = BT_CTF_FROM_COMMON(event->common.payload_field); + bt_ctf_object_get_ref(field); + } + + return field; +} + +struct bt_ctf_field *bt_ctf_event_get_payload_field( + struct bt_ctf_event *event) +{ + return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_payload(BT_CTF_TO_COMMON(event))); +} + +struct bt_ctf_field *bt_ctf_event_get_header(struct bt_ctf_event *event) +{ + return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_header(BT_CTF_TO_COMMON(event))); +} + +struct bt_ctf_field *bt_ctf_event_get_context(struct bt_ctf_event *event) +{ + return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_context(BT_CTF_TO_COMMON(event))); +} + +struct bt_ctf_field *bt_ctf_event_get_stream_event_context( + struct bt_ctf_event *event) +{ + return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_stream_event_context( + BT_CTF_TO_COMMON(event))); +} + +BT_HIDDEN +int bt_ctf_event_serialize(struct bt_ctf_event *event, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + int ret = 0; + + BT_ASSERT(event); + BT_ASSERT(ctfser); + + BT_LOGV_STR("Serializing event's context field."); + if (event->common.context_field) { + ret = bt_ctf_field_serialize_recursive( + (void *) event->common.context_field, ctfser, + native_byte_order); + if (ret) { + BT_LOGW("Cannot serialize event's context field: " + "event-addr=%p, event-class-name=\"%s\", " + "event-class-id=%" PRId64, + event, + bt_ctf_event_class_common_get_name(event->common.class), + bt_ctf_event_class_common_get_id(event->common.class)); + goto end; + } + } + + BT_LOGV_STR("Serializing event's payload field."); + if (event->common.payload_field) { + ret = bt_ctf_field_serialize_recursive( + (void *) event->common.payload_field, ctfser, + native_byte_order); + if (ret) { + BT_LOGW("Cannot serialize event's payload field: " + "event-addr=%p, event-class-name=\"%s\", " + "event-class-id=%" PRId64, + event, + bt_ctf_event_class_common_get_name(event->common.class), + bt_ctf_event_class_common_get_id(event->common.class)); + goto end; + } + } + +end: + return ret; +} + +BT_HIDDEN +void _bt_ctf_event_freeze(struct bt_ctf_event *event) +{ + _bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true); +} + +int bt_ctf_event_set_header(struct bt_ctf_event *event, + struct bt_ctf_field *header) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); + + /* + * Ensure the provided header's type matches the one registered to the + * stream class. + */ + if (header) { + BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare( + ((struct bt_ctf_field_common *) header)->type, + bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type) == 0, + "Header field's type is different from the " + "expected field type: event-addr=%p, ft-addr=%p, " + "expected-ft-addr=%p", + event, ((struct bt_ctf_field_common *) header)->type, + bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type); + } else { + BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type, + "Setting no event header field, " + "but event header field type is not NULL: " + "event-addr=%p, header-ft-addr=%p", + event, + bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type); + } + + bt_ctf_object_put_ref(event->common.header_field->field); + event->common.header_field->field = bt_ctf_object_get_ref(header); + BT_LOGV("Set event's header field: event-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64 ", " + "header-field-addr=%p", + event, bt_ctf_event_class_common_get_name(event->common.class), + bt_ctf_event_class_common_get_id(event->common.class), header); + return 0; +} + +int bt_ctf_event_common_set_payload(struct bt_ctf_event *event, + struct bt_ctf_field *payload) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); + + if (payload) { + BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare( + ((struct bt_ctf_field_common *) payload)->type, + event->common.class->payload_field_type) == 0, + "Payload field's type is different from the " + "expected field type: event-addr=%p, ft-addr=%p, " + "expected-ft-addr=%p", + event, + ((struct bt_ctf_field_common *) payload)->type, + event->common.class->payload_field_type); + } else { + BT_CTF_ASSERT_PRE(!event->common.class->payload_field_type, + "Setting no event payload field, " + "but event payload field type is not NULL: " + "event-addr=%p, payload-ft-addr=%p", + event, event->common.class->payload_field_type); + } + + bt_ctf_object_put_ref(event->common.payload_field); + event->common.payload_field = bt_ctf_object_get_ref(payload); + BT_LOGV("Set event's payload field: event-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64 ", " + "payload-field-addr=%p", + event, bt_ctf_event_class_common_get_name(event->common.class), + bt_ctf_event_class_common_get_id(event->common.class), payload); + return 0; +} + +int bt_ctf_event_set_context(struct bt_ctf_event *event, + struct bt_ctf_field *context) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); + + if (context) { + BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare( + ((struct bt_ctf_field_common *) context)->type, + event->common.class->context_field_type) == 0, + "Context field's type is different from the " + "expected field type: event-addr=%p, ft-addr=%p, " + "expected-ft-addr=%p", + event, ((struct bt_ctf_field_common *) context)->type, + event->common.class->context_field_type); + } else { + BT_CTF_ASSERT_PRE(!event->common.class->context_field_type, + "Setting no event context field, " + "but event context field type is not NULL: " + "event-addr=%p, context-ft-addr=%p", + event, event->common.class->context_field_type); + } + + bt_ctf_object_put_ref(event->common.context_field); + event->common.context_field = bt_ctf_object_get_ref(context); + BT_LOGV("Set event's context field: event-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64 ", " + "context-field-addr=%p", + event, bt_ctf_event_class_common_get_name(event->common.class), + bt_ctf_event_class_common_get_id(event->common.class), context); + return 0; +} + +int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event, + struct bt_ctf_field *stream_event_context) +{ + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); + + if (stream_event_context) { + BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare( + ((struct bt_ctf_field_common *) stream_event_context)->type, + bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type) == 0, + "Stream event context field's type is different from the " + "expected field type: event-addr=%p, ft-addr=%p, " + "expected-ft-addr=%p", + event, + ((struct bt_ctf_field_common *) stream_event_context)->type, + bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type); + } else { + BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type, + "Setting no stream event context field, " + "but stream event context field type is not NULL: " + "event-addr=%p, context-ft-addr=%p", + event, + bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type); + } + + bt_ctf_object_put_ref(event->common.stream_event_context_field); + event->common.stream_event_context_field = bt_ctf_object_get_ref(stream_event_context); + BT_LOGV("Set event's stream event context field: event-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64 ", " + "stream-event-context-field-addr=%p", + event, bt_ctf_event_class_common_get_name(event->common.class), + bt_ctf_event_class_common_get_id(event->common.class), + stream_event_context); + return 0; +} diff --git a/ctf-writer/field-path.c b/ctf-writer/field-path.c new file mode 100644 index 00000000..284e850d --- /dev/null +++ b/ctf-writer/field-path.c @@ -0,0 +1,172 @@ +/* + * field-path.c + * + * Babeltrace CTF writer - Field path + * + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2016 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-FIELD-PATH" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static +void field_path_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_path *field_path = (struct bt_ctf_field_path *) obj; + + BT_LOGD("Destroying field path: addr=%p", obj); + + if (!field_path) { + return; + } + + if (field_path->indexes) { + g_array_free(field_path->indexes, TRUE); + } + g_free(field_path); +} + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_create(void) +{ + struct bt_ctf_field_path *field_path = NULL; + + BT_LOGD_STR("Creating empty field path object."); + + field_path = g_new0(struct bt_ctf_field_path, 1); + if (!field_path) { + BT_LOGE_STR("Failed to allocate one field path."); + goto error; + } + + bt_ctf_object_init_shared(&field_path->base, field_path_destroy); + field_path->root = BT_CTF_SCOPE_UNKNOWN; + field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int)); + if (!field_path->indexes) { + BT_LOGE_STR("Failed to allocate a GArray."); + goto error; + } + + BT_LOGD("Created empty field path object: addr=%p", field_path); + return field_path; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path); + return NULL; +} + +BT_HIDDEN +void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path) +{ + if (field_path->indexes->len > 0) { + g_array_remove_range(field_path->indexes, 0, + field_path->indexes->len); + } +} + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_copy( + struct bt_ctf_field_path *path) +{ + struct bt_ctf_field_path *new_path; + + BT_ASSERT(path); + BT_LOGD("Copying field path: addr=%p, index-count=%u", + path, path->indexes->len); + new_path = bt_ctf_field_path_create(); + if (!new_path) { + BT_LOGE_STR("Cannot create empty field path."); + goto end; + } + + new_path->root = path->root; + g_array_insert_vals(new_path->indexes, 0, + path->indexes->data, path->indexes->len); + BT_LOGD("Copied field path: original-addr=%p, copy-addr=%p", + path, new_path); +end: + return new_path; +} + +enum bt_ctf_scope bt_ctf_field_path_get_root_scope( + const struct bt_ctf_field_path *field_path) +{ + enum bt_ctf_scope scope = BT_CTF_SCOPE_UNKNOWN; + + if (!field_path) { + BT_LOGW_STR("Invalid parameter: field path is NULL."); + goto end; + } + + scope = field_path->root; + +end: + return scope; +} + +int64_t bt_ctf_field_path_get_index_count( + const struct bt_ctf_field_path *field_path) +{ + int64_t count = (int64_t) -1; + + if (!field_path) { + BT_LOGW_STR("Invalid parameter: field path is NULL."); + goto end; + } + + count = (int64_t) field_path->indexes->len; + +end: + return count; +} + +int bt_ctf_field_path_get_index(const struct bt_ctf_field_path *field_path, + uint64_t index) +{ + int ret = INT_MIN; + + if (!field_path) { + BT_LOGW_STR("Invalid parameter: field path is NULL."); + goto end; + } + + if (index >= field_path->indexes->len) { + BT_LOGW("Invalid parameter: index is out of bounds: " + "addr=%p, index=%" PRIu64 ", count=%u", + field_path, index, field_path->indexes->len); + goto end; + } + + ret = g_array_index(field_path->indexes, int, index); + +end: + return ret; +} diff --git a/ctf-writer/field-types.c b/ctf-writer/field-types.c new file mode 100644 index 00000000..2d18c45c --- /dev/null +++ b/ctf-writer/field-types.c @@ -0,0 +1,5564 @@ +/* + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-FIELD-TYPES" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void destroy_enumeration_mapping(struct bt_ctf_enumeration_mapping *mapping) +{ + g_free(mapping); +} + +BT_HIDDEN +void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft, + bool init_bo, bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + BT_ASSERT(ft && (ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN) && + (ft->id < BT_CTF_FIELD_TYPE_ID_NR)); + + bt_ctf_object_init_shared(&ft->base, release_func); + ft->methods = methods; + + if (init_bo) { + int ret; + const enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_NATIVE; + + BT_LOGD("Setting initial field type's byte order: bo=%s", + bt_ctf_byte_order_string(bo)); + ret = bt_ctf_field_type_common_set_byte_order(ft, bo); + BT_ASSERT(ret == 0); + } + + ft->alignment = 1; +} + +BT_HIDDEN +void bt_ctf_field_type_common_integer_initialize( + struct bt_ctf_field_type_common *ft, + unsigned int size, bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + BT_ASSERT(size > 0); + BT_LOGD("Initializing common integer field type object: size=%u", + size); + ft->id = BT_CTF_FIELD_TYPE_ID_INTEGER; + int_ft->size = size; + int_ft->base = BT_CTF_INTEGER_BASE_DECIMAL; + int_ft->encoding = BT_CTF_STRING_ENCODING_NONE; + bt_ctf_field_type_common_initialize(ft, true, release_func, methods); + BT_LOGD("Initialized common integer field type object: addr=%p, size=%u", + ft, size); +} + +BT_HIDDEN +void bt_ctf_field_type_common_floating_point_initialize( + struct bt_ctf_field_type_common *ft, + bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); + + BT_LOGD_STR("Initializing common floating point number field type object."); + ft->id = BT_CTF_FIELD_TYPE_ID_FLOAT; + flt_ft->exp_dig = sizeof(float) * CHAR_BIT - FLT_MANT_DIG; + flt_ft->mant_dig = FLT_MANT_DIG; + bt_ctf_field_type_common_initialize(ft, true, release_func, methods); + BT_LOGD("Initialized common floating point number field type object: addr=%p, " + "exp-size=%u, mant-size=%u", ft, flt_ft->exp_dig, + flt_ft->mant_dig); +} + +BT_HIDDEN +void bt_ctf_field_type_common_enumeration_initialize( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *container_ft, + bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + + BT_ASSERT(container_ft); + BT_LOGD("Initializing common enumeration field type object: int-ft-addr=%p", + container_ft); + ft->id = BT_CTF_FIELD_TYPE_ID_ENUM; + enum_ft->container_ft = bt_ctf_object_get_ref(container_ft); + enum_ft->entries = g_ptr_array_new_with_free_func( + (GDestroyNotify) destroy_enumeration_mapping); + bt_ctf_field_type_common_initialize(ft, false, release_func, methods); + BT_LOGD("Initialized common enumeration field type object: addr=%p, " + "int-ft-addr=%p, int-ft-size=%u", ft, container_ft, + bt_ctf_field_type_common_integer_get_size(container_ft)); +} + +BT_HIDDEN +void bt_ctf_field_type_common_string_initialize( + struct bt_ctf_field_type_common *ft, + bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft); + + BT_LOGD_STR("Initializing common string field type object."); + ft->id = BT_CTF_FIELD_TYPE_ID_STRING; + bt_ctf_field_type_common_initialize(ft, true, release_func, methods); + string_ft->encoding = BT_CTF_STRING_ENCODING_UTF8; + ft->alignment = CHAR_BIT; + BT_LOGD("Initialized common string field type object: addr=%p", ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_structure_initialize( + struct bt_ctf_field_type_common *ft, + bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + + BT_LOGD_STR("Initializing common structure field type object."); + ft->id = BT_CTF_FIELD_TYPE_ID_STRUCT; + struct_ft->fields = g_array_new(FALSE, TRUE, + sizeof(struct bt_ctf_field_type_common_structure_field)); + struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL); + bt_ctf_field_type_common_initialize(ft, true, release_func, methods); + BT_LOGD("Initialized common structure field type object: addr=%p", ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_array_initialize( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *element_ft, + unsigned int length, bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); + + BT_ASSERT(element_ft); + BT_LOGD("Initializing common array field type object: element-ft-addr=%p, " + "length=%u", element_ft, length); + ft->id = BT_CTF_FIELD_TYPE_ID_ARRAY; + array_ft->element_ft = bt_ctf_object_get_ref(element_ft); + array_ft->length = length; + bt_ctf_field_type_common_initialize(ft, false, release_func, methods); + BT_LOGD("Initialized common array field type object: addr=%p, " + "element-ft-addr=%p, length=%u", ft, element_ft, length); +} + +BT_HIDDEN +void bt_ctf_field_type_common_sequence_initialize( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *element_ft, + const char *length_field_name, + bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + BT_ASSERT(element_ft); + BT_ASSERT(length_field_name); + BT_ASSERT(bt_ctf_identifier_is_valid(length_field_name)); + BT_LOGD("Initializing common sequence field type object: element-ft-addr=%p, " + "length-field-name=\"%s\"", element_ft, length_field_name); + ft->id = BT_CTF_FIELD_TYPE_ID_SEQUENCE; + seq_ft->element_ft = bt_ctf_object_get_ref(element_ft); + seq_ft->length_field_name = g_string_new(length_field_name); + bt_ctf_field_type_common_initialize(ft, false, release_func, methods); + BT_LOGD("Initialized common sequence field type object: addr=%p, " + "element-ft-addr=%p, length-field-name=\"%s\"", + ft, element_ft, length_field_name); +} + +BT_HIDDEN +void bt_ctf_field_type_common_variant_initialize( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *tag_ft, + const char *tag_name, + bt_ctf_object_release_func release_func, + struct bt_ctf_field_type_common_methods *methods) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + BT_ASSERT(!tag_name || bt_ctf_identifier_is_valid(tag_name)); + BT_LOGD("Initializing common variant field type object: " + "tag-ft-addr=%p, tag-field-name=\"%s\"", + tag_ft, tag_name); + ft->id = BT_CTF_FIELD_TYPE_ID_VARIANT; + var_ft->tag_name = g_string_new(tag_name); + var_ft->choice_name_to_index = g_hash_table_new(NULL, NULL); + var_ft->choices = g_array_new(FALSE, TRUE, + sizeof(struct bt_ctf_field_type_common_variant_choice)); + + if (tag_ft) { + var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft); + } + + bt_ctf_field_type_common_initialize(ft, true, release_func, methods); + /* A variant's alignment is undefined */ + ft->alignment = 0; + BT_LOGD("Initialized common variant field type object: addr=%p, " + "tag-ft-addr=%p, tag-field-name=\"%s\"", + ft, tag_ft, tag_name); +} + +BT_HIDDEN +void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_integer *ft = (void *) obj; + + if (!ft) { + return; + } + + BT_LOGD("Destroying integer field type object: addr=%p", ft); + BT_LOGD_STR("Putting mapped clock class."); + bt_ctf_object_put_ref(ft->mapped_clock_class); + g_free(ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_floating_point *ft = (void *) obj; + + if (!ft) { + return; + } + + BT_LOGD("Destroying floating point number field type object: addr=%p", ft); + g_free(ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_enumeration *ft = (void *) obj; + + if (!ft) { + return; + } + + BT_LOGD("Destroying enumeration field type object: addr=%p", ft); + g_ptr_array_free(ft->entries, TRUE); + BT_LOGD_STR("Putting container field type."); + bt_ctf_object_put_ref(ft->container_ft); + g_free(ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_string *ft = (void *) obj; + + if (!ft) { + return; + } + + BT_LOGD("Destroying string field type object: addr=%p", ft); + g_free(ft); +} + +static +void bt_ctf_field_type_common_structure_field_finalize( + struct bt_ctf_field_type_common_structure_field *field) +{ + if (!field) { + return; + } + + BT_LOGD("Finalizing structure field type's field: " + "addr=%p, field-ft-addr=%p, field-name=\"%s\"", + field, field->type, g_quark_to_string(field->name)); + BT_LOGD_STR("Putting field type."); + bt_ctf_object_put_ref(field->type); +} + +BT_HIDDEN +void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_structure *ft = (void *) obj; + uint64_t i; + + if (!ft) { + return; + } + + BT_LOGD("Destroying structure field type object: addr=%p", ft); + + if (ft->fields) { + for (i = 0; i < ft->fields->len; i++) { + bt_ctf_field_type_common_structure_field_finalize( + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + ft, i)); + } + + g_array_free(ft->fields, TRUE); + } + + if (ft->field_name_to_index) { + g_hash_table_destroy(ft->field_name_to_index); + } + + g_free(ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_array *ft = (void *) obj; + + if (!ft) { + return; + } + + BT_LOGD("Destroying array field type object: addr=%p", ft); + BT_LOGD_STR("Putting element field type."); + bt_ctf_object_put_ref(ft->element_ft); + g_free(ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_sequence *ft = (void *) obj; + + if (!ft) { + return; + } + + BT_LOGD("Destroying sequence field type object: addr=%p", ft); + BT_LOGD_STR("Putting element field type."); + bt_ctf_object_put_ref(ft->element_ft); + g_string_free(ft->length_field_name, TRUE); + BT_LOGD_STR("Putting length field path."); + bt_ctf_object_put_ref(ft->length_field_path); + g_free(ft); +} + +static +void bt_ctf_field_type_common_variant_choice_finalize( + struct bt_ctf_field_type_common_variant_choice *choice) +{ + if (!choice) { + return; + } + + BT_LOGD("Finalizing variant field type's choice: " + "addr=%p, field-ft-addr=%p, field-name=\"%s\"", + choice, choice->type, g_quark_to_string(choice->name)); + BT_LOGD_STR("Putting field type."); + bt_ctf_object_put_ref(choice->type); + + if (choice->ranges) { + g_array_free(choice->ranges, TRUE); + } +} + +BT_HIDDEN +void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_common_variant *ft = (void *) obj; + uint64_t i; + + if (!ft) { + return; + } + + BT_LOGD("Destroying variant field type object: addr=%p", ft); + + if (ft->choices) { + for (i = 0; i < ft->choices->len; i++) { + bt_ctf_field_type_common_variant_choice_finalize( + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + ft, i)); + } + + g_array_free(ft->choices, TRUE); + } + + if (ft->choice_name_to_index) { + g_hash_table_destroy(ft->choice_name_to_index); + } + + if (ft->tag_name) { + g_string_free(ft->tag_name, TRUE); + } + + BT_LOGD_STR("Putting tag field type."); + bt_ctf_object_put_ref(ft->tag_ft); + BT_LOGD_STR("Putting tag field path."); + bt_ctf_object_put_ref(ft->tag_field_path); + g_free(ft); +} + +struct range_overlap_query { + union { + uint64_t _unsigned; + int64_t _signed; + } range_start; + + union { + uint64_t _unsigned; + int64_t _signed; + } range_end; + int overlaps; + GQuark mapping_name; +}; + +static +void check_ranges_overlap(gpointer element, gpointer query) +{ + struct bt_ctf_enumeration_mapping *mapping = element; + struct range_overlap_query *overlap_query = query; + + if (mapping->range_start._signed <= overlap_query->range_end._signed + && overlap_query->range_start._signed <= + mapping->range_end._signed) { + overlap_query->overlaps = 1; + overlap_query->mapping_name = mapping->string; + } + + overlap_query->overlaps |= + mapping->string == overlap_query->mapping_name; + + if (overlap_query->overlaps) { + BT_LOGV("Overlapping enumeration field type mappings: " + "mapping-name=\"%s\", " + "mapping-a-range-start=%" PRId64 ", " + "mapping-a-range-end=%" PRId64 ", " + "mapping-b-range-start=%" PRId64 ", " + "mapping-b-range-end=%" PRId64, + g_quark_to_string(mapping->string), + mapping->range_start._signed, + mapping->range_end._signed, + overlap_query->range_start._signed, + overlap_query->range_end._signed); + } +} + +static +void check_ranges_overlap_unsigned(gpointer element, gpointer query) +{ + struct bt_ctf_enumeration_mapping *mapping = element; + struct range_overlap_query *overlap_query = query; + + if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned + && overlap_query->range_start._unsigned <= + mapping->range_end._unsigned) { + overlap_query->overlaps = 1; + overlap_query->mapping_name = mapping->string; + } + + overlap_query->overlaps |= + mapping->string == overlap_query->mapping_name; + + if (overlap_query->overlaps) { + BT_LOGW("Overlapping enumeration field type mappings: " + "mapping-name=\"%s\", " + "mapping-a-range-start=%" PRIu64 ", " + "mapping-a-range-end=%" PRIu64 ", " + "mapping-b-range-start=%" PRIu64 ", " + "mapping-b-range-end=%" PRIu64, + g_quark_to_string(mapping->string), + mapping->range_start._unsigned, + mapping->range_end._unsigned, + overlap_query->range_start._unsigned, + overlap_query->range_end._unsigned); + } +} + +static +gint compare_enumeration_mappings_signed(struct bt_ctf_enumeration_mapping **a, + struct bt_ctf_enumeration_mapping **b) +{ + return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1; +} + +static +gint compare_enumeration_mappings_unsigned(struct bt_ctf_enumeration_mapping **a, + struct bt_ctf_enumeration_mapping **b) +{ + return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1; +} + +static +int add_structure_variant_member(GArray *members, + GHashTable *field_name_to_index, + struct bt_ctf_field_type_common *field_type, const char *field_name, + bool is_variant) +{ + int ret = 0; + GQuark name_quark = g_quark_from_string(field_name); + struct bt_ctf_field_type_common **member_ft; + GQuark *member_name; + + /* Make sure structure does not contain a field of the same name */ + if (g_hash_table_lookup_extended(field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, NULL)) { + BT_LOGW("Structure or variant field type already contains a field type with this name: " + "field-name=\"%s\"", field_name); + ret = -1; + goto end; + } + + g_array_set_size(members, members->len + 1); + + if (is_variant) { + struct bt_ctf_field_type_common_variant_choice *choice = + &g_array_index(members, + struct bt_ctf_field_type_common_variant_choice, + members->len - 1); + + member_ft = &choice->type; + member_name = &choice->name; + BT_ASSERT(!choice->ranges); + choice->ranges = g_array_new(FALSE, TRUE, + sizeof(struct bt_ctf_field_type_common_variant_choice_range)); + BT_ASSERT(choice->ranges); + } else { + struct bt_ctf_field_type_common_structure_field *field = + &g_array_index(members, + struct bt_ctf_field_type_common_structure_field, + members->len - 1); + + member_ft = &field->type; + member_name = &field->name; + } + + *member_name = name_quark; + *member_ft = bt_ctf_object_get_ref(field_type); + g_hash_table_insert(field_name_to_index, + GUINT_TO_POINTER(name_quark), + GUINT_TO_POINTER(members->len - 1)); + BT_LOGV("Added structure/variant field type member: member-ft-addr=%p, " + "member-name=\"%s\"", field_type, field_name); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft) +{ + int ret = 0; + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + if (int_ft->mapped_clock_class && int_ft->is_signed) { + BT_LOGW("Invalid integer field type: cannot be signed and have a mapped clock class: " + "ft-addr=%p, clock-class-addr=%p, clock-class-name=\"%s\"", + ft, int_ft->mapped_clock_class, + bt_ctf_clock_class_get_name(int_ft->mapped_clock_class)); + ret = -1; + goto end; + } + +end: + return ret; +} + +static +void bt_ctf_field_type_enum_iter_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_field_type_enumeration_mapping_iterator *iter = + container_of(obj, + struct bt_ctf_field_type_enumeration_mapping_iterator, + base); + + BT_LOGD("Destroying enumeration field type mapping iterator: addr=%p", + obj); + BT_LOGD_STR("Putting parent enumeration field type."); + bt_ctf_object_put_ref(iter->enumeration_ft); + g_free(iter); +} + +static +struct bt_ctf_field_type_enumeration_mapping_iterator * +bt_ctf_field_type_common_enumeration_find_mappings_type( + struct bt_ctf_field_type_common *ft, + enum bt_ctf_field_type_enumeration_mapping_iterator_type iterator_type) +{ + struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, + "Field type"); + iter = g_new0(struct bt_ctf_field_type_enumeration_mapping_iterator, 1); + if (!iter) { + BT_LOGE_STR("Failed to allocate one enumeration field type mapping."); + goto end; + } + + bt_ctf_object_init_shared(&iter->base, bt_ctf_field_type_enum_iter_destroy); + iter->enumeration_ft = bt_ctf_object_get_ref(ft); + iter->index = -1; + iter->type = iterator_type; + +end: + return iter; +} + +BT_HIDDEN +struct bt_ctf_field_type_enumeration_mapping_iterator * +bt_ctf_field_type_common_enumeration_find_mappings_by_name( + struct bt_ctf_field_type_common *ft, const char *name) +{ + struct bt_ctf_field_type_enumeration_mapping_iterator *iter; + + iter = bt_ctf_field_type_common_enumeration_find_mappings_type( + ft, CTF_ITERATOR_BY_NAME); + if (!iter) { + BT_LOGW("Cannot create enumeration field type mapping iterator: " + "ft-addr=%p, mapping-name=\"%s\"", ft, name); + goto error; + } + + iter->u.name_quark = g_quark_try_string(name); + if (!iter->u.name_quark) { + /* + * No results are possible, set the iterator's position at the + * end. + */ + iter->index = iter->enumeration_ft->entries->len; + } + + return iter; + +error: + bt_ctf_object_put_ref(iter); + return NULL; +} + +static +struct bt_ctf_enumeration_mapping *bt_ctf_field_type_common_enumeration_get_mapping_by_index( + struct bt_ctf_field_type_common *ft, uint64_t index) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + struct bt_ctf_enumeration_mapping *mapping = NULL; + + if (index >= enum_ft->entries->len) { + BT_LOGW("Invalid parameter: index is out of bounds: " + "addr=%p, index=%" PRIu64 ", count=%u", + ft, index, enum_ft->entries->len); + goto end; + } + + mapping = g_ptr_array_index(enum_ft->entries, index); + +end: + return mapping; +} + +BT_HIDDEN +int bt_ctf_field_type_enumeration_mapping_iterator_next( + struct bt_ctf_field_type_enumeration_mapping_iterator *iter) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = iter->enumeration_ft; + int i, ret = 0, len; + + BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator"); + len = enum_ft->entries->len; + for (i = iter->index + 1; i < len; i++) { + struct bt_ctf_enumeration_mapping *mapping = + bt_ctf_field_type_common_enumeration_get_mapping_by_index( + BT_CTF_TO_COMMON(enum_ft), i); + + switch (iter->type) { + case CTF_ITERATOR_BY_NAME: + if (mapping->string == iter->u.name_quark) { + iter->index = i; + goto end; + } + break; + case CTF_ITERATOR_BY_SIGNED_VALUE: + { + int64_t value = iter->u.signed_value; + + if (value >= mapping->range_start._signed && + value <= mapping->range_end._signed) { + iter->index = i; + goto end; + } + break; + } + case CTF_ITERATOR_BY_UNSIGNED_VALUE: + { + uint64_t value = iter->u.unsigned_value; + + if (value >= mapping->range_start._unsigned && + value <= mapping->range_end._unsigned) { + iter->index = i; + goto end; + } + break; + } + default: + BT_LOGF("Invalid enumeration field type mapping iterator type: " + "type=%d", iter->type); + abort(); + } + } + + ret = -1; + +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_field_type_enumeration_mapping_iterator * +bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value( + struct bt_ctf_field_type_common *ft, int64_t value) +{ + struct bt_ctf_field_type_enumeration_mapping_iterator *iter; + + iter = bt_ctf_field_type_common_enumeration_find_mappings_type( + ft, CTF_ITERATOR_BY_SIGNED_VALUE); + if (!iter) { + BT_LOGW("Cannot create enumeration field type mapping iterator: " + "ft-addr=%p, value=%" PRId64, ft, value); + goto error; + } + + if (bt_ctf_field_type_common_integer_is_signed( + BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 1) { + BT_LOGW("Invalid parameter: enumeration field type is unsigned: " + "enum-ft-addr=%p, int-ft-addr=%p", + ft, iter->enumeration_ft->container_ft); + goto error; + } + + iter->u.signed_value = value; + return iter; + +error: + bt_ctf_object_put_ref(iter); + return NULL; +} + +BT_HIDDEN +struct bt_ctf_field_type_enumeration_mapping_iterator * +bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value( + struct bt_ctf_field_type_common *ft, uint64_t value) +{ + struct bt_ctf_field_type_enumeration_mapping_iterator *iter; + + iter = bt_ctf_field_type_common_enumeration_find_mappings_type( + ft, CTF_ITERATOR_BY_UNSIGNED_VALUE); + if (!iter) { + BT_LOGW("Cannot create enumeration field type mapping iterator: " + "ft-addr=%p, value=%" PRIu64, ft, value); + goto error; + } + + if (bt_ctf_field_type_common_integer_is_signed( + BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 0) { + BT_LOGW("Invalid parameter: enumeration field type is signed: " + "enum-ft-addr=%p, int-ft-addr=%p", + ft, iter->enumeration_ft->container_ft); + goto error; + } + + iter->u.unsigned_value = value; + return iter; + +error: + bt_ctf_object_put_ref(iter); + return NULL; +} + +BT_HIDDEN +int bt_ctf_field_type_enumeration_mapping_iterator_signed_get( + struct bt_ctf_field_type_enumeration_mapping_iterator *iter, + const char **mapping_name, int64_t *range_begin, + int64_t *range_end) +{ + BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator"); + BT_CTF_ASSERT_PRE(iter->index != -1, + "Invalid enumeration field type mapping iterator access: " + "addr=%p, position=-1", iter); + return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index( + (void *) iter->enumeration_ft, iter->index, + mapping_name, range_begin, range_end); +} + +BT_HIDDEN +int bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get( + struct bt_ctf_field_type_enumeration_mapping_iterator *iter, + const char **mapping_name, uint64_t *range_begin, + uint64_t *range_end) +{ + BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator"); + BT_CTF_ASSERT_PRE(iter->index != -1, + "Invalid enumeration field type mapping iterator access: " + "addr=%p, position=-1", iter); + return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index( + (void *) iter->enumeration_ft, iter->index, + mapping_name, range_begin, range_end); +} + +/* + * Note: This algorithm is O(n^2) vs number of enumeration mappings. + * Only used when freezing an enumeration. + */ +static +void bt_ctf_field_type_common_enumeration_set_range_overlap( + struct bt_ctf_field_type_common_enumeration *ft) +{ + int64_t i, j, len; + int is_signed; + + BT_LOGV("Setting enumeration field type's overlap flag: addr=%p", + ft); + len = ft->entries->len; + is_signed = bt_ctf_field_type_common_integer_is_signed( + BT_CTF_TO_COMMON(ft->container_ft)); + + for (i = 0; i < len; i++) { + for (j = i + 1; j < len; j++) { + struct bt_ctf_enumeration_mapping *mapping[2]; + + mapping[0] = bt_ctf_field_type_common_enumeration_get_mapping_by_index( + BT_CTF_TO_COMMON(ft), i); + mapping[1] = bt_ctf_field_type_common_enumeration_get_mapping_by_index( + BT_CTF_TO_COMMON(ft), j); + if (is_signed) { + if (mapping[0]->range_start._signed + <= mapping[1]->range_end._signed + && mapping[0]->range_end._signed + >= mapping[1]->range_start._signed) { + ft->has_overlapping_ranges = BT_TRUE; + goto end; + } + } else { + if (mapping[0]->range_start._unsigned + <= mapping[1]->range_end._unsigned + && mapping[0]->range_end._unsigned + >= mapping[1]->range_start._unsigned) { + ft->has_overlapping_ranges = BT_TRUE; + goto end; + } + } + } + } + +end: + if (ft->has_overlapping_ranges) { + BT_LOGV_STR("Enumeration field type has overlapping ranges."); + } else { + BT_LOGV_STR("Enumeration field type has no overlapping ranges."); + } +} + +BT_HIDDEN +int bt_ctf_field_type_common_enumeration_validate_recursive( + struct bt_ctf_field_type_common *ft) +{ + int ret = 0; + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + + ret = bt_ctf_field_type_common_integer_validate( + BT_CTF_TO_COMMON(enum_ft->container_ft)); + if (ret) { + BT_LOGW("Invalid enumeration field type: container type is invalid: " + "enum-ft-addr=%p, int-ft-addr=%p", + ft, enum_ft->container_ft); + goto end; + } + + /* Ensure enum has entries */ + if (enum_ft->entries->len == 0) { + BT_LOGW("Invalid enumeration field type: no entries: " + "addr=%p", ft); + ret = -1; + goto end; + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_sequence_validate_recursive( + struct bt_ctf_field_type_common *ft) +{ + int ret = 0; + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + /* Length field name should be set at this point */ + if (seq_ft->length_field_name->len == 0) { + BT_LOGW("Invalid sequence field type: no length field name: " + "addr=%p", ft); + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_common_validate(seq_ft->element_ft); + if (ret) { + BT_LOGW("Invalid sequence field type: invalid element field type: " + "seq-ft-addr=%p, element-ft-add=%p", + ft, seq_ft->element_ft); + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_array_validate_recursive( + struct bt_ctf_field_type_common *ft) +{ + int ret = 0; + struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); + + ret = bt_ctf_field_type_common_validate(array_ft->element_ft); + if (ret) { + BT_LOGW("Invalid array field type: invalid element field type: " + "array-ft-addr=%p, element-ft-add=%p", + ft, array_ft->element_ft); + } + + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_structure_validate_recursive( + struct bt_ctf_field_type_common *ft) +{ + int ret = 0; + struct bt_ctf_field_type_common *child_ft = NULL; + int64_t field_count = + bt_ctf_field_type_common_structure_get_field_count(ft); + int64_t i; + + BT_ASSERT(field_count >= 0); + + for (i = 0; i < field_count; ++i) { + const char *field_name; + + ret = bt_ctf_field_type_common_structure_borrow_field_by_index(ft, + &field_name, &child_ft, i); + BT_ASSERT(ret == 0); + ret = bt_ctf_field_type_common_validate(child_ft); + if (ret) { + BT_LOGW("Invalid structure field type: " + "a contained field type is invalid: " + "struct-ft-addr=%p, field-ft-addr=%p, " + "field-name=\"%s\", field-index=%" PRId64, + ft, child_ft, field_name, i); + goto end; + } + } + +end: + return ret; +} + +static +bt_bool bt_ctf_field_type_common_enumeration_has_overlapping_ranges( + struct bt_ctf_field_type_common_enumeration *enum_ft) +{ + if (!enum_ft->common.frozen) { + bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft); + } + + return enum_ft->has_overlapping_ranges; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_validate_recursive( + struct bt_ctf_field_type_common *ft) +{ + int ret = 0; + int64_t field_count; + struct bt_ctf_field_type_common *child_ft = NULL; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + int64_t i; + + if (var_ft->tag_name->len == 0) { + BT_LOGW("Invalid variant field type: no tag field name: " + "addr=%p", ft); + ret = -1; + goto end; + } + + if (!var_ft->tag_ft) { + BT_LOGW("Invalid variant field type: no tag field type: " + "addr=%p, tag-field-name=\"%s\"", var_ft, + var_ft->tag_name->str); + ret = -1; + goto end; + } + + if (bt_ctf_field_type_common_enumeration_has_overlapping_ranges(var_ft->tag_ft)) { + BT_LOGW("Invalid variant field type: enumeration tag field type has overlapping ranges: " + "variant-ft-addr=%p, tag-field-name=\"%s\", " + "enum-ft-addr=%p", ft, var_ft->tag_name->str, + var_ft->tag_ft); + ret = -1; + goto end; + } + + /* + * It is valid to have a variant field type which does not have + * the fields corresponding to each label in the associated + * enumeration. + * + * It is also valid to have variant field type fields which + * cannot be selected because the variant field type tag has no + * mapping named as such. This scenario, while not ideal, cannot + * cause any error. + * + * If a non-existing field happens to be selected by an + * enumeration while reading a variant field, an error will be + * generated at that point (while reading the stream). + */ + field_count = bt_ctf_field_type_common_variant_get_field_count(ft); + if (field_count < 0) { + BT_LOGW("Invalid variant field type: no fields: " + "addr=%p, tag-field-name=\"%s\"", + ft, var_ft->tag_name->str); + ret = -1; + goto end; + } + + for (i = 0; i < field_count; ++i) { + const char *field_name; + + ret = bt_ctf_field_type_common_variant_borrow_field_by_index(ft, + &field_name, &child_ft, i); + BT_ASSERT(ret == 0); + ret = bt_ctf_field_type_common_validate(child_ft); + if (ret) { + BT_LOGW("Invalid variant field type: " + "a contained field type is invalid: " + "variant-ft-addr=%p, tag-field-name=\"%s\", " + "field-ft-addr=%p, field-name=\"%s\", " + "field-index=%" PRId64, + ft, var_ft->tag_name->str, child_ft, + field_name, i); + goto end; + } + } + +end: + return ret; +} + +/* + * This function validates a given field type without considering + * where this field type is located. It only validates the properties + * of the given field type and the properties of its children if + * applicable. + */ +BT_HIDDEN +int bt_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft) +{ + int ret = 0; + + BT_ASSERT(ft); + + if (ft->valid) { + /* Already marked as valid */ + goto end; + } + + if (ft->methods->validate) { + ret = ft->methods->validate(ft); + } + + if (ret == 0 && ft->frozen) { + /* Field type is valid */ + BT_LOGV("Marking field type as valid: addr=%p", ft); + ft->valid = 1; + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, + "Field type"); + return (int) int_ft->size; +} + +BT_HIDDEN +bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, + "Field type"); + return int_ft->is_signed; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft, + bt_bool is_signed) +{ + int ret = 0; + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid parameter: field type is not an integer field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + int_ft->is_signed = !!is_signed; + BT_LOGV("Set integer field type's signedness: addr=%p, is-signed=%d", + ft, is_signed); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft, + unsigned int size) +{ + int ret = 0; + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid parameter: field type is not an integer field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (size == 0 || size > 64) { + BT_LOGW("Invalid parameter: size must be between 1 and 64: " + "addr=%p, size=%u", ft, size); + ret = -1; + goto end; + } + + int_ft->size = size; + BT_LOGV("Set integer field type's size: addr=%p, size=%u", + ft, size); + +end: + return ret; +} + +BT_HIDDEN +enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, + "Field type"); + return int_ft->base; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft, + enum bt_ctf_integer_base base) +{ + int ret = 0; + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid parameter: field type is not an integer field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + switch (base) { + case BT_CTF_INTEGER_BASE_UNSPECIFIED: + case BT_CTF_INTEGER_BASE_BINARY: + case BT_CTF_INTEGER_BASE_OCTAL: + case BT_CTF_INTEGER_BASE_DECIMAL: + case BT_CTF_INTEGER_BASE_HEXADECIMAL: + { + int_ft->base = base; + break; + } + default: + BT_LOGW("Invalid parameter: unknown integer field type base: " + "addr=%p, base=%d", ft, base); + ret = -1; + } + + BT_LOGV("Set integer field type's base: addr=%p, base=%s", + ft, bt_ctf_integer_base_string(base)); + +end: + return ret; +} + +BT_HIDDEN +enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, + "Field type"); + return int_ft->encoding; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft, + enum bt_ctf_string_encoding encoding) +{ + int ret = 0; + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid parameter: field type is not an integer field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (encoding != BT_CTF_STRING_ENCODING_UTF8 && + encoding != BT_CTF_STRING_ENCODING_ASCII && + encoding != BT_CTF_STRING_ENCODING_NONE) { + BT_LOGW("Invalid parameter: unknown string encoding: " + "addr=%p, encoding=%d", ft, encoding); + ret = -1; + goto end; + } + + int_ft->encoding = encoding; + BT_LOGV("Set integer field type's encoding: addr=%p, encoding=%s", + ft, bt_ctf_string_encoding_string(encoding)); + +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, + "Field type"); + return int_ft->mapped_clock_class; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_clock_class *clock_class) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + int ret = 0; + + if (!clock_class) { + BT_LOGW_STR("Invalid parameter: clock class is NULL."); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid parameter: field type is not an integer field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + goto end; + } + + if (!bt_ctf_clock_class_is_valid(clock_class)) { + BT_LOGW("Invalid parameter: clock class is invalid: ft-addr=%p" + "clock-class-addr=%p, clock-class-name=\"%s\"", + ft, clock_class, + bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + bt_ctf_object_put_ref(int_ft->mapped_clock_class); + int_ft->mapped_clock_class = bt_ctf_object_get_ref(clock_class); + BT_LOGV("Set integer field type's mapped clock class: ft-addr=%p, " + "clock-class-addr=%p, clock-class-name=\"%s\"", + ft, clock_class, bt_ctf_clock_class_get_name(clock_class)); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_integer_set_mapped_clock_class( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_clock_class *clock_class) +{ + int ret = 0; + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen( + ft, clock_class); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index( + struct bt_ctf_field_type_common *ft, uint64_t index, + const char **mapping_name, int64_t *range_begin, + int64_t *range_end) +{ + int ret = 0; + struct bt_ctf_enumeration_mapping *mapping; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, + BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); + mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(ft, + index); + if (!mapping) { + /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() logs errors */ + ret = -1; + goto end; + } + + if (mapping_name) { + *mapping_name = g_quark_to_string(mapping->string); + BT_ASSERT(*mapping_name); + } + + if (range_begin) { + *range_begin = mapping->range_start._signed; + } + + if (range_end) { + *range_end = mapping->range_end._signed; + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index( + struct bt_ctf_field_type_common *ft, uint64_t index, + const char **mapping_name, uint64_t *range_begin, + uint64_t *range_end) +{ + int ret = 0; + struct bt_ctf_enumeration_mapping *mapping; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); + mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index( + ft, index); + if (!mapping) { + /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() reports any error */ + ret = -1; + goto end; + } + + if (mapping_name) { + *mapping_name = g_quark_to_string(mapping->string); + BT_ASSERT(*mapping_name); + } + + if (range_begin) { + *range_begin = mapping->range_start._unsigned; + } + + if (range_end) { + *range_end = mapping->range_end._unsigned; + } + +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_field_type_common * +bt_ctf_field_type_common_enumeration_borrow_container_field_type( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); + return BT_CTF_TO_COMMON(enum_ft->container_ft); +} + +BT_HIDDEN +int bt_ctf_field_type_common_enumeration_signed_add_mapping( + struct bt_ctf_field_type_common *ft, const char *string, + int64_t range_start, int64_t range_end) +{ + int ret = 0; + GQuark mapping_name; + struct bt_ctf_enumeration_mapping *mapping; + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + char *escaped_string; + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (!string) { + BT_LOGW_STR("Invalid parameter: string is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) { + BT_LOGW("Invalid parameter: field type is not an enumeration field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (range_end < range_start) { + BT_LOGW("Invalid parameter: range's end is lesser than range's start: " + "addr=%p, range-start=%" PRId64 ", range-end=%" PRId64, + ft, range_start, range_end); + ret = -1; + goto end; + } + + if (strlen(string) == 0) { + BT_LOGW("Invalid parameter: mapping name is an empty string: " + "enum-ft-addr=%p, mapping-name-addr=%p", ft, + string); + ret = -1; + goto end; + } + + escaped_string = g_strescape(string, NULL); + if (!escaped_string) { + BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, " + "mapping-name-addr=%p, mapping-name=\"%s\"", + ft, string, string); + ret = -1; + goto end; + } + + mapping = g_new(struct bt_ctf_enumeration_mapping, 1); + if (!mapping) { + BT_LOGE_STR("Failed to allocate one enumeration mapping."); + ret = -1; + goto error_free; + } + mapping_name = g_quark_from_string(escaped_string); + *mapping = (struct bt_ctf_enumeration_mapping) { + .range_start._signed = range_start, + .range_end._signed = range_end, + .string = mapping_name, + }; + g_ptr_array_add(enum_ft->entries, mapping); + g_ptr_array_sort(enum_ft->entries, + (GCompareFunc) compare_enumeration_mappings_signed); + BT_LOGV("Added mapping to signed enumeration field type: addr=%p, " + "name=\"%s\", range-start=%" PRId64 ", " + "range-end=%" PRId64, + ft, string, range_start, range_end); + +error_free: + free(escaped_string); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_enumeration_unsigned_add_mapping( + struct bt_ctf_field_type_common *ft, const char *string, + uint64_t range_start, uint64_t range_end) +{ + int ret = 0; + GQuark mapping_name; + struct bt_ctf_enumeration_mapping *mapping; + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + char *escaped_string; + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (!string) { + BT_LOGW_STR("Invalid parameter: string is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) { + BT_LOGW("Invalid parameter: field type is not an enumeration field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (range_end < range_start) { + BT_LOGW("Invalid parameter: range's end is lesser than range's start: " + "addr=%p, range-start=%" PRIu64 ", range-end=%" PRIu64, + ft, range_start, range_end); + ret = -1; + goto end; + } + + if (strlen(string) == 0) { + BT_LOGW("Invalid parameter: mapping name is an empty string: " + "enum-ft-addr=%p, mapping-name-addr=%p", ft, + string); + ret = -1; + goto end; + } + + escaped_string = g_strescape(string, NULL); + if (!escaped_string) { + BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, " + "mapping-name-addr=%p, mapping-name=\"%s\"", + ft, string, string); + ret = -1; + goto end; + } + + mapping = g_new(struct bt_ctf_enumeration_mapping, 1); + if (!mapping) { + BT_LOGE_STR("Failed to allocate one enumeration mapping."); + ret = -1; + goto error_free; + } + mapping_name = g_quark_from_string(escaped_string); + *mapping = (struct bt_ctf_enumeration_mapping) { + .range_start._unsigned = range_start, + .range_end._unsigned = range_end, + .string = mapping_name, + }; + g_ptr_array_add(enum_ft->entries, mapping); + g_ptr_array_sort(enum_ft->entries, + (GCompareFunc) compare_enumeration_mappings_unsigned); + BT_LOGV("Added mapping to unsigned enumeration field type: addr=%p, " + "name=\"%s\", range-start=%" PRIu64 ", " + "range-end=%" PRIu64, + ft, string, range_start, range_end); + +error_free: + free(escaped_string); + +end: + return ret; +} + +BT_HIDDEN +int64_t bt_ctf_field_type_common_enumeration_get_mapping_count( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); + return (int64_t) enum_ft->entries->len; +} + +BT_HIDDEN +int bt_ctf_field_type_common_floating_point_get_exponent_digits( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT, + "Field type"); + return (int) flt_ft->exp_dig; +} + +BT_HIDDEN +int bt_ctf_field_type_common_floating_point_set_exponent_digits( + struct bt_ctf_field_type_common *ft, + unsigned int exponent_digits) +{ + int ret = 0; + struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) { + BT_LOGW("Invalid parameter: field type is not a floating point number field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) && + (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) && + (exponent_digits != + sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) { + BT_LOGW("Invalid parameter: invalid exponent size: " + "addr=%p, exp-size=%u", ft, exponent_digits); + ret = -1; + goto end; + } + + flt_ft->exp_dig = exponent_digits; + BT_LOGV("Set floating point number field type's exponent size: addr=%p, " + "exp-size=%u", ft, exponent_digits); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_floating_point_get_mantissa_digits( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT, + "Field type"); + return (int) flt_ft->mant_dig; +} + +BT_HIDDEN +int bt_ctf_field_type_common_floating_point_set_mantissa_digits( + struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits) +{ + int ret = 0; + struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) { + BT_LOGW("Invalid parameter: field type is not a floating point number field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if ((mantissa_digits != FLT_MANT_DIG) && + (mantissa_digits != DBL_MANT_DIG) && + (mantissa_digits != LDBL_MANT_DIG)) { + BT_LOGW("Invalid parameter: invalid mantissa size: " + "addr=%p, mant-size=%u", ft, mantissa_digits); + ret = -1; + goto end; + } + + flt_ft->mant_dig = mantissa_digits; + BT_LOGV("Set floating point number field type's mantissa size: addr=%p, " + "mant-size=%u", ft, mantissa_digits); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_structure_replace_field( + struct bt_ctf_field_type_common *ft, + const char *field_name, + struct bt_ctf_field_type_common *field_type) +{ + int ret = 0; + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + GQuark name_quark; + uint64_t i; + + BT_ASSERT(ft); + BT_ASSERT(field_name); + BT_ASSERT(field_type); + BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_STRUCT); + name_quark = g_quark_from_string(field_name); + + for (i = 0; i < struct_ft->fields->len; i++) { + struct bt_ctf_field_type_common_structure_field *field = + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i); + + if (field->name == name_quark) { + bt_ctf_object_put_ref(field->type); + field->type = bt_ctf_object_get_ref(field_type); + } + } + + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *field_type, + const char *field_name) +{ + int ret = 0; + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + + /* + * TODO: check that `field_type` does not contain `type`, + * recursively. + */ + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (!field_name) { + BT_LOGW_STR("Invalid parameter: field name is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { + BT_LOGW("Invalid parameter: field type is not a structure field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (ft == field_type) { + BT_LOGW("Invalid parameter: structure field type and field type to add are the same: " + "addr=%p", ft); + ret = -1; + goto end; + } + + if (add_structure_variant_member(struct_ft->fields, + struct_ft->field_name_to_index, field_type, field_name, + false)) { + BT_LOGW("Cannot add field to structure field type: " + "struct-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"", + ft, field_type, field_name); + ret = -1; + goto end; + } + + BT_LOGV("Added structure field type field: struct-ft-addr=%p, " + "field-ft-addr=%p, field-name=\"%s\"", ft, + field_type, field_name); + +end: + return ret; +} + +BT_HIDDEN +int64_t bt_ctf_field_type_common_structure_get_field_count( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, + "Field type"); + return (int64_t) struct_ft->fields->len; +} + +BT_HIDDEN +int bt_ctf_field_type_common_structure_borrow_field_by_index( + struct bt_ctf_field_type_common *ft, + const char **field_name, + struct bt_ctf_field_type_common **field_type, uint64_t index) +{ + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + struct bt_ctf_field_type_common_structure_field *field; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, + "Field type"); + BT_CTF_ASSERT_PRE(index < struct_ft->fields->len, + "Index is out of bounds: index=%" PRIu64 ", " + "count=%u, ft-addr=%p", + index, struct_ft->fields->len, ft); + field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(struct_ft, index); + + if (field_type) { + *field_type = field->type; + } + + if (field_name) { + *field_name = g_quark_to_string(field->name); + BT_ASSERT(*field_name); + } + + return 0; +} + +BT_HIDDEN +struct bt_ctf_field_type_common * +bt_ctf_field_type_common_structure_borrow_field_type_by_name( + struct bt_ctf_field_type_common *ft, const char *name) +{ + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_common_structure_field *field; + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + struct bt_ctf_field_type_common *field_type = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_NON_NULL(name, "Name"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, + "Field type"); + name_quark = g_quark_try_string(name); + if (!name_quark) { + BT_LOGV("No such structure field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, name); + goto end; + } + + if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) { + BT_LOGV("No such structure field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, name); + goto end; + } + + field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, index); + field_type = field->type; + +end: + return field_type; +} + +BT_HIDDEN +struct bt_ctf_field_type_common * +bt_ctf_field_type_common_variant_borrow_tag_field_type( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + struct bt_ctf_field_type_common *tag_ft = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + + if (!var_ft->tag_ft) { + BT_LOGV("Variant field type has no tag field type: " + "addr=%p", ft); + goto end; + } + + tag_ft = BT_CTF_TO_COMMON(var_ft->tag_ft); + +end: + return tag_ft; +} + +BT_HIDDEN +const char *bt_ctf_field_type_common_variant_get_tag_name( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + const char *tag_name = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + + if (var_ft->tag_name->len == 0) { + BT_LOGV("Variant field type has no tag field name: " + "addr=%p", ft); + goto end; + } + + tag_name = var_ft->tag_name->str; + +end: + return tag_name; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_set_tag_name( + struct bt_ctf_field_type_common *ft, const char *name) +{ + int ret = 0; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) { + BT_LOGW("Invalid parameter: field type is not a variant field type: " + "addr=%p, ft-id=%s", ft, bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (!bt_ctf_identifier_is_valid(name)) { + BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: " + "variant-ft-addr=%p, tag-field-name=\"%s\"", + ft, name); + ret = -1; + goto end; + } + + g_string_assign(var_ft->tag_name, name); + BT_LOGV("Set variant field type's tag field name: addr=%p, " + "tag-field-name=\"%s\"", ft, name); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *field_type, + const char *field_name) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + GQuark field_name_quark = g_quark_from_string(field_name); + + /* + * TODO: check that `field_type` does not contain `type`, + * recursively. + */ + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) { + BT_LOGW("Invalid parameter: field type is not a variant field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (ft == field_type) { + BT_LOGW("Invalid parameter: variant field type and field type to add are the same: " + "addr=%p", ft); + ret = -1; + goto end; + } + + /* The user has explicitly provided a tag; validate against it. */ + if (var_ft->tag_ft) { + int name_found = 0; + + /* Make sure this name is present in the enum tag */ + for (i = 0; i < var_ft->tag_ft->entries->len; i++) { + struct bt_ctf_enumeration_mapping *mapping = + g_ptr_array_index(var_ft->tag_ft->entries, i); + + if (mapping->string == field_name_quark) { + name_found = 1; + break; + } + } + + if (!name_found) { + /* Validation failed */ + BT_LOGW("Invalid parameter: field name does not name a tag field type's mapping: " + "variant-ft-addr=%p, tag-ft-addr=%p, " + "tag-field-name=\"%s\"" + "field-ft-addr=%p, field-name=\"%s\"", + ft, var_ft->tag_ft, var_ft->tag_name->str, + field_type, field_name); + ret = -1; + goto end; + } + } + + if (add_structure_variant_member(var_ft->choices, + var_ft->choice_name_to_index, field_type, + field_name, true)) { + BT_LOGW("Cannot add field to variant field type: " + "variant-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"", + ft, field_type, field_name); + ret = -1; + goto end; + } + + BT_LOGV("Added variant field type field: variant-ft-addr=%p, " + "field-ft-addr=%p, field-name=\"%s\"", ft, + field_type, field_name); + +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_field_type_common * +bt_ctf_field_type_common_variant_borrow_field_type_by_name( + struct bt_ctf_field_type_common *ft, + const char *field_name) +{ + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_common_variant_choice *choice; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + struct bt_ctf_field_type_common *field_type = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_NON_NULL(field_name, "Name"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + name_quark = g_quark_try_string(field_name); + if (!name_quark) { + BT_LOGV("No such variant field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, field_name); + goto end; + } + + if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) { + BT_LOGV("No such variant field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, field_name); + goto end; + } + + choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index); + field_type = choice->type; + +end: + return field_type; +} + +BT_HIDDEN +int64_t bt_ctf_field_type_common_variant_get_field_count( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Variant field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + return (int64_t) var_ft->choices->len; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_borrow_field_by_index( + struct bt_ctf_field_type_common *ft, + const char **field_name, + struct bt_ctf_field_type_common **field_type, uint64_t index) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + struct bt_ctf_field_type_common_variant_choice *choice; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + BT_CTF_ASSERT_PRE(index < var_ft->choices->len, + "Index is out of bounds: index=%" PRIu64 ", " + "count=%u, ft-addr=%p", + index, var_ft->choices->len, ft); + choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index); + + if (field_type) { + *field_type = choice->type; + } + + if (field_name) { + *field_name = g_quark_to_string(choice->name); + BT_ASSERT(*field_name); + } + + return 0; +} + +BT_HIDDEN +int64_t bt_ctf_field_type_common_variant_find_choice_index( + struct bt_ctf_field_type_common *ft, uint64_t uval, + bool is_signed) +{ + int64_t ret; + uint64_t i; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + BT_ASSERT(ft); + BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_VARIANT); + + if (bt_ctf_field_type_common_variant_update_choices(ft)) { + ret = INT64_C(-1); + goto end; + } + + for (i = 0; i < var_ft->choices->len; i++) { + uint64_t range_i; + struct bt_ctf_field_type_common_variant_choice *choice = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + var_ft, i); + + for (range_i = 0; range_i < choice->ranges->len; range_i++) { + struct bt_ctf_field_type_common_variant_choice_range *range = + &g_array_index( + choice->ranges, + struct bt_ctf_field_type_common_variant_choice_range, + range_i); + + if (is_signed) { + int64_t tag_ival = (int64_t) uval; + + if (tag_ival >= range->lower.i && + tag_ival <= range->upper.i) { + goto found; + } + } else { + if (uval >= range->lower.u && + uval <= range->upper.u) { + goto found; + } + } + } + } + + /* Range not found */ + ret = INT64_C(-1); + goto end; + +found: + ret = (int64_t) i; + +end: + return ret; +} + +BT_HIDDEN +struct bt_ctf_field_type_common * +bt_ctf_field_type_common_array_borrow_element_field_type( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY, + "Field type"); + BT_ASSERT(array_ft && array_ft->element_ft); + return array_ft->element_ft; +} + +BT_HIDDEN +int bt_ctf_field_type_common_array_set_element_field_type( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *element_ft) +{ + int ret = 0; + struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: array field type is NULL."); + ret = -1; + goto end; + } + + if (!element_ft) { + BT_LOGW_STR("Invalid parameter: element field type is NULL."); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_ARRAY) { + BT_LOGW("Invalid parameter: field type is not an array field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (array_ft->element_ft) { + BT_CTF_OBJECT_PUT_REF_AND_RESET(array_ft->element_ft); + } + + array_ft->element_ft = bt_ctf_object_get_ref(element_ft); + BT_LOGV("Set array field type's element field type: array-ft-addr=%p, " + "element-ft-addr=%p", ft, element_ft); + +end: + return ret; +} + +BT_HIDDEN +int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY, + "Field type"); + return (int64_t) array_ft->length; +} + +BT_HIDDEN +struct bt_ctf_field_type_common *bt_ctf_field_type_common_sequence_borrow_element_field_type( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE, + "Field type"); + return seq_ft->element_ft; +} + +BT_HIDDEN +int bt_ctf_field_type_common_sequence_set_element_field_type( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *element_ft) +{ + int ret = 0; + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: sequence field type is NULL."); + ret = -1; + goto end; + } + + if (!element_ft) { + BT_LOGW_STR("Invalid parameter: element field type is NULL."); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) { + BT_LOGW("Invalid parameter: field type is not a sequence field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (seq_ft->element_ft) { + BT_CTF_OBJECT_PUT_REF_AND_RESET(seq_ft->element_ft); + } + + seq_ft->element_ft = element_ft; + bt_ctf_object_get_ref(seq_ft->element_ft); + BT_LOGV("Set sequence field type's element field type: sequence-ft-addr=%p, " + "element-ft-addr=%p", ft, element_ft); + +end: + return ret; +} + +BT_HIDDEN +const char *bt_ctf_field_type_common_sequence_get_length_field_name( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE, + "Field type"); + return seq_ft->length_field_name ? + seq_ft->length_field_name->str : NULL; +} + +BT_HIDDEN +enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRING, + "Field type"); + return string_ft->encoding; +} + +BT_HIDDEN +int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft, + enum bt_ctf_string_encoding encoding) +{ + int ret = 0; + struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_STRING) { + BT_LOGW("Invalid parameter: field type is not a string field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + if (encoding != BT_CTF_STRING_ENCODING_UTF8 && + encoding != BT_CTF_STRING_ENCODING_ASCII) { + BT_LOGW("Invalid parameter: unknown string encoding: " + "addr=%p, encoding=%d", ft, encoding); + ret = -1; + goto end; + } + + string_ft->encoding = encoding; + BT_LOGV("Set string field type's encoding: addr=%p, encoding=%s", + ft, bt_ctf_string_encoding_string(encoding)); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *ft) +{ + int ret; + enum bt_ctf_field_type_id type_id; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + + if (ft->frozen) { + ret = (int) ft->alignment; + goto end; + } + + type_id = bt_ctf_field_type_common_get_type_id(ft); + switch (type_id) { + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + { + struct bt_ctf_field_type_common *element_ft = + bt_ctf_field_type_common_sequence_borrow_element_field_type(ft); + + BT_ASSERT(element_ft); + ret = bt_ctf_field_type_common_get_alignment(element_ft); + break; + } + case BT_CTF_FIELD_TYPE_ID_ARRAY: + { + struct bt_ctf_field_type_common *element_ft = + bt_ctf_field_type_common_array_borrow_element_field_type(ft); + + BT_ASSERT(element_ft); + ret = bt_ctf_field_type_common_get_alignment(element_ft); + break; + } + case BT_CTF_FIELD_TYPE_ID_STRUCT: + { + int64_t i, element_count; + + element_count = bt_ctf_field_type_common_structure_get_field_count( + ft); + BT_ASSERT(element_count >= 0); + + for (i = 0; i < element_count; i++) { + struct bt_ctf_field_type_common *field = NULL; + int field_alignment; + + ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + ft, NULL, &field, i); + BT_ASSERT(ret == 0); + BT_ASSERT(field); + field_alignment = bt_ctf_field_type_common_get_alignment( + field); + if (field_alignment < 0) { + ret = field_alignment; + goto end; + } + + ft->alignment = MAX(field_alignment, ft->alignment); + } + ret = (int) ft->alignment; + break; + } + case BT_CTF_FIELD_TYPE_ID_UNKNOWN: + BT_LOGW("Invalid parameter: unknown field type ID: " + "addr=%p, ft-id=%d", ft, type_id); + ret = -1; + break; + default: + ret = (int) ft->alignment; + break; + } + +end: + return ret; +} + +static inline +int is_power_of_two(unsigned int value) +{ + return ((value & (value - 1)) == 0) && value > 0; +} + +BT_HIDDEN +int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft, + unsigned int alignment) +{ + int ret = 0; + enum bt_ctf_field_type_id type_id; + + /* Alignment must be a power of two */ + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (!is_power_of_two(alignment)) { + BT_LOGW("Invalid parameter: alignment is not a power of two: " + "addr=%p, align=%u", ft, alignment); + ret = -1; + goto end; + } + + type_id = bt_ctf_field_type_common_get_type_id(ft); + if (type_id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) { + BT_LOGW("Invalid parameter: unknown field type ID: " + "addr=%p, ft-id=%d", ft, type_id); + ret = -1; + goto end; + } + + if (ft->id == BT_CTF_FIELD_TYPE_ID_STRING && alignment != CHAR_BIT) { + BT_LOGW("Invalid parameter: alignment must be %u for a string field type: " + "addr=%p, align=%u", CHAR_BIT, ft, alignment); + ret = -1; + goto end; + } + + if (type_id == BT_CTF_FIELD_TYPE_ID_VARIANT || + type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE || + type_id == BT_CTF_FIELD_TYPE_ID_ARRAY) { + /* Setting an alignment on these types makes no sense */ + BT_LOGW("Invalid parameter: cannot set the alignment of this field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + ft->alignment = alignment; + ret = 0; + BT_LOGV("Set field type's alignment: addr=%p, align=%u", + ft, alignment); + +end: + return ret; +} + +BT_HIDDEN +enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order( + struct bt_ctf_field_type_common *ft) +{ + enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + + switch (ft->id) { + case BT_CTF_FIELD_TYPE_ID_INTEGER: + { + struct bt_ctf_field_type_common_integer *integer = + BT_CTF_FROM_COMMON(ft); + + ret = integer->user_byte_order; + break; + } + case BT_CTF_FIELD_TYPE_ID_ENUM: + { + struct bt_ctf_field_type_common_enumeration *enum_ft = + BT_CTF_FROM_COMMON(ft); + + ret = bt_ctf_field_type_common_get_byte_order( + BT_CTF_TO_COMMON(enum_ft->container_ft)); + break; + } + case BT_CTF_FIELD_TYPE_ID_FLOAT: + { + struct bt_ctf_field_type_common_floating_point *floating_point = + BT_CTF_FROM_COMMON(ft); + ret = floating_point->user_byte_order; + break; + } + default: + BT_LOGW("Invalid parameter: cannot get the byte order of this field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + goto end; + } + + BT_ASSERT(ret == BT_CTF_BYTE_ORDER_NATIVE || + ret == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN || + ret == BT_CTF_BYTE_ORDER_BIG_ENDIAN || + ret == BT_CTF_BYTE_ORDER_NETWORK); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft, + enum bt_ctf_byte_order byte_order) +{ + int ret = 0; + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->frozen) { + BT_LOGW("Invalid parameter: field type is frozen: addr=%p", + ft); + ret = -1; + goto end; + } + + if (byte_order != BT_CTF_BYTE_ORDER_NATIVE && + byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN && + byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN && + byte_order != BT_CTF_BYTE_ORDER_NETWORK) { + BT_LOGW("Invalid parameter: invalid byte order: " + "addr=%p, bo=%s", ft, + bt_ctf_byte_order_string(byte_order)); + ret = -1; + goto end; + } + + if (ft->methods->set_byte_order) { + ft->methods->set_byte_order(ft, byte_order); + } + + BT_LOGV("Set field type's byte order: addr=%p, bo=%s", + ft, bt_ctf_byte_order_string(byte_order)); + +end: + return ret; +} + +BT_HIDDEN +enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id( + struct bt_ctf_field_type_common *ft) +{ + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + return ft->id; +} + +BT_HIDDEN +void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft) +{ + if (!ft || ft->frozen) { + return; + } + + BT_ASSERT(ft->methods->freeze); + ft->methods->freeze(ft); +} + +BT_HIDDEN +struct bt_ctf_field_type_common * +bt_ctf_field_type_common_variant_borrow_field_type_signed( + struct bt_ctf_field_type_common_variant *var_ft, + int64_t tag_value) +{ + struct bt_ctf_field_type_common *field_type = NULL; + GQuark field_name_quark; + gpointer index; + struct bt_ctf_field_type_common_variant_choice *choice; + struct range_overlap_query query = { + .range_start._signed = tag_value, + .range_end._signed = tag_value, + .mapping_name = 0, + .overlaps = 0, + }; + + g_ptr_array_foreach(var_ft->tag_ft->entries, check_ranges_overlap, + &query); + if (!query.overlaps) { + goto end; + } + + field_name_quark = query.mapping_name; + if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, + GUINT_TO_POINTER(field_name_quark), NULL, &index)) { + goto end; + } + + choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, + (size_t) index); + field_type = choice->type; + +end: + return field_type; +} + +BT_HIDDEN +struct bt_ctf_field_type_common * +bt_ctf_field_type_common_variant_borrow_field_type_unsigned( + struct bt_ctf_field_type_common_variant *var_ft, + uint64_t tag_value) +{ + struct bt_ctf_field_type_common *field_type = NULL; + GQuark field_name_quark; + gpointer index; + struct bt_ctf_field_type_common_variant_choice *choice; + struct range_overlap_query query = { + .range_start._unsigned = tag_value, + .range_end._unsigned = tag_value, + .mapping_name = 0, + .overlaps = 0, + }; + + g_ptr_array_foreach(var_ft->tag_ft->entries, + check_ranges_overlap_unsigned, &query); + if (!query.overlaps) { + goto end; + } + + field_name_quark = query.mapping_name; + if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, + GUINT_TO_POINTER(field_name_quark), NULL, &index)) { + goto end; + } + + choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, + (size_t) index); + field_type = choice->type; + +end: + return field_type; +} + +BT_HIDDEN +struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common *ft_copy = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_ASSERT(ft->methods->copy); + ft_copy = ft->methods->copy(ft); + if (!ft_copy) { + BT_LOGE_STR("Cannot copy field type."); + goto end; + } + + ft_copy->alignment = ft->alignment; + +end: + return ft_copy; +} + +BT_HIDDEN +int bt_ctf_field_type_common_structure_get_field_name_index( + struct bt_ctf_field_type_common *ft, const char *name) +{ + int ret; + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_NON_NULL(name, "Name"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, + "Field type"); + + name_quark = g_quark_try_string(name); + if (!name_quark) { + BT_LOGV("No such structure field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, name); + ret = -1; + goto end; + } + + if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index, + GUINT_TO_POINTER(name_quark), + NULL, (gpointer *) &index)) { + BT_LOGV("No such structure field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, name); + ret = -1; + goto end; + } + + ret = (int) index; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_get_field_name_index( + struct bt_ctf_field_type_common *ft, const char *name) +{ + int ret; + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_NON_NULL(name, "Name"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + name_quark = g_quark_try_string(name); + if (!name_quark) { + BT_LOGV("No such variant field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, name); + ret = -1; + goto end; + } + + if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, + GUINT_TO_POINTER(name_quark), + NULL, (gpointer *) &index)) { + BT_LOGV("No such variant field type field name: " + "ft-addr=%p, field-name=\"%s\"", + ft, name); + ret = -1; + goto end; + } + + ret = (int) index; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_sequence_set_length_field_path( + struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path) +{ + int ret = 0; + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) { + BT_LOGW("Invalid parameter: field type is not a sequence field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + bt_ctf_object_get_ref(path); + BT_CTF_OBJECT_MOVE_REF(seq_ft->length_field_path, path); + BT_LOGV("Set sequence field type's length field path: ft-addr=%p, " + "field-path-addr=%p", ft, path); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_set_tag_field_path( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_path *path) +{ + int ret = 0; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + ret = -1; + goto end; + } + + if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) { + BT_LOGW("Invalid parameter: field type is not a variant field type: " + "addr=%p, ft-id=%s", ft, + bt_ctf_field_type_id_string(ft->id)); + ret = -1; + goto end; + } + + bt_ctf_object_get_ref(path); + BT_CTF_OBJECT_MOVE_REF(var_ft->tag_field_path, path); + BT_LOGV("Set variant field type's tag field path: ft-addr=%p, " + "field-path-addr=%p", ft, path); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_set_tag_field_type( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_field_type_common *tag_ft) +{ + int ret = 0; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + if (!ft) { + BT_LOGW_STR("Invalid parameter: variant field type is NULL."); + ret = -1; + goto end; + } + + if (!tag_ft) { + BT_LOGW_STR("Invalid parameter: tag field type is NULL."); + ret = -1; + goto end; + } + + if (tag_ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) { + BT_LOGW("Invalid parameter: tag field type is not an enumeration field type: " + "addr=%p, ft-id=%s", tag_ft, + bt_ctf_field_type_id_string(tag_ft->id)); + ret = -1; + goto end; + } + + bt_ctf_object_put_ref(var_ft->tag_ft); + var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft); + BT_LOGV("Set variant field type's tag field type: variant-ft-addr=%p, " + "tag-ft-addr=%p", ft, tag_ft); + +end: + return ret; +} + +BT_HIDDEN +void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft) +{ + ft->frozen = 1; +} + +BT_HIDDEN +void bt_ctf_field_type_common_enumeration_freeze_recursive( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + + BT_LOGD("Freezing enumeration field type object: addr=%p", ft); + bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft); + bt_ctf_field_type_common_generic_freeze(ft); + BT_LOGD("Freezing enumeration field type object's container field type: int-ft-addr=%p", + enum_ft->container_ft); + bt_ctf_field_type_common_freeze(BT_CTF_TO_COMMON(enum_ft->container_ft)); +} + +BT_HIDDEN +void bt_ctf_field_type_common_structure_freeze_recursive( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + uint64_t i; + + /* Cache the alignment */ + BT_LOGD("Freezing structure field type object: addr=%p", ft); + ft->alignment = bt_ctf_field_type_common_get_alignment(ft); + bt_ctf_field_type_common_generic_freeze(ft); + + for (i = 0; i < struct_ft->fields->len; i++) { + struct bt_ctf_field_type_common_structure_field *field = + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i); + + BT_LOGD("Freezing structure field type field: " + "ft-addr=%p, name=\"%s\"", + field->type, g_quark_to_string(field->name)); + bt_ctf_field_type_common_freeze(field->type); + } +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_update_choices(struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + uint64_t i; + int ret = 0; + bool is_signed; + + if (ft->frozen && var_ft->choices_up_to_date) { + goto end; + } + + BT_ASSERT(var_ft->tag_ft); + is_signed = !!var_ft->tag_ft->container_ft->is_signed; + + for (i = 0; i < var_ft->choices->len; i++) { + struct bt_ctf_field_type_common_variant_choice *choice = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i); + const char *choice_name = g_quark_to_string(choice->name); + struct bt_ctf_field_type_enumeration_mapping_iterator *iter = + bt_ctf_field_type_common_enumeration_find_mappings_by_name( + BT_CTF_TO_COMMON(var_ft->tag_ft), choice_name); + + if (!iter) { + ret = -1; + goto end; + } + + BT_ASSERT(choice->ranges); + g_array_set_size(choice->ranges, 0); + + while (bt_ctf_field_type_enumeration_mapping_iterator_next(iter) == 0) { + struct bt_ctf_field_type_common_variant_choice_range range; + + if (is_signed) { + ret = bt_ctf_field_type_enumeration_mapping_iterator_signed_get( + iter, NULL, + &range.lower.i, &range.upper.i); + } else { + ret = bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get( + iter, NULL, + &range.lower.u, &range.upper.u); + } + + BT_ASSERT(ret == 0); + g_array_append_val(choice->ranges, range); + } + + bt_ctf_object_put_ref(iter); + } + + var_ft->choices_up_to_date = true; + +end: + return ret; +} + +BT_HIDDEN +void bt_ctf_field_type_common_variant_freeze_recursive( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + uint64_t i; + + BT_LOGD("Freezing variant field type object: addr=%p", ft); + bt_ctf_field_type_common_generic_freeze(ft); + + for (i = 0; i < var_ft->choices->len; i++) { + struct bt_ctf_field_type_common_variant_choice *choice = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i); + + BT_LOGD("Freezing variant field type member: " + "ft-addr=%p, name=\"%s\"", + choice->type, g_quark_to_string(choice->name)); + bt_ctf_field_type_common_freeze(choice->type); + } +} + +BT_HIDDEN +void bt_ctf_field_type_common_array_freeze_recursive( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); + + /* Cache the alignment */ + BT_LOGD("Freezing array field type object: addr=%p", ft); + ft->alignment = bt_ctf_field_type_common_get_alignment(ft); + bt_ctf_field_type_common_generic_freeze(ft); + BT_LOGD("Freezing array field type object's element field type: element-ft-addr=%p", + array_ft->element_ft); + bt_ctf_field_type_common_freeze(array_ft->element_ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_sequence_freeze_recursive( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + /* Cache the alignment */ + BT_LOGD("Freezing sequence field type object: addr=%p", ft); + ft->alignment = bt_ctf_field_type_common_get_alignment(ft); + bt_ctf_field_type_common_generic_freeze(ft); + BT_LOGD("Freezing sequence field type object's element field type: element-ft-addr=%p", + seq_ft->element_ft); + bt_ctf_field_type_common_freeze(seq_ft->element_ft); +} + +BT_HIDDEN +void bt_ctf_field_type_common_integer_set_byte_order( + struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order) +{ + struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); + + int_ft->user_byte_order = byte_order; +} + +BT_HIDDEN +void bt_ctf_field_type_common_enumeration_set_byte_order_recursive( + struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); + + bt_ctf_field_type_common_set_byte_order(BT_CTF_TO_COMMON(enum_ft->container_ft), + byte_order); +} + +BT_HIDDEN +void bt_ctf_field_type_common_floating_point_set_byte_order( + struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order) +{ + struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); + + flt_ft->user_byte_order = byte_order; +} + +BT_HIDDEN +void bt_ctf_field_type_common_structure_set_byte_order_recursive( + struct bt_ctf_field_type_common *ft, + enum bt_ctf_byte_order byte_order) +{ + int i; + struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); + + for (i = 0; i < struct_ft->fields->len; i++) { + struct bt_ctf_field_type_common_structure_field *field = + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + struct_ft, i); + struct bt_ctf_field_type_common *field_type = field->type; + + bt_ctf_field_type_common_set_byte_order(field_type, byte_order); + } +} + +BT_HIDDEN +void bt_ctf_field_type_common_variant_set_byte_order_recursive( + struct bt_ctf_field_type_common *ft, + enum bt_ctf_byte_order byte_order) +{ + int i; + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + for (i = 0; i < var_ft->choices->len; i++) { + struct bt_ctf_field_type_common_variant_choice *choice = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + var_ft, i); + struct bt_ctf_field_type_common *field_type = choice->type; + + bt_ctf_field_type_common_set_byte_order(field_type, byte_order); + } +} + +BT_HIDDEN +void bt_ctf_field_type_common_array_set_byte_order_recursive( + struct bt_ctf_field_type_common *ft, + enum bt_ctf_byte_order byte_order) +{ + struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); + + bt_ctf_field_type_common_set_byte_order(array_ft->element_ft, byte_order); +} + +BT_HIDDEN +void bt_ctf_field_type_common_sequence_set_byte_order_recursive( + struct bt_ctf_field_type_common *ft, + enum bt_ctf_byte_order byte_order) +{ + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + bt_ctf_field_type_common_set_byte_order(seq_ft->element_ft, byte_order); +} + + +BT_HIDDEN +int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + struct bt_ctf_field_type_common_integer *int_ft_a = BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_integer *int_ft_b = BT_CTF_FROM_COMMON(ft_b); + + /* Length */ + if (int_ft_a->size != int_ft_b->size) { + BT_LOGV("Integer field types differ: different sizes: " + "ft-a-size=%u, ft-b-size=%u", + int_ft_a->size, int_ft_b->size); + goto end; + } + + /* Byte order */ + if (int_ft_a->user_byte_order != int_ft_b->user_byte_order) { + BT_LOGV("Integer field types differ: different byte orders: " + "ft-a-bo=%s, ft-b-bo=%s", + bt_ctf_byte_order_string(int_ft_a->user_byte_order), + bt_ctf_byte_order_string(int_ft_b->user_byte_order)); + goto end; + } + + /* Signedness */ + if (int_ft_a->is_signed != int_ft_b->is_signed) { + BT_LOGV("Integer field types differ: different signedness: " + "ft-a-is-signed=%d, ft-b-is-signed=%d", + int_ft_a->is_signed, + int_ft_b->is_signed); + goto end; + } + + /* Base */ + if (int_ft_a->base != int_ft_b->base) { + BT_LOGV("Integer field types differ: different bases: " + "ft-a-base=%s, ft-b-base=%s", + bt_ctf_integer_base_string(int_ft_a->base), + bt_ctf_integer_base_string(int_ft_b->base)); + goto end; + } + + /* Encoding */ + if (int_ft_a->encoding != int_ft_b->encoding) { + BT_LOGV("Integer field types differ: different encodings: " + "ft-a-encoding=%s, ft-b-encoding=%s", + bt_ctf_string_encoding_string(int_ft_a->encoding), + bt_ctf_string_encoding_string(int_ft_b->encoding)); + goto end; + } + + /* Mapped clock class */ + if (int_ft_a->mapped_clock_class) { + if (!int_ft_b->mapped_clock_class) { + BT_LOGV_STR("Integer field types differ: field type A " + "has a mapped clock class, but field type B " + "does not."); + goto end; + } + + if (bt_ctf_clock_class_compare(int_ft_a->mapped_clock_class, + int_ft_b->mapped_clock_class) != 0) { + BT_LOGV_STR("Integer field types differ: different " + "mapped clock classes."); + } + } else { + if (int_ft_b->mapped_clock_class) { + BT_LOGV_STR("Integer field types differ: field type A " + "has no description, but field type B has one."); + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_floating_point_compare( + struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + struct bt_ctf_field_type_common_floating_point *flt_ft_a = + BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_floating_point *flt_ft_b = + BT_CTF_FROM_COMMON(ft_b); + + /* Byte order */ + if (flt_ft_a->user_byte_order != flt_ft_b->user_byte_order) { + BT_LOGV("Floating point number field types differ: different byte orders: " + "ft-a-bo=%s, ft-b-bo=%s", + bt_ctf_byte_order_string(flt_ft_a->user_byte_order), + bt_ctf_byte_order_string(flt_ft_b->user_byte_order)); + goto end; + } + + /* Exponent length */ + if (flt_ft_a->exp_dig != flt_ft_b->exp_dig) { + BT_LOGV("Floating point number field types differ: different exponent sizes: " + "ft-a-exp-size=%u, ft-b-exp-size=%u", + flt_ft_a->exp_dig, flt_ft_b->exp_dig); + goto end; + } + + /* Mantissa length */ + if (flt_ft_a->mant_dig != flt_ft_b->mant_dig) { + BT_LOGV("Floating point number field types differ: different mantissa sizes: " + "ft-a-mant-size=%u, ft-b-mant-size=%u", + flt_ft_a->mant_dig, flt_ft_b->mant_dig); + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int compare_enumeration_mappings(struct bt_ctf_enumeration_mapping *mapping_a, + struct bt_ctf_enumeration_mapping *mapping_b) +{ + int ret = 1; + + /* Label */ + if (mapping_a->string != mapping_b->string) { + BT_LOGV("Enumeration field type mappings differ: different names: " + "mapping-a-name=\"%s\", mapping-b-name=\"%s\"", + g_quark_to_string(mapping_a->string), + g_quark_to_string(mapping_b->string)); + goto end; + } + + /* Range start */ + if (mapping_a->range_start._unsigned != + mapping_b->range_start._unsigned) { + BT_LOGV("Enumeration field type mappings differ: different starts of range: " + "mapping-a-range-start-unsigned=%" PRIu64 ", " + "mapping-b-range-start-unsigned=%" PRIu64, + mapping_a->range_start._unsigned, + mapping_b->range_start._unsigned); + goto end; + } + + /* Range end */ + if (mapping_a->range_end._unsigned != + mapping_b->range_end._unsigned) { + BT_LOGV("Enumeration field type mappings differ: different ends of range: " + "mapping-a-range-end-unsigned=%" PRIu64 ", " + "mapping-b-range-end-unsigned=%" PRIu64, + mapping_a->range_end._unsigned, + mapping_b->range_end._unsigned); + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_enumeration_compare_recursive( + struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_common_enumeration *enum_ft_a = + BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_enumeration *enum_ft_b = + BT_CTF_FROM_COMMON(ft_b); + + /* Container field type */ + ret = bt_ctf_field_type_common_compare( + BT_CTF_TO_COMMON(enum_ft_a->container_ft), + BT_CTF_TO_COMMON(enum_ft_b->container_ft)); + if (ret) { + BT_LOGV("Enumeration field types differ: different container field types: " + "ft-a-container-ft-addr=%p, ft-b-container-ft-addr=%p", + enum_ft_a->container_ft, enum_ft_b->container_ft); + goto end; + } + + ret = 1; + + /* Entries */ + if (enum_ft_a->entries->len != enum_ft_b->entries->len) { + goto end; + } + + for (i = 0; i < enum_ft_a->entries->len; ++i) { + struct bt_ctf_enumeration_mapping *mapping_a = + g_ptr_array_index(enum_ft_a->entries, i); + struct bt_ctf_enumeration_mapping *mapping_b = + g_ptr_array_index(enum_ft_b->entries, i); + + if (compare_enumeration_mappings(mapping_a, mapping_b)) { + BT_LOGV("Enumeration field types differ: different mappings: " + "ft-a-mapping-addr=%p, ft-b-mapping-addr=%p, " + "ft-a-mapping-name=\"%s\", ft-b-mapping-name=\"%s\"", + mapping_a, mapping_b, + g_quark_to_string(mapping_a->string), + g_quark_to_string(mapping_b->string)); + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + struct bt_ctf_field_type_common_string *string_ft_a = BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_string *string_ft_b = BT_CTF_FROM_COMMON(ft_b); + + /* Encoding */ + if (string_ft_a->encoding != string_ft_b->encoding) { + BT_LOGV("String field types differ: different encodings: " + "ft-a-encoding=%s, ft-b-encoding=%s", + bt_ctf_string_encoding_string(string_ft_a->encoding), + bt_ctf_string_encoding_string(string_ft_b->encoding)); + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int compare_structure_variant_members( + struct bt_ctf_field_type_common *member_a_ft, + struct bt_ctf_field_type_common *member_b_ft, + GQuark member_a_name, GQuark member_b_name) +{ + int ret = 1; + + /* Label */ + if (member_a_name != member_b_name) { + BT_LOGV("Structure/variant field type fields differ: different names: " + "field-a-name=%s, field-b-name=%s", + g_quark_to_string(member_a_name), + g_quark_to_string(member_b_name)); + goto end; + } + + /* Type */ + ret = bt_ctf_field_type_common_compare(member_a_ft, member_b_ft); + if (ret == 1) { + BT_LOGV("Structure/variant field type fields differ: different field types: " + "field-name=\"%s\", field-a-ft-addr=%p, field-b-ft-addr=%p", + g_quark_to_string(member_a_name), + member_a_ft, member_b_ft); + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_structure_compare_recursive( + struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_common_structure *struct_ft_a = + BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_structure *struct_ft_b = + BT_CTF_FROM_COMMON(ft_b); + + /* Alignment */ + if (bt_ctf_field_type_common_get_alignment(ft_a) != + bt_ctf_field_type_common_get_alignment(ft_b)) { + BT_LOGV("Structure field types differ: different alignments: " + "ft-a-align=%u, ft-b-align=%u", + bt_ctf_field_type_common_get_alignment(ft_a), + bt_ctf_field_type_common_get_alignment(ft_b)); + goto end; + } + + /* Fields */ + if (struct_ft_a->fields->len != struct_ft_b->fields->len) { + BT_LOGV("Structure field types differ: different field counts: " + "ft-a-field-count=%u, ft-b-field-count=%u", + struct_ft_a->fields->len, struct_ft_b->fields->len); + goto end; + } + + for (i = 0; i < struct_ft_a->fields->len; ++i) { + struct bt_ctf_field_type_common_structure_field *field_a = + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + struct_ft_a, i); + struct bt_ctf_field_type_common_structure_field *field_b = + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + struct_ft_b, i); + + ret = compare_structure_variant_members(field_a->type, + field_b->type, field_a->name, field_b->name); + if (ret) { + /* compare_structure_variant_members() logs what differs */ + BT_LOGV_STR("Structure field types differ: different fields."); + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_variant_compare_recursive( + struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_common_variant *var_ft_a = BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_variant *var_ft_b = BT_CTF_FROM_COMMON(ft_b); + + /* Tag name */ + if (strcmp(var_ft_a->tag_name->str, var_ft_b->tag_name->str)) { + BT_LOGV("Variant field types differ: different tag field names: " + "ft-a-tag-field-name=\"%s\", ft-b-tag-field-name=\"%s\"", + var_ft_a->tag_name->str, var_ft_b->tag_name->str); + goto end; + } + + /* Tag type */ + ret = bt_ctf_field_type_common_compare(BT_CTF_TO_COMMON(var_ft_a->tag_ft), + BT_CTF_TO_COMMON(var_ft_b->tag_ft)); + if (ret) { + BT_LOGV("Variant field types differ: different tag field types: " + "ft-a-tag-ft-addr=%p, ft-b-tag-ft-addr=%p", + var_ft_a->tag_ft, var_ft_b->tag_ft); + goto end; + } + + ret = 1; + + /* Fields */ + if (var_ft_a->choices->len != var_ft_b->choices->len) { + BT_LOGV("Variant field types differ: different field counts: " + "ft-a-field-count=%u, ft-b-field-count=%u", + var_ft_a->choices->len, var_ft_b->choices->len); + goto end; + } + + for (i = 0; i < var_ft_a->choices->len; ++i) { + struct bt_ctf_field_type_common_variant_choice *choice_a = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + var_ft_a, i); + struct bt_ctf_field_type_common_variant_choice *choice_b = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + var_ft_b, i); + + ret = compare_structure_variant_members(choice_a->type, + choice_b->type, choice_a->name, choice_b->name); + if (ret) { + /* compare_structure_variant_members() logs what differs */ + BT_LOGV_STR("Variant field types differ: different fields."); + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_array_compare_recursive( + struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + struct bt_ctf_field_type_common_array *array_ft_a = BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_array *array_ft_b = BT_CTF_FROM_COMMON(ft_b); + + /* Length */ + if (array_ft_a->length != array_ft_b->length) { + BT_LOGV("Structure field types differ: different lengths: " + "ft-a-length=%u, ft-b-length=%u", + array_ft_a->length, array_ft_b->length); + goto end; + } + + /* Element type */ + ret = bt_ctf_field_type_common_compare(array_ft_a->element_ft, + array_ft_b->element_ft); + if (ret == 1) { + BT_LOGV("Array field types differ: different element field types: " + "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p", + array_ft_a->element_ft, array_ft_b->element_ft); + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_sequence_compare_recursive( + struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = -1; + struct bt_ctf_field_type_common_sequence *seq_ft_a = BT_CTF_FROM_COMMON(ft_a); + struct bt_ctf_field_type_common_sequence *seq_ft_b = BT_CTF_FROM_COMMON(ft_b); + + /* Length name */ + if (strcmp(seq_ft_a->length_field_name->str, + seq_ft_b->length_field_name->str)) { + BT_LOGV("Sequence field types differ: different length field names: " + "ft-a-length-field-name=\"%s\", " + "ft-b-length-field-name=\"%s\"", + seq_ft_a->length_field_name->str, + seq_ft_b->length_field_name->str); + goto end; + } + + /* Element type */ + ret = bt_ctf_field_type_common_compare(seq_ft_a->element_ft, + seq_ft_b->element_ft); + if (ret == 1) { + BT_LOGV("Sequence field types differ: different element field types: " + "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p", + seq_ft_a->element_ft, seq_ft_b->element_ft); + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a, + struct bt_ctf_field_type_common *ft_b) +{ + int ret = 1; + + BT_CTF_ASSERT_PRE_NON_NULL(ft_a, "Field type A"); + BT_CTF_ASSERT_PRE_NON_NULL(ft_b, "Field type B"); + + if (ft_a == ft_b) { + /* Same reference: equal (even if both are NULL) */ + ret = 0; + goto end; + } + + if (!ft_a) { + BT_LOGW_STR("Invalid parameter: field type A is NULL."); + ret = -1; + goto end; + } + + if (!ft_b) { + BT_LOGW_STR("Invalid parameter: field type B is NULL."); + ret = -1; + goto end; + } + + if (ft_a->id != ft_b->id) { + /* Different type IDs */ + BT_LOGV("Field types differ: different IDs: " + "ft-a-addr=%p, ft-b-addr=%p, " + "ft-a-id=%s, ft-b-id=%s", + ft_a, ft_b, + bt_ctf_field_type_id_string(ft_a->id), + bt_ctf_field_type_id_string(ft_b->id)); + goto end; + } + + if (ft_a->id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) { + /* Both have unknown type IDs */ + BT_LOGW_STR("Invalid parameter: field type IDs are unknown."); + goto end; + } + + BT_ASSERT(ft_a->methods->compare); + ret = ft_a->methods->compare(ft_a, ft_b); + if (ret == 1) { + BT_LOGV("Field types differ: ft-a-addr=%p, ft-b-addr=%p", + ft_a, ft_b); + } + +end: + return ret; +} + +BT_HIDDEN +int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft) +{ + int64_t field_count = -1; + + switch (ft->id) { + case BT_CTF_FIELD_TYPE_ID_STRUCT: + field_count = + bt_ctf_field_type_common_structure_get_field_count(ft); + break; + case BT_CTF_FIELD_TYPE_ID_VARIANT: + field_count = + bt_ctf_field_type_common_variant_get_field_count(ft); + break; + case BT_CTF_FIELD_TYPE_ID_ARRAY: + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + /* + * Array and sequence types always contain a single member + * (the element type). + */ + field_count = 1; + break; + default: + break; + } + + return field_count; +} + +BT_HIDDEN +struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index( + struct bt_ctf_field_type_common *ft, int index) +{ + struct bt_ctf_field_type_common *field_type = NULL; + + switch (ft->id) { + case BT_CTF_FIELD_TYPE_ID_STRUCT: + { + int ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + ft, NULL, &field_type, index); + if (ret) { + field_type = NULL; + goto end; + } + break; + } + case BT_CTF_FIELD_TYPE_ID_VARIANT: + { + int ret = bt_ctf_field_type_common_variant_borrow_field_by_index( + ft, NULL, &field_type, index); + if (ret) { + field_type = NULL; + goto end; + } + break; + } + case BT_CTF_FIELD_TYPE_ID_ARRAY: + field_type = + bt_ctf_field_type_common_array_borrow_element_field_type(ft); + break; + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + field_type = + bt_ctf_field_type_common_sequence_borrow_element_field_type(ft); + break; + default: + break; + } + +end: + return field_type; +} + +BT_HIDDEN +int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft, + const char *name) +{ + int field_index = -1; + + switch (ft->id) { + case BT_CTF_FIELD_TYPE_ID_STRUCT: + field_index = bt_ctf_field_type_common_structure_get_field_name_index( + ft, name); + break; + case BT_CTF_FIELD_TYPE_ID_VARIANT: + field_index = bt_ctf_field_type_common_variant_get_field_name_index( + ft, name); + break; + default: + break; + } + + return field_index; +} + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + return var_ft->tag_field_path; +} + +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path( + struct bt_ctf_field_type_common *ft) +{ + struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE, + "Field type"); + return seq_ft->length_field_path; +} + +BT_HIDDEN +int bt_ctf_field_type_common_validate_single_clock_class( + struct bt_ctf_field_type_common *ft, + struct bt_ctf_clock_class **expected_clock_class) +{ + int ret = 0; + + if (!ft) { + goto end; + } + + BT_ASSERT(expected_clock_class); + + switch (ft->id) { + case BT_CTF_FIELD_TYPE_ID_INTEGER: + { + struct bt_ctf_clock_class *mapped_clock_class = + bt_ctf_field_type_common_integer_borrow_mapped_clock_class(ft); + + if (!mapped_clock_class) { + goto end; + } + + if (!*expected_clock_class) { + /* Move reference to output parameter */ + *expected_clock_class = bt_ctf_object_get_ref(mapped_clock_class); + mapped_clock_class = NULL; + BT_LOGV("Setting expected clock class: " + "expected-clock-class-addr=%p", + *expected_clock_class); + } else { + if (mapped_clock_class != *expected_clock_class) { + BT_LOGW("Integer field type is not mapped to " + "the expected clock class: " + "mapped-clock-class-addr=%p, " + "mapped-clock-class-name=\"%s\", " + "expected-clock-class-addr=%p, " + "expected-clock-class-name=\"%s\"", + mapped_clock_class, + bt_ctf_clock_class_get_name(mapped_clock_class), + *expected_clock_class, + bt_ctf_clock_class_get_name(*expected_clock_class)); + bt_ctf_object_put_ref(mapped_clock_class); + ret = -1; + goto end; + } + } + + break; + } + case BT_CTF_FIELD_TYPE_ID_ENUM: + case BT_CTF_FIELD_TYPE_ID_ARRAY: + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + { + struct bt_ctf_field_type_common *sub_ft = NULL; + + switch (ft->id) { + case BT_CTF_FIELD_TYPE_ID_ENUM: + sub_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type( + ft); + break; + case BT_CTF_FIELD_TYPE_ID_ARRAY: + sub_ft = bt_ctf_field_type_common_array_borrow_element_field_type( + ft); + break; + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + sub_ft = bt_ctf_field_type_common_sequence_borrow_element_field_type( + ft); + break; + default: + BT_LOGF("Unexpected field type ID: id=%d", ft->id); + abort(); + } + + BT_ASSERT(sub_ft); + ret = bt_ctf_field_type_common_validate_single_clock_class(sub_ft, + expected_clock_class); + break; + } + case BT_CTF_FIELD_TYPE_ID_STRUCT: + { + uint64_t i; + int64_t count = bt_ctf_field_type_common_structure_get_field_count( + ft); + + for (i = 0; i < count; i++) { + const char *name; + struct bt_ctf_field_type_common *member_type; + + ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + ft, &name, &member_type, i); + BT_ASSERT(ret == 0); + ret = bt_ctf_field_type_common_validate_single_clock_class( + member_type, expected_clock_class); + if (ret) { + BT_LOGW("Structure field type's field's type " + "is not recursively mapped to the " + "expected clock class: " + "field-ft-addr=%p, field-name=\"%s\"", + member_type, name); + goto end; + } + } + break; + } + case BT_CTF_FIELD_TYPE_ID_VARIANT: + { + uint64_t i; + int64_t count = bt_ctf_field_type_common_variant_get_field_count( + ft); + + for (i = 0; i < count; i++) { + const char *name; + struct bt_ctf_field_type_common *member_type; + + ret = bt_ctf_field_type_common_variant_borrow_field_by_index( + ft, &name, &member_type, i); + BT_ASSERT(ret == 0); + ret = bt_ctf_field_type_common_validate_single_clock_class( + member_type, expected_clock_class); + if (ret) { + BT_LOGW("Variant field type's field's type " + "is not recursively mapped to the " + "expected clock class: " + "field-ft-addr=%p, field-name=\"%s\"", + member_type, name); + goto end; + } + } + break; + } + default: + break; + } + +end: + return ret; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( + struct bt_ctf_field_type *ft); + +static +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive( + struct bt_ctf_field_type *ft); + +static +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( + struct bt_ctf_field_type *ft); + +static +struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive( + struct bt_ctf_field_type *ft); + +static +struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive( + struct bt_ctf_field_type *ft); + +static +struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive( + struct bt_ctf_field_type *ft); + +static +struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive( + struct bt_ctf_field_type *type); + +static +struct bt_ctf_field_type *bt_ctf_field_type_string_copy( + struct bt_ctf_field_type *type); + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_integer_methods = { + .freeze = bt_ctf_field_type_common_generic_freeze, + .validate = bt_ctf_field_type_common_integer_validate, + .set_byte_order = bt_ctf_field_type_common_integer_set_byte_order, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_integer_copy, + .compare = bt_ctf_field_type_common_integer_compare, +}; + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_floating_point_methods = { + .freeze = bt_ctf_field_type_common_generic_freeze, + .validate = NULL, + .set_byte_order = bt_ctf_field_type_common_floating_point_set_byte_order, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_floating_point_copy, + .compare = bt_ctf_field_type_common_floating_point_compare, +}; + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_enumeration_methods = { + .freeze = bt_ctf_field_type_common_enumeration_freeze_recursive, + .validate = bt_ctf_field_type_common_enumeration_validate_recursive, + .set_byte_order = bt_ctf_field_type_common_enumeration_set_byte_order_recursive, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_enumeration_copy_recursive, + .compare = bt_ctf_field_type_common_enumeration_compare_recursive, +}; + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_string_methods = { + .freeze = bt_ctf_field_type_common_generic_freeze, + .validate = NULL, + .set_byte_order = NULL, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_string_copy, + .compare = bt_ctf_field_type_common_string_compare, +}; + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_array_methods = { + .freeze = bt_ctf_field_type_common_array_freeze_recursive, + .validate = bt_ctf_field_type_common_array_validate_recursive, + .set_byte_order = bt_ctf_field_type_common_array_set_byte_order_recursive, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_array_copy_recursive, + .compare = bt_ctf_field_type_common_array_compare_recursive, +}; + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_sequence_methods = { + .freeze = bt_ctf_field_type_common_sequence_freeze_recursive, + .validate = bt_ctf_field_type_common_sequence_validate_recursive, + .set_byte_order = bt_ctf_field_type_common_sequence_set_byte_order_recursive, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_sequence_copy_recursive, + .compare = bt_ctf_field_type_common_sequence_compare_recursive, +}; + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_structure_methods = { + .freeze = bt_ctf_field_type_common_structure_freeze_recursive, + .validate = bt_ctf_field_type_common_structure_validate_recursive, + .set_byte_order = bt_ctf_field_type_common_structure_set_byte_order_recursive, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_structure_copy_recursive, + .compare = bt_ctf_field_type_common_structure_compare_recursive, +}; + +static struct bt_ctf_field_type_common_methods bt_ctf_field_type_variant_methods = { + .freeze = bt_ctf_field_type_common_variant_freeze_recursive, + .validate = bt_ctf_field_type_common_variant_validate_recursive, + .set_byte_order = bt_ctf_field_type_common_variant_set_byte_order_recursive, + .copy = (bt_ctf_field_type_common_method_copy) + bt_ctf_field_type_variant_copy_recursive, + .compare = bt_ctf_field_type_common_variant_compare_recursive, +}; + +typedef int (*bt_ctf_field_type_serialize_func)(struct bt_ctf_field_type_common *, + struct metadata_context *); + +BT_HIDDEN +int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + int ret; + struct bt_ctf_field_type_common *type_common = (void *) type; + bt_ctf_field_type_serialize_func serialize_func; + + BT_ASSERT(type); + BT_ASSERT(context); + + /* Make sure field type is valid before serializing it */ + ret = bt_ctf_field_type_common_validate((void *) type); + if (ret) { + BT_LOGW("Cannot serialize field type's metadata: field type is invalid: " + "addr=%p", type); + goto end; + } + + serialize_func = type_common->spec.writer.serialize_func; + ret = serialize_func((void *) type, context); + +end: + return ret; +} + +static +const char *get_encoding_string(enum bt_ctf_string_encoding encoding) +{ + const char *encoding_string; + + switch (encoding) { + case BT_CTF_STRING_ENCODING_NONE: + encoding_string = "none"; + break; + case BT_CTF_STRING_ENCODING_ASCII: + encoding_string = "ASCII"; + break; + case BT_CTF_STRING_ENCODING_UTF8: + encoding_string = "UTF8"; + break; + default: + encoding_string = "unknown"; + break; + } + + return encoding_string; +} + +static +const char *get_integer_base_string(enum bt_ctf_integer_base base) +{ + const char *base_string; + + switch (base) { + case BT_CTF_INTEGER_BASE_DECIMAL: + case BT_CTF_INTEGER_BASE_UNSPECIFIED: + base_string = "decimal"; + break; + case BT_CTF_INTEGER_BASE_HEXADECIMAL: + base_string = "hexadecimal"; + break; + case BT_CTF_INTEGER_BASE_OCTAL: + base_string = "octal"; + break; + case BT_CTF_INTEGER_BASE_BINARY: + base_string = "binary"; + break; + default: + base_string = "unknown"; + break; + } + + return base_string; +} + +static +void append_field_name(struct metadata_context *context, + const char *name) +{ + g_string_append_c(context->string, ' '); + + if (!bt_ctf_identifier_is_valid(name) || *name == '_') { + g_string_append_c(context->string, '_'); + } + + g_string_append(context->string, name); +} + +static +int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + struct bt_ctf_field_type_common_integer *integer = BT_CTF_FROM_COMMON(type); + int ret = 0; + + BT_LOGD("Serializing CTF writer integer field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + g_string_append_printf(context->string, + "integer { size = %u; align = %u; signed = %s; encoding = %s; base = %s; byte_order = %s", + integer->size, type->alignment, + (integer->is_signed ? "true" : "false"), + get_encoding_string(integer->encoding), + get_integer_base_string(integer->base), + bt_ctf_get_byte_order_string(integer->user_byte_order)); + if (integer->mapped_clock_class) { + const char *clock_name = bt_ctf_clock_class_get_name( + integer->mapped_clock_class); + + BT_ASSERT(clock_name); + g_string_append_printf(context->string, + "; map = clock.%s.value", clock_name); + } + + g_string_append(context->string, "; }"); + return ret; +} + +static +int bt_ctf_field_type_enumeration_serialize_recursive( + struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + size_t entry; + int ret; + struct bt_ctf_field_type_common_enumeration *enumeration = + BT_CTF_FROM_COMMON(type); + struct bt_ctf_field_type_common *container_type; + int container_signed; + + BT_LOGD("Serializing CTF writer enumeration field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + container_type = + bt_ctf_field_type_common_enumeration_borrow_container_field_type(type); + BT_ASSERT(container_type); + container_signed = bt_ctf_field_type_common_integer_is_signed( + container_type); + BT_ASSERT(container_signed >= 0); + g_string_append(context->string, "enum : "); + BT_LOGD_STR("Serializing CTF writer enumeration field type's container field type's metadata."); + ret = bt_ctf_field_type_serialize_recursive( + (void *) enumeration->container_ft, context); + if (ret) { + BT_LOGW("Cannot serialize CTF writer enumeration field type's container field type's metadata: " + "container-ft-addr=%p", enumeration->container_ft); + goto end; + } + + g_string_append(context->string, " { "); + for (entry = 0; entry < enumeration->entries->len; entry++) { + struct bt_ctf_enumeration_mapping *mapping = + enumeration->entries->pdata[entry]; + const char *label = g_quark_to_string(mapping->string); + + g_string_append(context->string, "\""); + + if (!bt_ctf_identifier_is_valid(label) || label[0] == '_') { + g_string_append(context->string, "_"); + } + + g_string_append_printf(context->string, "%s\" = ", label); + + if (container_signed) { + if (mapping->range_start._signed == + mapping->range_end._signed) { + g_string_append_printf(context->string, + "%" PRId64, + mapping->range_start._signed); + } else { + g_string_append_printf(context->string, + "%" PRId64 " ... %" PRId64, + mapping->range_start._signed, + mapping->range_end._signed); + } + } else { + if (mapping->range_start._unsigned == + mapping->range_end._unsigned) { + g_string_append_printf(context->string, + "%" PRIu64, + mapping->range_start._unsigned); + } else { + g_string_append_printf(context->string, + "%" PRIu64 " ... %" PRIu64, + mapping->range_start._unsigned, + mapping->range_end._unsigned); + } + } + + g_string_append(context->string, + ((entry != (enumeration->entries->len - 1)) ? + ", " : " }")); + } + + if (context->field_name->len) { + append_field_name(context, + context->field_name->str); + g_string_assign(context->field_name, ""); + } + +end: + return ret; +} + +static +int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + struct bt_ctf_field_type_common_floating_point *floating_point = + BT_CTF_FROM_COMMON(type); + + BT_LOGD("Serializing CTF writer floating point number field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + g_string_append_printf(context->string, + "floating_point { exp_dig = %u; mant_dig = %u; byte_order = %s; align = %u; }", + floating_point->exp_dig, + floating_point->mant_dig, + bt_ctf_get_byte_order_string(floating_point->user_byte_order), + type->alignment); + return 0; +} + +static +int bt_ctf_field_type_structure_serialize_recursive( + struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + size_t i; + unsigned int indent; + int ret = 0; + struct bt_ctf_field_type_common_structure *structure = BT_CTF_FROM_COMMON(type); + GString *structure_field_name = context->field_name; + + BT_LOGD("Serializing CTF writer structure field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + context->field_name = g_string_new(""); + + context->current_indentation_level++; + g_string_append(context->string, "struct {\n"); + + for (i = 0; i < structure->fields->len; i++) { + struct bt_ctf_field_type_common_structure_field *field = + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + structure, i); + + BT_LOGD("Serializing CTF writer structure field type's field metadata: " + "index=%zu, " + "field-ft-addr=%p, field-name=\"%s\"", + i, field, g_quark_to_string(field->name)); + + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + g_string_assign(context->field_name, + g_quark_to_string(field->name)); + ret = bt_ctf_field_type_serialize_recursive( + (void *) field->type, context); + if (ret) { + BT_LOGW("Cannot serialize CTF writer structure field type's field's metadata: " + "index=%zu, " + "field-ft-addr=%p, field-name=\"%s\"", + i, field->type, + g_quark_to_string(field->name)); + goto end; + } + + if (context->field_name->len) { + append_field_name(context, + context->field_name->str); + } + g_string_append(context->string, ";\n"); + } + + context->current_indentation_level--; + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + g_string_append_printf(context->string, "} align(%u)", + type->alignment); + +end: + g_string_free(context->field_name, TRUE); + context->field_name = structure_field_name; + return ret; +} + +static +int bt_ctf_field_type_variant_serialize_recursive( + struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + size_t i; + unsigned int indent; + int ret = 0; + struct bt_ctf_field_type_common_variant *variant = BT_CTF_FROM_COMMON(type); + GString *variant_field_name = context->field_name; + + BT_LOGD("Serializing CTF writer variant field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + context->field_name = g_string_new(""); + if (variant->tag_name->len > 0) { + g_string_append(context->string, "variant <"); + append_field_name(context, variant->tag_name->str); + g_string_append(context->string, "> {\n"); + } else { + g_string_append(context->string, "variant {\n"); + } + + context->current_indentation_level++; + for (i = 0; i < variant->choices->len; i++) { + struct bt_ctf_field_type_common_variant_choice *field = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + variant, i); + + BT_LOGD("Serializing CTF writer variant field type's field metadata: " + "index=%zu, " + "field-ft-addr=%p, field-name=\"%s\"", + i, field, g_quark_to_string(field->name)); + + g_string_assign(context->field_name, + g_quark_to_string(field->name)); + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + g_string_assign(context->field_name, + g_quark_to_string(field->name)); + ret = bt_ctf_field_type_serialize_recursive( + (void *) field->type, context); + if (ret) { + BT_LOGW("Cannot serialize CTF writer variant field type's field's metadata: " + "index=%zu, " + "field-ft-addr=%p, field-name=\"%s\"", + i, field->type, + g_quark_to_string(field->name)); + goto end; + } + + if (context->field_name->len) { + append_field_name(context, + context->field_name->str); + g_string_append_c(context->string, ';'); + } + + g_string_append_c(context->string, '\n'); + } + + context->current_indentation_level--; + for (indent = 0; indent < context->current_indentation_level; + indent++) { + g_string_append_c(context->string, '\t'); + } + + g_string_append(context->string, "}"); + +end: + g_string_free(context->field_name, TRUE); + context->field_name = variant_field_name; + return ret; +} + +static +int bt_ctf_field_type_array_serialize_recursive( + struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + int ret = 0; + struct bt_ctf_field_type_common_array *array = BT_CTF_FROM_COMMON(type); + + BT_LOGD("Serializing CTF writer array field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + BT_LOGD_STR("Serializing CTF writer array field type's element field type's metadata."); + ret = bt_ctf_field_type_serialize_recursive( + (void *) array->element_ft, context); + if (ret) { + BT_LOGW("Cannot serialize CTF writer array field type's element field type's metadata: " + "element-ft-addr=%p", array->element_ft); + goto end; + } + + if (context->field_name->len) { + append_field_name(context, + context->field_name->str); + + g_string_append_printf(context->string, "[%u]", array->length); + g_string_assign(context->field_name, ""); + } else { + g_string_append_printf(context->string, "[%u]", array->length); + } + +end: + return ret; +} + +static +int bt_ctf_field_type_sequence_serialize_recursive( + struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + int ret = 0; + struct bt_ctf_field_type_common_sequence *sequence = BT_CTF_FROM_COMMON(type); + + BT_LOGD("Serializing CTF writer sequence field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + BT_LOGD_STR("Serializing CTF writer sequence field type's element field type's metadata."); + ret = bt_ctf_field_type_serialize_recursive( + (void *) sequence->element_ft, context); + if (ret) { + BT_LOGW("Cannot serialize CTF writer sequence field type's element field type's metadata: " + "element-ft-addr=%p", sequence->element_ft); + goto end; + } + + if (context->field_name->len) { + append_field_name(context, context->field_name->str); + g_string_assign(context->field_name, ""); + } + g_string_append(context->string, "["); + append_field_name(context, sequence->length_field_name->str); + g_string_append(context->string, "]"); + +end: + return ret; +} + +static +int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type_common *type, + struct metadata_context *context) +{ + struct bt_ctf_field_type_common_string *string = BT_CTF_FROM_COMMON(type); + + BT_LOGD("Serializing CTF writer string field type's metadata: " + "ft-addr=%p, metadata-context-addr=%p", type, context); + g_string_append_printf(context->string, + "string { encoding = %s; }", + get_encoding_string(string->encoding)); + return 0; +} + +struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size) +{ + struct bt_ctf_field_type_common_integer *integer = NULL; + + BT_LOGD("Creating CTF writer integer field type object: size=%u", size); + + if (size == 0 || size > 64) { + BT_LOGW("Invalid parameter: size must be between 1 and 64: " + "size=%u", size); + goto error; + } + + integer = g_new0(struct bt_ctf_field_type_common_integer, 1); + if (!integer) { + BT_LOGE_STR("Failed to allocate one integer field type."); + goto error; + } + + bt_ctf_field_type_common_integer_initialize(BT_CTF_TO_COMMON(integer), + size, bt_ctf_field_type_common_integer_destroy, + &bt_ctf_field_type_integer_methods); + integer->common.spec.writer.serialize_func = + bt_ctf_field_type_integer_serialize; + BT_LOGD("Created CTF writer integer field type object: addr=%p, size=%u", + integer, size); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(integer); + +end: + return (void *) integer; +} + +int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_integer_get_size((void *) ft); +} + +bt_bool bt_ctf_field_type_integer_is_signed(struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_integer_is_signed((void *) ft); +} + +int bt_ctf_field_type_integer_set_is_signed(struct bt_ctf_field_type *ft, + bt_bool is_signed) +{ + return bt_ctf_field_type_common_integer_set_is_signed((void *) ft, + is_signed); +} + +int bt_ctf_field_type_integer_set_size(struct bt_ctf_field_type *ft, + unsigned int size) +{ + return bt_ctf_field_type_common_integer_set_size((void *) ft, size); +} + +enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base( + struct bt_ctf_field_type *ft) +{ + return (int) bt_ctf_field_type_common_integer_get_base((void *) ft); +} + +int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *ft, + enum bt_ctf_integer_base base) +{ + return bt_ctf_field_type_common_integer_set_base((void *) ft, + (int) base); +} + +enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding( + struct bt_ctf_field_type *ft) +{ + return (int) bt_ctf_field_type_common_integer_get_encoding((void *) ft); +} + +int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *ft, + enum bt_ctf_string_encoding encoding) +{ + return bt_ctf_field_type_common_integer_set_encoding((void *) ft, + (int) encoding); +} + +struct bt_ctf_clock_class *bt_ctf_field_type_integer_get_mapped_clock_class( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_object_get_ref(bt_ctf_field_type_common_integer_borrow_mapped_clock_class( + (void *) ft)); +} + +int bt_ctf_field_type_integer_set_mapped_clock_class( + struct bt_ctf_field_type *ft, + struct bt_ctf_clock_class *clock_class) +{ + return bt_ctf_field_type_common_integer_set_mapped_clock_class((void *) ft, + clock_class); +} + +int bt_ctf_field_type_enumeration_signed_get_mapping_by_index( + struct bt_ctf_field_type *ft, uint64_t index, + const char **mapping_name, int64_t *range_begin, + int64_t *range_end) +{ + return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index( + (void *) ft, index, mapping_name, range_begin, range_end); +} + +int bt_ctf_field_type_enumeration_unsigned_get_mapping_by_index( + struct bt_ctf_field_type *ft, uint64_t index, + const char **mapping_name, uint64_t *range_begin, + uint64_t *range_end) +{ + return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index( + (void *) ft, index, mapping_name, range_begin, range_end); +} + +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( + struct bt_ctf_field_type *container_ft) +{ + struct bt_ctf_field_type_common_enumeration *enumeration = NULL; + struct bt_ctf_field_type_common *int_ft = (void *) container_ft; + + BT_LOGD("Creating CTF writer enumeration field type object: int-ft-addr=%p", + container_ft); + + if (!container_ft) { + BT_LOGW_STR("Invalid parameter: field type is NULL."); + goto error; + } + + if (int_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid parameter: container field type is not an integer field type: " + "container-ft-addr=%p, container-ft-id=%s", + container_ft, bt_ctf_field_type_id_string(int_ft->id)); + goto error; + } + + enumeration = g_new0(struct bt_ctf_field_type_common_enumeration, 1); + if (!enumeration) { + BT_LOGE_STR("Failed to allocate one enumeration field type."); + goto error; + } + + bt_ctf_field_type_common_enumeration_initialize(BT_CTF_TO_COMMON(enumeration), + int_ft, bt_ctf_field_type_common_enumeration_destroy_recursive, + &bt_ctf_field_type_enumeration_methods); + enumeration->common.spec.writer.serialize_func = + bt_ctf_field_type_enumeration_serialize_recursive; + BT_LOGD("Created CTF writer enumeration field type object: addr=%p, " + "int-ft-addr=%p, int-ft-size=%u", + enumeration, container_ft, + bt_ctf_field_type_integer_get_size(container_ft)); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration); + +end: + return (void *) enumeration; +} + +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_field_type( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_object_get_ref( + bt_ctf_field_type_common_enumeration_borrow_container_field_type( + (void *) ft)); +} + +int bt_ctf_field_type_enumeration_signed_add_mapping( + struct bt_ctf_field_type *ft, const char *string, + int64_t range_start, int64_t range_end) +{ + return bt_ctf_field_type_common_enumeration_signed_add_mapping( + (void *) ft, string, range_start, range_end); +} + +int bt_ctf_field_type_enumeration_unsigned_add_mapping( + struct bt_ctf_field_type *ft, const char *string, + uint64_t range_start, uint64_t range_end) +{ + return bt_ctf_field_type_common_enumeration_unsigned_add_mapping( + (void *) ft, string, range_start, range_end); +} + +int64_t bt_ctf_field_type_enumeration_get_mapping_count( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_enumeration_get_mapping_count((void *) ft); +} + +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void) +{ + struct bt_ctf_field_type_common_floating_point *floating_point = + g_new0(struct bt_ctf_field_type_common_floating_point, 1); + + BT_LOGD_STR("Creating CTF writer floating point number field type object."); + + if (!floating_point) { + BT_LOGE_STR("Failed to allocate one floating point number field type."); + goto end; + } + + bt_ctf_field_type_common_floating_point_initialize( + BT_CTF_TO_COMMON(floating_point), + bt_ctf_field_type_common_floating_point_destroy, + &bt_ctf_field_type_floating_point_methods); + floating_point->common.spec.writer.serialize_func = + bt_ctf_field_type_floating_point_serialize; + BT_LOGD("Created CTF writer floating point number field type object: addr=%p, " + "exp-size=%u, mant-size=%u", floating_point, + floating_point->exp_dig, floating_point->mant_dig); + +end: + return (void *) floating_point; +} + +int bt_ctf_field_type_floating_point_get_exponent_digits( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_floating_point_get_exponent_digits( + (void *) ft); +} + +int bt_ctf_field_type_floating_point_set_exponent_digits( + struct bt_ctf_field_type *ft, unsigned int exponent_digits) +{ + return bt_ctf_field_type_common_floating_point_set_exponent_digits( + (void *) ft, exponent_digits); +} + +int bt_ctf_field_type_floating_point_get_mantissa_digits( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_floating_point_get_mantissa_digits( + (void *) ft); +} + +int bt_ctf_field_type_floating_point_set_mantissa_digits( + struct bt_ctf_field_type *ft, unsigned int mantissa_digits) +{ + return bt_ctf_field_type_common_floating_point_set_mantissa_digits( + (void *) ft, mantissa_digits); +} + +struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void) +{ + struct bt_ctf_field_type_common_structure *structure = + g_new0(struct bt_ctf_field_type_common_structure, 1); + + BT_LOGD_STR("Creating CTF writer structure field type object."); + + if (!structure) { + BT_LOGE_STR("Failed to allocate one structure field type."); + goto error; + } + + bt_ctf_field_type_common_structure_initialize(BT_CTF_TO_COMMON(structure), + bt_ctf_field_type_common_structure_destroy_recursive, + &bt_ctf_field_type_structure_methods); + structure->common.spec.writer.serialize_func = + bt_ctf_field_type_structure_serialize_recursive; + BT_LOGD("Created CTF writer structure field type object: addr=%p", + structure); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(structure); + +end: + return (void *) structure; +} + +int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *ft, + struct bt_ctf_field_type *field_type, + const char *field_name) +{ + return bt_ctf_field_type_common_structure_add_field((void *) ft, + (void *) field_type, field_name); +} + +int64_t bt_ctf_field_type_structure_get_field_count(struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_structure_get_field_count((void *) ft); +} + +int bt_ctf_field_type_structure_get_field_by_index( + struct bt_ctf_field_type *ft, + const char **field_name, + struct bt_ctf_field_type **field_type, uint64_t index) +{ + int ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + (void *) ft, field_name, (void *) field_type, index); + + if (ret == 0 && field_type) { + bt_ctf_object_get_ref(*field_type); + } + + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name( + struct bt_ctf_field_type *ft, const char *name) +{ + return bt_ctf_object_get_ref(bt_ctf_field_type_common_structure_borrow_field_type_by_name( + (void *) ft, name)); +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_create( + struct bt_ctf_field_type *tag_ft, const char *tag_name) +{ + struct bt_ctf_field_type_common_variant *var_ft = NULL; + + BT_LOGD("Creating CTF writer variant field type object: " + "tag-ft-addr=%p, tag-field-name=\"%s\"", + tag_ft, tag_name); + + if (tag_name && !bt_ctf_identifier_is_valid(tag_name)) { + BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: " + "tag-ft-addr=%p, tag-field-name=\"%s\"", + tag_ft, tag_name); + goto error; + } + + var_ft = g_new0(struct bt_ctf_field_type_common_variant, 1); + if (!var_ft) { + BT_LOGE_STR("Failed to allocate one variant field type."); + goto error; + } + + bt_ctf_field_type_common_variant_initialize(BT_CTF_TO_COMMON(var_ft), + (void *) tag_ft, tag_name, + bt_ctf_field_type_common_variant_destroy_recursive, + &bt_ctf_field_type_variant_methods); + var_ft->common.spec.writer.serialize_func = + bt_ctf_field_type_variant_serialize_recursive; + BT_LOGD("Created CTF writer variant field type object: addr=%p, " + "tag-ft-addr=%p, tag-field-name=\"%s\"", + var_ft, tag_ft, tag_name); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(var_ft); + +end: + return (void *) var_ft; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_field_type( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_tag_field_type( + (void *) ft)); +} + +const char *bt_ctf_field_type_variant_get_tag_name(struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_variant_get_tag_name((void *) ft); +} + +int bt_ctf_field_type_variant_set_tag_name( + struct bt_ctf_field_type *ft, const char *name) +{ + return bt_ctf_field_type_common_variant_set_tag_name((void *) ft, name); +} + +int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *ft, + struct bt_ctf_field_type *field_type, + const char *field_name) +{ + return bt_ctf_field_type_common_variant_add_field((void *) ft, + (void *) field_type, field_name); +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name( + struct bt_ctf_field_type *ft, + const char *field_name) +{ + return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_field_type_by_name( + (void *) ft, field_name)); +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag( + struct bt_ctf_field_type *ft, + struct bt_ctf_field *tag_field) +{ + int ret; + int64_t choice_index; + struct bt_ctf_field *container; + struct bt_ctf_field_type_common_variant *var_ft = (void *) ft; + struct bt_ctf_field_type *ret_ft = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type"); + BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, + "Field type"); + BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID( + (struct bt_ctf_field_common *) tag_field, + BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((struct bt_ctf_field_common *) tag_field, + "Tag field"); + + container = bt_ctf_field_enumeration_borrow_container(tag_field); + BT_ASSERT(container); + + if (var_ft->tag_ft->container_ft->is_signed) { + int64_t val; + + ret = bt_ctf_field_integer_signed_get_value(container, + &val); + BT_ASSERT(ret == 0); + choice_index = bt_ctf_field_type_common_variant_find_choice_index( + (void *) ft, (uint64_t) val, true); + } else { + uint64_t val; + + ret = bt_ctf_field_integer_unsigned_get_value(container, + &val); + BT_ASSERT(ret == 0); + choice_index = bt_ctf_field_type_common_variant_find_choice_index( + (void *) ft, val, false); + } + + if (choice_index < 0) { + BT_LOGW("Cannot find variant field type's field: " + "var-ft-addr=%p, tag-field-addr=%p", ft, tag_field); + goto end; + } + + ret = bt_ctf_field_type_variant_get_field_by_index(ft, NULL, + &ret_ft, choice_index); + BT_ASSERT(ret == 0); + +end: + return ret_ft; +} + +int64_t bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_variant_get_field_count((void *) ft); +} + +int bt_ctf_field_type_variant_get_field_by_index(struct bt_ctf_field_type *ft, + const char **field_name, struct bt_ctf_field_type **field_type, + uint64_t index) +{ + int ret = bt_ctf_field_type_common_variant_borrow_field_by_index( + (void *) ft, field_name, (void *) field_type, index); + + if (ret == 0 && field_type) { + bt_ctf_object_get_ref(*field_type); + } + + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_array_create( + struct bt_ctf_field_type *element_ft, unsigned int length) +{ + struct bt_ctf_field_type_common_array *array = NULL; + + BT_LOGD("Creating CTF writer array field type object: element-ft-addr=%p, " + "length=%u", element_ft, length); + + if (!element_ft) { + BT_LOGW_STR("Invalid parameter: element field type is NULL."); + goto error; + } + + if (length == 0) { + BT_LOGW_STR("Invalid parameter: length is zero."); + goto error; + } + + array = g_new0(struct bt_ctf_field_type_common_array, 1); + if (!array) { + BT_LOGE_STR("Failed to allocate one array field type."); + goto error; + } + + bt_ctf_field_type_common_array_initialize(BT_CTF_TO_COMMON(array), + (void *) element_ft, length, + bt_ctf_field_type_common_array_destroy_recursive, + &bt_ctf_field_type_array_methods); + array->common.spec.writer.serialize_func = + bt_ctf_field_type_array_serialize_recursive; + BT_LOGD("Created CTF writer array field type object: addr=%p, " + "element-ft-addr=%p, length=%u", + array, element_ft, length); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(array); + +end: + return (void *) array; +} + +struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_field_type( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_object_get_ref(bt_ctf_field_type_common_array_borrow_element_field_type( + (void *) ft)); +} + +int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_array_get_length((void *) ft); +} + +struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( + struct bt_ctf_field_type *element_ft, + const char *length_field_name) +{ + struct bt_ctf_field_type_common_sequence *sequence = NULL; + + BT_LOGD("Creating CTF writer sequence field type object: element-ft-addr=%p, " + "length-field-name=\"%s\"", element_ft, length_field_name); + + if (!element_ft) { + BT_LOGW_STR("Invalid parameter: element field type is NULL."); + goto error; + } + + if (!bt_ctf_identifier_is_valid(length_field_name)) { + BT_LOGW("Invalid parameter: length field name is not a valid CTF identifier: " + "length-field-name=\"%s\"", length_field_name); + goto error; + } + + sequence = g_new0(struct bt_ctf_field_type_common_sequence, 1); + if (!sequence) { + BT_LOGE_STR("Failed to allocate one sequence field type."); + goto error; + } + + bt_ctf_field_type_common_sequence_initialize(BT_CTF_TO_COMMON(sequence), + (void *) element_ft, length_field_name, + bt_ctf_field_type_common_sequence_destroy_recursive, + &bt_ctf_field_type_sequence_methods); + sequence->common.spec.writer.serialize_func = + bt_ctf_field_type_sequence_serialize_recursive; + BT_LOGD("Created CTF writer sequence field type object: addr=%p, " + "element-ft-addr=%p, length-field-name=\"%s\"", + sequence, element_ft, length_field_name); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(sequence); + +end: + return (void *) sequence; +} + +struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_field_type( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_object_get_ref(bt_ctf_field_type_common_sequence_borrow_element_field_type( + (void *) ft)); +} + +const char *bt_ctf_field_type_sequence_get_length_field_name( + struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_sequence_get_length_field_name((void *) ft); +} + +struct bt_ctf_field_type *bt_ctf_field_type_string_create(void) +{ + struct bt_ctf_field_type_common_string *string = + g_new0(struct bt_ctf_field_type_common_string, 1); + + BT_LOGD_STR("Creating CTF writer string field type object."); + + if (!string) { + BT_LOGE_STR("Failed to allocate one string field type."); + return NULL; + } + + bt_ctf_field_type_common_string_initialize(BT_CTF_TO_COMMON(string), + bt_ctf_field_type_common_string_destroy, + &bt_ctf_field_type_string_methods); + string->common.spec.writer.serialize_func = + bt_ctf_field_type_string_serialize; + BT_LOGD("Created CTF writer string field type object: addr=%p", string); + return (void *) string; +} + +enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding( + struct bt_ctf_field_type *ft) +{ + return (int) bt_ctf_field_type_common_string_get_encoding((void *) ft); +} + +int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *ft, + enum bt_ctf_string_encoding encoding) +{ + return bt_ctf_field_type_common_string_set_encoding((void *) ft, + (int) encoding); +} + +int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *ft) +{ + return bt_ctf_field_type_common_get_alignment((void *) ft); +} + +int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *ft, + unsigned int alignment) +{ + return bt_ctf_field_type_common_set_alignment((void *) ft, alignment); +} + +enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order( + struct bt_ctf_field_type *ft) +{ + return (int) bt_ctf_field_type_common_get_byte_order((void *) ft); +} + +int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *ft, + enum bt_ctf_byte_order byte_order) +{ + return bt_ctf_field_type_common_set_byte_order((void *) ft, + (int) byte_order); +} + +enum bt_ctf_field_type_id bt_ctf_field_type_get_type_id( + struct bt_ctf_field_type *ft) +{ + return (int) bt_ctf_field_type_common_get_type_id((void *) ft); +} + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft) +{ + return (void *) bt_ctf_field_type_common_copy((void *) ft); +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( + struct bt_ctf_field_type *ft) +{ + struct bt_ctf_field_type_common_integer *int_ft = (void *) ft; + struct bt_ctf_field_type_common_integer *copy_ft; + + BT_LOGD("Copying CTF writer integer field type's: addr=%p", ft); + copy_ft = (void *) bt_ctf_field_type_integer_create(int_ft->size); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer integer field type."); + goto end; + } + + copy_ft->mapped_clock_class = bt_ctf_object_get_ref(int_ft->mapped_clock_class); + copy_ft->user_byte_order = int_ft->user_byte_order; + copy_ft->is_signed = int_ft->is_signed; + copy_ft->size = int_ft->size; + copy_ft->base = int_ft->base; + copy_ft->encoding = int_ft->encoding; + BT_LOGD("Copied CTF writer integer field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + return (void *) copy_ft; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive( + struct bt_ctf_field_type *ft) +{ + size_t i; + struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) ft; + struct bt_ctf_field_type_common_enumeration *copy_ft = NULL; + struct bt_ctf_field_type_common_enumeration *container_copy_ft; + + BT_LOGD("Copying CTF writer enumeration field type's: addr=%p", ft); + + /* Copy the source enumeration's container */ + BT_LOGD_STR("Copying CTF writer enumeration field type's container field type."); + container_copy_ft = BT_CTF_FROM_COMMON(bt_ctf_field_type_common_copy( + BT_CTF_TO_COMMON(enum_ft->container_ft))); + if (!container_copy_ft) { + BT_LOGE_STR("Cannot copy CTF writer enumeration field type's container field type."); + goto end; + } + + copy_ft = (void *) bt_ctf_field_type_enumeration_create( + (void *) container_copy_ft); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer enumeration field type."); + goto end; + } + + /* Copy all enumaration entries */ + for (i = 0; i < enum_ft->entries->len; i++) { + struct bt_ctf_enumeration_mapping *mapping = g_ptr_array_index( + enum_ft->entries, i); + struct bt_ctf_enumeration_mapping *copy_mapping = g_new0( + struct bt_ctf_enumeration_mapping, 1); + + if (!copy_mapping) { + BT_LOGE_STR("Failed to allocate one enumeration mapping."); + goto error; + } + + *copy_mapping = *mapping; + g_ptr_array_add(copy_ft->entries, copy_mapping); + } + + BT_LOGD("Copied CTF writer enumeration field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + bt_ctf_object_put_ref(container_copy_ft); + return (void *) copy_ft; + +error: + bt_ctf_object_put_ref(container_copy_ft); + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); + return (void *) copy_ft; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( + struct bt_ctf_field_type *ft) +{ + struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); + struct bt_ctf_field_type_common_floating_point *copy_ft; + + BT_LOGD("Copying CTF writer floating point number field type's: addr=%p", ft); + copy_ft = (void *) bt_ctf_field_type_floating_point_create(); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer floating point number field type."); + goto end; + } + + copy_ft->user_byte_order = flt_ft->user_byte_order; + copy_ft->exp_dig = flt_ft->exp_dig; + copy_ft->mant_dig = flt_ft->mant_dig; + BT_LOGD("Copied CTF writer floating point number field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + return (void *) copy_ft; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive( + struct bt_ctf_field_type *ft) +{ + int64_t i; + GHashTableIter iter; + gpointer key, value; + struct bt_ctf_field_type_common_structure *struct_ft = (void *) ft; + struct bt_ctf_field_type_common_structure *copy_ft; + + BT_LOGD("Copying CTF writer structure field type's: addr=%p", ft); + copy_ft = (void *) bt_ctf_field_type_structure_create(); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer structure field type."); + goto end; + } + + /* Copy field_name_to_index */ + g_hash_table_iter_init(&iter, struct_ft->field_name_to_index); + while (g_hash_table_iter_next(&iter, &key, &value)) { + g_hash_table_insert(copy_ft->field_name_to_index, + key, value); + } + + g_array_set_size(copy_ft->fields, struct_ft->fields->len); + + for (i = 0; i < struct_ft->fields->len; i++) { + struct bt_ctf_field_type_common_structure_field *entry, *copy_entry; + struct bt_ctf_field_type_common *field_ft_copy; + + entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + struct_ft, i); + copy_entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + copy_ft, i); + BT_LOGD("Copying CTF writer structure field type's field: " + "index=%" PRId64 ", " + "field-ft-addr=%p, field-name=\"%s\"", + i, entry, g_quark_to_string(entry->name)); + + field_ft_copy = (void *) bt_ctf_field_type_copy( + (void *) entry->type); + if (!field_ft_copy) { + BT_LOGE("Cannot copy CTF writer structure field type's field: " + "index=%" PRId64 ", " + "field-ft-addr=%p, field-name=\"%s\"", + i, entry, g_quark_to_string(entry->name)); + goto error; + } + + copy_entry->name = entry->name; + copy_entry->type = field_ft_copy; + } + + BT_LOGD("Copied CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + return (void *) copy_ft; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); + return NULL; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive( + struct bt_ctf_field_type *ft) +{ + int64_t i; + GHashTableIter iter; + gpointer key, value; + struct bt_ctf_field_type_common *tag_ft_copy = NULL; + struct bt_ctf_field_type_common_variant *var_ft = (void *) ft; + struct bt_ctf_field_type_common_variant *copy_ft = NULL; + + BT_LOGD("Copying CTF writer variant field type's: addr=%p", ft); + if (var_ft->tag_ft) { + BT_LOGD_STR("Copying CTF writer variant field type's tag field type."); + tag_ft_copy = bt_ctf_field_type_common_copy( + BT_CTF_TO_COMMON(var_ft->tag_ft)); + if (!tag_ft_copy) { + BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field type."); + goto end; + } + } + + copy_ft = (void *) bt_ctf_field_type_variant_create( + (void *) tag_ft_copy, + var_ft->tag_name->len ? var_ft->tag_name->str : NULL); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer variant field type."); + goto end; + } + + /* Copy field_name_to_index */ + g_hash_table_iter_init(&iter, var_ft->choice_name_to_index); + while (g_hash_table_iter_next(&iter, &key, &value)) { + g_hash_table_insert(copy_ft->choice_name_to_index, + key, value); + } + + g_array_set_size(copy_ft->choices, var_ft->choices->len); + + for (i = 0; i < var_ft->choices->len; i++) { + struct bt_ctf_field_type_common_variant_choice *entry, *copy_entry; + struct bt_ctf_field_type_common *field_ft_copy; + uint64_t range_i; + + entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i); + copy_entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + copy_ft, i); + BT_LOGD("Copying CTF writer variant field type's field: " + "index=%" PRId64 ", " + "field-ft-addr=%p, field-name=\"%s\"", + i, entry, g_quark_to_string(entry->name)); + + field_ft_copy = (void *) bt_ctf_field_type_copy( + (void *) entry->type); + if (!field_ft_copy) { + BT_LOGE("Cannot copy CTF writer variant field type's field: " + "index=%" PRId64 ", " + "field-ft-addr=%p, field-name=\"%s\"", + i, entry, g_quark_to_string(entry->name)); + g_free(copy_entry); + goto error; + } + + copy_entry->name = entry->name; + copy_entry->type = field_ft_copy; + + /* Copy ranges */ + copy_entry->ranges = g_array_new(FALSE, TRUE, + sizeof(struct bt_ctf_field_type_common_variant_choice_range)); + BT_ASSERT(copy_entry->ranges); + g_array_set_size(copy_entry->ranges, entry->ranges->len); + + for (range_i = 0; range_i < entry->ranges->len; range_i++) { + copy_entry->ranges[range_i] = entry->ranges[range_i]; + } + } + + if (var_ft->tag_field_path) { + BT_LOGD_STR("Copying CTF writer variant field type's tag field path."); + copy_ft->tag_field_path = bt_ctf_field_path_copy( + var_ft->tag_field_path); + if (!copy_ft->tag_field_path) { + BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field path."); + goto error; + } + } + + copy_ft->choices_up_to_date = var_ft->choices_up_to_date; + BT_LOGD("Copied CTF writer variant field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + bt_ctf_object_put_ref(tag_ft_copy); + return (void *) copy_ft; + +error: + bt_ctf_object_put_ref(tag_ft_copy); + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); + return NULL; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive( + struct bt_ctf_field_type *ft) +{ + struct bt_ctf_field_type_common *container_ft_copy = NULL; + struct bt_ctf_field_type_common_array *array_ft = (void *) ft; + struct bt_ctf_field_type_common_array *copy_ft = NULL; + + BT_LOGD("Copying CTF writer array field type's: addr=%p", ft); + BT_LOGD_STR("Copying CTF writer array field type's element field type."); + container_ft_copy = bt_ctf_field_type_common_copy(array_ft->element_ft); + if (!container_ft_copy) { + BT_LOGE_STR("Cannot copy CTF writer array field type's element field type."); + goto end; + } + + copy_ft = (void *) bt_ctf_field_type_array_create( + (void *) container_ft_copy, array_ft->length); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer array field type."); + goto end; + } + + BT_LOGD("Copied CTF writer array field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + bt_ctf_object_put_ref(container_ft_copy); + return (void *) copy_ft; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive( + struct bt_ctf_field_type *ft) +{ + struct bt_ctf_field_type_common *container_ft_copy = NULL; + struct bt_ctf_field_type_common_sequence *seq_ft = (void *) ft; + struct bt_ctf_field_type_common_sequence *copy_ft = NULL; + + BT_LOGD("Copying CTF writer sequence field type's: addr=%p", ft); + BT_LOGD_STR("Copying CTF writer sequence field type's element field type."); + container_ft_copy = bt_ctf_field_type_common_copy(seq_ft->element_ft); + if (!container_ft_copy) { + BT_LOGE_STR("Cannot copy CTF writer sequence field type's element field type."); + goto end; + } + + copy_ft = (void *) bt_ctf_field_type_sequence_create( + (void *) container_ft_copy, + seq_ft->length_field_name->len ? + seq_ft->length_field_name->str : NULL); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer sequence field type."); + goto end; + } + + if (seq_ft->length_field_path) { + BT_LOGD_STR("Copying CTF writer sequence field type's length field path."); + copy_ft->length_field_path = bt_ctf_field_path_copy( + seq_ft->length_field_path); + if (!copy_ft->length_field_path) { + BT_LOGE_STR("Cannot copy CTF writer sequence field type's length field path."); + goto error; + } + } + + BT_LOGD("Copied CTF writer sequence field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + bt_ctf_object_put_ref(container_ft_copy); + return (void *) copy_ft; +error: + bt_ctf_object_put_ref(container_ft_copy); + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); + return NULL; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_string_copy(struct bt_ctf_field_type *ft) +{ + struct bt_ctf_field_type_common_string *string_ft = (void *) ft; + struct bt_ctf_field_type_common_string *copy_ft = NULL; + + BT_LOGD("Copying CTF writer string field type's: addr=%p", ft); + copy_ft = (void *) bt_ctf_field_type_string_create(); + if (!copy_ft) { + BT_LOGE_STR("Cannot create CTF writer string field type."); + goto end; + } + + copy_ft->encoding = string_ft->encoding; + BT_LOGD("Copied CTF writer string field type: original-ft-addr=%p, copy-ft-addr=%p", + ft, copy_ft); + +end: + return (void *) copy_ft; +} diff --git a/ctf-writer/field-wrapper.c b/ctf-writer/field-wrapper.c new file mode 100644 index 00000000..a5a3b46f --- /dev/null +++ b/ctf-writer/field-wrapper.c @@ -0,0 +1,87 @@ +/* + * Copyright 2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-FIELD-WRAPPER" +#include "logging.h" + +#include +#include +#include +#include +#include + +BT_HIDDEN +struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data) +{ + struct bt_ctf_field_wrapper *field_wrapper = + g_new0(struct bt_ctf_field_wrapper, 1); + + BT_LOGD_STR("Creating empty field wrapper object."); + + if (!field_wrapper) { + BT_LOGE("Failed to allocate one field wrapper."); + goto end; + } + + bt_ctf_object_init_unique(&field_wrapper->base); + BT_LOGD("Created empty field wrapper object: addr=%p", + field_wrapper); + +end: + return field_wrapper; +} + +BT_HIDDEN +void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field_wrapper) +{ + BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper); + BT_ASSERT(!field_wrapper->field); + BT_LOGD_STR("Putting stream class."); + g_free(field_wrapper); +} + +BT_HIDDEN +struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create( + struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft) +{ + struct bt_ctf_field_wrapper *field_wrapper = NULL; + + BT_ASSERT(pool); + BT_ASSERT(ft); + field_wrapper = bt_ctf_object_pool_create_object(pool); + if (!field_wrapper) { + BT_LOGE("Cannot allocate one field wrapper"); + goto error; + } + + BT_ASSERT(field_wrapper->field); + goto end; + +error: + if (field_wrapper) { + bt_ctf_field_wrapper_destroy(field_wrapper); + field_wrapper = NULL; + } + +end: + return field_wrapper; +} diff --git a/ctf-writer/fields.c b/ctf-writer/fields.c new file mode 100644 index 00000000..327f62e2 --- /dev/null +++ b/ctf-writer/fields.c @@ -0,0 +1,1860 @@ +/* + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-FIELDS" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BT_CTF_ASSERT_PRE_CTF_FIELD_IS_INT_OR_ENUM(_field, _name) \ + BT_CTF_ASSERT_PRE((_field)->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || \ + (_field)->type->id == BT_CTF_FIELD_TYPE_ID_ENUM, \ + _name " is not an integer or an enumeration field: " \ + "field-addr=%p", (_field)) + +BT_HIDDEN +struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field) +{ + struct bt_ctf_field_common *copy = NULL; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Field"); + BT_ASSERT(field_type_common_has_known_id(field->type)); + BT_ASSERT(field->methods->copy); + copy = field->methods->copy(field); + if (!copy) { + BT_LOGW("Cannot create field: ft-addr=%p", field->type); + goto end; + } + + bt_ctf_field_common_set(copy, field->payload_set); + +end: + return copy; +} + +BT_HIDDEN +int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field, + struct bt_ctf_field_type_common *type, + bool is_shared, bt_ctf_object_release_func release_func, + struct bt_ctf_field_common_methods *methods, + bt_ctf_field_common_create_func field_create_func, + GDestroyNotify field_release_func) +{ + int ret = 0; + struct bt_ctf_field_type_common_structure *structure_type = + BT_CTF_FROM_COMMON(type); + struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); + size_t i; + + BT_LOGD("Initializing common structure field object: ft-addr=%p", type); + bt_ctf_field_common_initialize(field, type, is_shared, + release_func, methods); + structure->fields = g_ptr_array_new_with_free_func(field_release_func); + g_ptr_array_set_size(structure->fields, structure_type->fields->len); + + /* Create all fields contained in the structure field. */ + for (i = 0; i < structure_type->fields->len; i++) { + struct bt_ctf_field_common *field; + struct bt_ctf_field_type_common_structure_field *struct_field = + BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( + structure_type, i); + field = field_create_func(struct_field->type); + if (!field) { + BT_LOGE("Failed to create structure field's member: name=\"%s\", index=%zu", + g_quark_to_string(struct_field->name), i); + ret = -1; + goto end; + } + + g_ptr_array_index(structure->fields, i) = field; + } + + BT_LOGD("Initialized common structure field object: addr=%p, ft-addr=%p", + field, type); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field, + struct bt_ctf_field_type_common *type, + bool is_shared, bt_ctf_object_release_func release_func, + struct bt_ctf_field_common_methods *methods, + bt_ctf_field_common_create_func field_create_func, + GDestroyNotify field_release_func) +{ + int ret = 0; + struct bt_ctf_field_type_common_variant *variant_type = + BT_CTF_FROM_COMMON(type); + struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); + size_t i; + + BT_LOGD("Initializing common variant field object: ft-addr=%p", type); + bt_ctf_field_common_initialize(field, type, is_shared, + release_func, methods); + ret = bt_ctf_field_type_common_variant_update_choices(type); + if (ret) { + BT_LOGE("Cannot update common variant field type choices: " + "ret=%d", ret); + goto end; + } + + variant->fields = g_ptr_array_new_with_free_func(field_release_func); + g_ptr_array_set_size(variant->fields, variant_type->choices->len); + + /* Create all fields contained in the variant field. */ + for (i = 0; i < variant_type->choices->len; i++) { + struct bt_ctf_field_common *field; + struct bt_ctf_field_type_common_variant_choice *var_choice = + BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( + variant_type, i); + + field = field_create_func(var_choice->type); + if (!field) { + BT_LOGE("Failed to create variant field's member: name=\"%s\", index=%zu", + g_quark_to_string(var_choice->name), i); + ret = -1; + goto end; + } + + g_ptr_array_index(variant->fields, i) = field; + } + + BT_LOGD("Initialized common variant field object: addr=%p, ft-addr=%p", + field, type); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field, + struct bt_ctf_field_type_common *type, + bool is_shared, bt_ctf_object_release_func release_func, + struct bt_ctf_field_common_methods *methods) +{ + int ret = 0; + struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field); + + BT_LOGD("Initializing common string field object: ft-addr=%p", type); + bt_ctf_field_common_initialize(field, type, is_shared, + release_func, methods); + string->buf = g_array_sized_new(FALSE, FALSE, sizeof(char), 1); + if (!string->buf) { + ret = -1; + goto end; + } + + g_array_index(string->buf, char, 0) = '\0'; + BT_LOGD("Initialized common string field object: addr=%p, ft-addr=%p", + field, type); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field, + struct bt_ctf_field_type_common *type, + bool is_shared, bt_ctf_object_release_func release_func, + struct bt_ctf_field_common_methods *methods, + bt_ctf_field_common_create_func field_create_func, + GDestroyNotify field_destroy_func) +{ + struct bt_ctf_field_type_common_array *array_type = BT_CTF_FROM_COMMON(type); + struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); + unsigned int array_length; + int ret = 0; + uint64_t i; + + BT_LOGD("Initializing common array field object: ft-addr=%p", type); + BT_ASSERT(type); + bt_ctf_field_common_initialize(field, type, is_shared, + release_func, methods); + array_length = array_type->length; + array->elements = g_ptr_array_sized_new(array_length); + if (!array->elements) { + ret = -1; + goto end; + } + + g_ptr_array_set_free_func(array->elements, field_destroy_func); + g_ptr_array_set_size(array->elements, array_length); + + for (i = 0; i < array_length; i++) { + array->elements->pdata[i] = field_create_func( + array_type->element_ft); + if (!array->elements->pdata[i]) { + ret = -1; + goto end; + } + } + + BT_LOGD("Initialized common array field object: addr=%p, ft-addr=%p", + field, type); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field, + struct bt_ctf_field_type_common *type, + bool is_shared, bt_ctf_object_release_func release_func, + struct bt_ctf_field_common_methods *methods, + GDestroyNotify field_destroy_func) +{ + struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); + int ret = 0; + + BT_LOGD("Initializing common sequence field object: ft-addr=%p", type); + BT_ASSERT(type); + bt_ctf_field_common_initialize(field, type, is_shared, + release_func, methods); + sequence->elements = g_ptr_array_new(); + if (!sequence->elements) { + ret = -1; + goto end; + } + + g_ptr_array_set_free_func(sequence->elements, field_destroy_func); + BT_LOGD("Initialized common sequence field object: addr=%p, ft-addr=%p", + field, type); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field) +{ + return (field && field->payload_set) ? 0 : -1; +} + +BT_HIDDEN +int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field) +{ + int64_t i; + int ret = 0; + struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + for (i = 0; i < structure->fields->len; i++) { + ret = bt_ctf_field_common_validate_recursive( + (void *) structure->fields->pdata[i]); + + if (ret) { + int this_ret; + const char *name; + + this_ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + field->type, &name, NULL, i); + BT_ASSERT(this_ret == 0); + BT_CTF_ASSERT_PRE_MSG("Invalid structure field's field: " + "struct-field-addr=%p, field-name=\"%s\", " + "index=%" PRId64 ", field-addr=%p", + field, name, i, structure->fields->pdata[i]); + goto end; + } + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field) +{ + int ret = 0; + struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + if (!variant->current_field) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_common_validate_recursive(variant->current_field); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field) +{ + int64_t i; + int ret = 0; + struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + for (i = 0; i < array->elements->len; i++) { + ret = bt_ctf_field_common_validate_recursive((void *) array->elements->pdata[i]); + if (ret) { + BT_CTF_ASSERT_PRE_MSG("Invalid array field's element field: " + "array-field-addr=%p, %" PRId64 ", " + "elem-field-addr=%p", + field, i, array->elements->pdata[i]); + goto end; + } + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field) +{ + int64_t i; + int ret = 0; + struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + for (i = 0; i < sequence->elements->len; i++) { + ret = bt_ctf_field_common_validate_recursive( + (void *) sequence->elements->pdata[i]); + if (ret) { + BT_CTF_ASSERT_PRE_MSG("Invalid sequence field's element field: " + "seq-field-addr=%p, %" PRId64 ", " + "elem-field-addr=%p", + field, i, sequence->elements->pdata[i]); + goto end; + } + } +end: + return ret; +} + +BT_HIDDEN +void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field) +{ + BT_ASSERT(field); + field->payload_set = false; +} + +BT_HIDDEN +void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field) +{ + int64_t i; + struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + for (i = 0; i < structure->fields->len; i++) { + struct bt_ctf_field_common *member = structure->fields->pdata[i]; + + if (!member) { + /* + * Structure members are lazily initialized; + * skip if this member has not been allocated + * yet. + */ + continue; + } + + bt_ctf_field_common_reset_recursive(member); + } +} + +BT_HIDDEN +void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field) +{ + struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + variant->current_field = NULL; +} + +BT_HIDDEN +void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field) +{ + size_t i; + struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + for (i = 0; i < array->elements->len; i++) { + struct bt_ctf_field_common *member = array->elements->pdata[i]; + + if (!member) { + /* + * Array elements are lazily initialized; skip + * if this member has not been allocated yet. + */ + continue; + } + + bt_ctf_field_common_reset_recursive(member); + } +} + +BT_HIDDEN +void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field) +{ + struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); + uint64_t i; + + BT_ASSERT(field); + + for (i = 0; i < sequence->elements->len; i++) { + if (sequence->elements->pdata[i]) { + bt_ctf_field_common_reset_recursive( + sequence->elements->pdata[i]); + } + } + + sequence->length = 0; +} + +BT_HIDDEN +void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field, + bool is_frozen) +{ + field->frozen = is_frozen; +} + +BT_HIDDEN +void bt_ctf_field_common_structure_set_is_frozen_recursive( + struct bt_ctf_field_common *field, bool is_frozen) +{ + uint64_t i; + struct bt_ctf_field_common_structure *structure_field = + BT_CTF_FROM_COMMON(field); + + BT_LOGD("Freezing structure field object: addr=%p", field); + + for (i = 0; i < structure_field->fields->len; i++) { + struct bt_ctf_field_common *struct_field = + g_ptr_array_index(structure_field->fields, i); + + BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64, + struct_field, i); + bt_ctf_field_common_set_is_frozen_recursive(struct_field, + is_frozen); + } + + bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); +} + +BT_HIDDEN +void bt_ctf_field_common_variant_set_is_frozen_recursive( + struct bt_ctf_field_common *field, bool is_frozen) +{ + uint64_t i; + struct bt_ctf_field_common_variant *variant_field = BT_CTF_FROM_COMMON(field); + + BT_LOGD("Freezing variant field object: addr=%p", field); + + for (i = 0; i < variant_field->fields->len; i++) { + struct bt_ctf_field_common *var_field = + g_ptr_array_index(variant_field->fields, i); + + BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64, + var_field, i); + bt_ctf_field_common_set_is_frozen_recursive(var_field, is_frozen); + } + + bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); +} + +BT_HIDDEN +void bt_ctf_field_common_array_set_is_frozen_recursive( + struct bt_ctf_field_common *field, bool is_frozen) +{ + int64_t i; + struct bt_ctf_field_common_array *array_field = BT_CTF_FROM_COMMON(field); + + BT_LOGD("Freezing array field object: addr=%p", field); + + for (i = 0; i < array_field->elements->len; i++) { + struct bt_ctf_field_common *elem_field = + g_ptr_array_index(array_field->elements, i); + + BT_LOGD("Freezing array field object's element field: " + "element-field-addr=%p, index=%" PRId64, + elem_field, i); + bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen); + } + + bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); +} + +BT_HIDDEN +void bt_ctf_field_common_sequence_set_is_frozen_recursive( + struct bt_ctf_field_common *field, bool is_frozen) +{ + int64_t i; + struct bt_ctf_field_common_sequence *sequence_field = + BT_CTF_FROM_COMMON(field); + + BT_LOGD("Freezing sequence field object: addr=%p", field); + + for (i = 0; i < sequence_field->length; i++) { + struct bt_ctf_field_common *elem_field = + g_ptr_array_index(sequence_field->elements, i); + + BT_LOGD("Freezing sequence field object's element field: " + "element-field-addr=%p, index=%" PRId64, + elem_field, i); + bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen); + } + + bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); +} + +BT_HIDDEN +void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field, + bool is_frozen) +{ + if (!field) { + goto end; + } + + BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d", + field, is_frozen); + BT_ASSERT(field_type_common_has_known_id(field->type)); + BT_ASSERT(field->methods->set_is_frozen); + field->methods->set_is_frozen(field, is_frozen); + +end: + return; +} + +BT_HIDDEN +bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field) +{ + return field && field->payload_set; +} + +BT_HIDDEN +bt_bool bt_ctf_field_common_structure_is_set_recursive( + struct bt_ctf_field_common *field) +{ + bt_bool is_set = BT_FALSE; + size_t i; + struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + for (i = 0; i < structure->fields->len; i++) { + is_set = bt_ctf_field_common_is_set_recursive( + structure->fields->pdata[i]); + if (!is_set) { + goto end; + } + } + +end: + return is_set; +} + +BT_HIDDEN +bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field) +{ + struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); + bt_bool is_set = BT_FALSE; + + BT_ASSERT(field); + + if (variant->current_field) { + is_set = bt_ctf_field_common_is_set_recursive( + variant->current_field); + } + + return is_set; +} + +BT_HIDDEN +bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field) +{ + size_t i; + bt_bool is_set = BT_FALSE; + struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + for (i = 0; i < array->elements->len; i++) { + is_set = bt_ctf_field_common_is_set_recursive(array->elements->pdata[i]); + if (!is_set) { + goto end; + } + } + +end: + return is_set; +} + +BT_HIDDEN +bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field) +{ + size_t i; + bt_bool is_set = BT_FALSE; + struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); + + BT_ASSERT(field); + + if (!sequence->elements) { + goto end; + } + + for (i = 0; i < sequence->elements->len; i++) { + is_set = bt_ctf_field_common_is_set_recursive( + sequence->elements->pdata[i]); + if (!is_set) { + goto end; + } + } + +end: + return is_set; +} + +static struct bt_ctf_field_common_methods bt_ctf_field_integer_methods = { + .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen, + .validate = bt_ctf_field_common_generic_validate, + .copy = NULL, + .is_set = bt_ctf_field_common_generic_is_set, + .reset = bt_ctf_field_common_generic_reset, +}; + +static struct bt_ctf_field_common_methods bt_ctf_field_floating_point_methods = { + .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen, + .validate = bt_ctf_field_common_generic_validate, + .copy = NULL, + .is_set = bt_ctf_field_common_generic_is_set, + .reset = bt_ctf_field_common_generic_reset, +}; + +static +void bt_ctf_field_enumeration_set_is_frozen_recursive( + struct bt_ctf_field_common *field, bool is_frozen); + +static +int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field); + +static +bt_bool bt_ctf_field_enumeration_is_set_recursive( + struct bt_ctf_field_common *field); + +static +void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field); + +static struct bt_ctf_field_common_methods bt_ctf_field_enumeration_methods = { + .set_is_frozen = bt_ctf_field_enumeration_set_is_frozen_recursive, + .validate = bt_ctf_field_enumeration_validate_recursive, + .copy = NULL, + .is_set = bt_ctf_field_enumeration_is_set_recursive, + .reset = bt_ctf_field_enumeration_reset_recursive, +}; + +static struct bt_ctf_field_common_methods bt_ctf_field_string_methods = { + .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen, + .validate = bt_ctf_field_common_generic_validate, + .copy = NULL, + .is_set = bt_ctf_field_common_generic_is_set, + .reset = bt_ctf_field_common_generic_reset, +}; + +static struct bt_ctf_field_common_methods bt_ctf_field_structure_methods = { + .set_is_frozen = bt_ctf_field_common_structure_set_is_frozen_recursive, + .validate = bt_ctf_field_common_structure_validate_recursive, + .copy = NULL, + .is_set = bt_ctf_field_common_structure_is_set_recursive, + .reset = bt_ctf_field_common_structure_reset_recursive, +}; + +static struct bt_ctf_field_common_methods bt_ctf_field_sequence_methods = { + .set_is_frozen = bt_ctf_field_common_sequence_set_is_frozen_recursive, + .validate = bt_ctf_field_common_sequence_validate_recursive, + .copy = NULL, + .is_set = bt_ctf_field_common_sequence_is_set_recursive, + .reset = bt_ctf_field_common_sequence_reset_recursive, +}; + +static struct bt_ctf_field_common_methods bt_ctf_field_array_methods = { + .set_is_frozen = bt_ctf_field_common_array_set_is_frozen_recursive, + .validate = bt_ctf_field_common_array_validate_recursive, + .copy = NULL, + .is_set = bt_ctf_field_common_array_is_set_recursive, + .reset = bt_ctf_field_common_array_reset_recursive, +}; + +static +void bt_ctf_field_variant_set_is_frozen_recursive(struct bt_ctf_field_common *field, + bool is_frozen); + +static +int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field); + +static +bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field); + +static +void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field); + +static struct bt_ctf_field_common_methods bt_ctf_field_variant_methods = { + .set_is_frozen = bt_ctf_field_variant_set_is_frozen_recursive, + .validate = bt_ctf_field_variant_validate_recursive, + .copy = NULL, + .is_set = bt_ctf_field_variant_is_set_recursive, + .reset = bt_ctf_field_variant_reset_recursive, +}; + +static +struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *bt_ctf_field_enumeration_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *bt_ctf_field_floating_point_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *bt_ctf_field_structure_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *); + +static +struct bt_ctf_field *(* const field_create_funcs[])(struct bt_ctf_field_type *) = { + [BT_CTF_FIELD_TYPE_ID_INTEGER] = bt_ctf_field_integer_create, + [BT_CTF_FIELD_TYPE_ID_ENUM] = bt_ctf_field_enumeration_create, + [BT_CTF_FIELD_TYPE_ID_FLOAT] = bt_ctf_field_floating_point_create, + [BT_CTF_FIELD_TYPE_ID_STRUCT] = bt_ctf_field_structure_create, + [BT_CTF_FIELD_TYPE_ID_VARIANT] = bt_ctf_field_variant_create, + [BT_CTF_FIELD_TYPE_ID_ARRAY] = bt_ctf_field_array_create, + [BT_CTF_FIELD_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_create, + [BT_CTF_FIELD_TYPE_ID_STRING] = bt_ctf_field_string_create, +}; + +typedef int (*bt_ctf_field_serialize_recursive_func)( + struct bt_ctf_field_common *, struct bt_ctfser *, + enum bt_ctf_byte_order); + +static +void bt_ctf_field_integer_destroy(struct bt_ctf_field *field) +{ + BT_LOGD("Destroying CTF writer integer field object: addr=%p", field); + bt_ctf_field_common_integer_finalize((void *) field); + g_free(field); +} + +static +void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field) +{ + BT_LOGD("Destroying CTF writer floating point field object: addr=%p", + field); + bt_ctf_field_common_floating_point_finalize((void *) field); + g_free(field); +} + +static +void bt_ctf_field_enumeration_destroy_recursive(struct bt_ctf_field *field) +{ + struct bt_ctf_field_enumeration *enumeration = BT_CTF_FROM_COMMON(field); + + BT_LOGD("Destroying CTF writer enumeration field object: addr=%p", + field); + BT_LOGD_STR("Putting container field."); + bt_ctf_object_put_ref(enumeration->container); + bt_ctf_field_common_finalize((void *) field); + g_free(field); +} + +static +void bt_ctf_field_structure_destroy_recursive(struct bt_ctf_field *field) +{ + BT_LOGD("Destroying CTF writer structure field object: addr=%p", field); + bt_ctf_field_common_structure_finalize_recursive((void *) field); + g_free(field); +} + +static +void bt_ctf_field_variant_destroy_recursive(struct bt_ctf_field *field) +{ + struct bt_ctf_field_variant *variant = BT_CTF_FROM_COMMON(field); + + BT_LOGD("Destroying CTF writer variant field object: addr=%p", field); + BT_LOGD_STR("Putting tag field."); + bt_ctf_object_put_ref(variant->tag); + bt_ctf_field_common_variant_finalize_recursive((void *) field); + g_free(field); +} + +static +void bt_ctf_field_array_destroy_recursive(struct bt_ctf_field *field) +{ + BT_LOGD("Destroying CTF writer array field object: addr=%p", field); + bt_ctf_field_common_array_finalize_recursive((void *) field); + g_free(field); +} + +static +void bt_ctf_field_sequence_destroy_recursive(struct bt_ctf_field *field) +{ + BT_LOGD("Destroying CTF writer sequence field object: addr=%p", field); + bt_ctf_field_common_sequence_finalize_recursive((void *) field); + g_free(field); +} + +static +void bt_ctf_field_string_destroy(struct bt_ctf_field *field) +{ + BT_LOGD("Destroying CTF writer string field object: addr=%p", field); + bt_ctf_field_common_string_finalize((void *) field); + g_free(field); +} + +BT_HIDDEN +int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + struct bt_ctf_field_common *field_common = (void *) field; + bt_ctf_field_serialize_recursive_func serialize_func; + + BT_ASSERT(ctfser); + BT_CTF_ASSERT_PRE_NON_NULL(field, "Field"); + BT_ASSERT(field_common->spec.writer.serialize_func); + serialize_func = field_common->spec.writer.serialize_func; + return serialize_func(field_common, ctfser, + native_byte_order); +} + +static +int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + int ret; + struct bt_ctf_field_type_common_integer *int_type = + BT_CTF_FROM_COMMON(field->type); + struct bt_ctf_field_common_integer *int_field = + BT_CTF_FROM_COMMON(field); + enum bt_ctf_byte_order byte_order; + + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field"); + BT_LOGV("Serializing CTF writer integer field: addr=%p, native-bo=%s", + field, + bt_ctf_byte_order_string(native_byte_order)); + byte_order = int_type->user_byte_order; + if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { + byte_order = native_byte_order; + } + + if (int_type->is_signed) { + ret = bt_ctfser_write_signed_int(ctfser, + int_field->payload.signd, int_type->common.alignment, + int_type->size, + byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? + LITTLE_ENDIAN : BIG_ENDIAN); + } else { + ret = bt_ctfser_write_unsigned_int(ctfser, + int_field->payload.unsignd, int_type->common.alignment, + int_type->size, + byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? + LITTLE_ENDIAN : BIG_ENDIAN); + } + + if (unlikely(ret)) { + BT_LOGE("Cannot serialize integer field: ret=%d", ret); + goto end; + } + +end: + return ret; +} + +static +int bt_ctf_field_enumeration_serialize_recursive( + struct bt_ctf_field_common *field, struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + struct bt_ctf_field_enumeration *enumeration = (void *) field; + + BT_LOGV("Serializing enumeration field: addr=%p, native-bo=%s", + field, bt_ctf_byte_order_string(native_byte_order)); + BT_LOGV_STR("Serializing enumeration field's payload field."); + return bt_ctf_field_serialize_recursive( + (void *) enumeration->container, ctfser, native_byte_order); +} + +static +int bt_ctf_field_floating_point_serialize(struct bt_ctf_field_common *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + int ret = -1; + struct bt_ctf_field_type_common_floating_point *flt_type = + BT_CTF_FROM_COMMON(field->type); + struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field); + enum bt_ctf_byte_order byte_order; + + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field"); + BT_LOGV("Serializing floating point number field: " + "addr=%p, native-bo=%s", field, + bt_ctf_byte_order_string(native_byte_order)); + + byte_order = flt_type->user_byte_order; + if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { + byte_order = native_byte_order; + } + + if (flt_type->mant_dig == FLT_MANT_DIG) { + ret = bt_ctfser_write_float32(ctfser, flt_field->payload, + flt_type->common.alignment, + byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? + LITTLE_ENDIAN : BIG_ENDIAN); + } else if (flt_type->mant_dig == DBL_MANT_DIG) { + ret = bt_ctfser_write_float64(ctfser, flt_field->payload, + flt_type->common.alignment, + byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? + LITTLE_ENDIAN : BIG_ENDIAN); + } else { + abort(); + } + + if (unlikely(ret)) { + BT_LOGE("Cannot serialize floating point number field: " + "ret=%d", ret); + goto end; + } + +end: + return ret; +} + +static +int bt_ctf_field_structure_serialize_recursive(struct bt_ctf_field_common *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + int64_t i; + int ret; + struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); + + BT_LOGV("Serializing structure field: addr=%p, native-bo=%s", + field, bt_ctf_byte_order_string(native_byte_order)); + ret = bt_ctfser_align_offset_in_current_packet(ctfser, + field->type->alignment); + if (unlikely(ret)) { + BT_LOGE("Cannot align offset before serializing structure field: " + "ret=%d", ret); + goto end; + } + + for (i = 0; i < structure->fields->len; i++) { + struct bt_ctf_field_common *member = g_ptr_array_index( + structure->fields, i); + const char *field_name = NULL; + + BT_LOGV("Serializing structure field's field: ser-offset=%" PRIu64 ", " + "field-addr=%p, index=%" PRIu64, + bt_ctfser_get_offset_in_current_packet_bits(ctfser), + member, i); + + if (unlikely(!member)) { + ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + field->type, &field_name, NULL, i); + BT_ASSERT(ret == 0); + BT_LOGW("Cannot serialize structure field's field: field is not set: " + "struct-field-addr=%p, " + "field-name=\"%s\", index=%" PRId64, + field, field_name, i); + ret = -1; + goto end; + } + + ret = bt_ctf_field_serialize_recursive((void *) member, ctfser, + native_byte_order); + if (unlikely(ret)) { + ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + field->type, &field_name, NULL, i); + BT_ASSERT(ret == 0); + BT_LOGW("Cannot serialize structure field's field: " + "struct-field-addr=%p, field-addr=%p, " + "field-name=\"%s\", index=%" PRId64, + field->type, member, field_name, i); + break; + } + } + +end: + return ret; +} + +static +int bt_ctf_field_variant_serialize_recursive(struct bt_ctf_field_common *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); + + BT_LOGV("Serializing variant field: addr=%p, native-bo=%s", + field, bt_ctf_byte_order_string(native_byte_order)); + BT_LOGV_STR("Serializing variant field's payload field."); + return bt_ctf_field_serialize_recursive( + (void *) variant->current_field, ctfser, native_byte_order); +} + +static +int bt_ctf_field_array_serialize_recursive(struct bt_ctf_field_common *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + int64_t i; + int ret = 0; + struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); + + BT_LOGV("Serializing array field: addr=%p, native-bo=%s", + field, bt_ctf_byte_order_string(native_byte_order)); + + for (i = 0; i < array->elements->len; i++) { + struct bt_ctf_field_common *elem_field = + g_ptr_array_index(array->elements, i); + + BT_LOGV("Serializing array field's element field: " + "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64, + bt_ctfser_get_offset_in_current_packet_bits(ctfser), + elem_field, i); + ret = bt_ctf_field_serialize_recursive( + (void *) elem_field, ctfser, native_byte_order); + if (unlikely(ret)) { + BT_LOGW("Cannot serialize array field's element field: " + "array-field-addr=%p, field-addr=%p, " + "index=%" PRId64, field, elem_field, i); + goto end; + } + } + +end: + return ret; +} + +static +int bt_ctf_field_sequence_serialize_recursive(struct bt_ctf_field_common *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + int64_t i; + int ret = 0; + struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); + + BT_LOGV("Serializing sequence field: addr=%p, native-bo=%s", + field, bt_ctf_byte_order_string(native_byte_order)); + + for (i = 0; i < sequence->elements->len; i++) { + struct bt_ctf_field_common *elem_field = + g_ptr_array_index(sequence->elements, i); + + BT_LOGV("Serializing sequence field's element field: " + "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64, + bt_ctfser_get_offset_in_current_packet_bits(ctfser), + elem_field, i); + ret = bt_ctf_field_serialize_recursive( + (void *) elem_field, ctfser, native_byte_order); + if (unlikely(ret)) { + BT_LOGW("Cannot serialize sequence field's element field: " + "sequence-field-addr=%p, field-addr=%p, " + "index=%" PRId64, field, elem_field, i); + goto end; + } + } + +end: + return ret; +} + +static +int bt_ctf_field_string_serialize(struct bt_ctf_field_common *field, + struct bt_ctfser *ctfser, + enum bt_ctf_byte_order native_byte_order) +{ + int ret; + struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field); + + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field"); + BT_LOGV("Serializing string field: addr=%p, native-bo=%s", + field, bt_ctf_byte_order_string((int) native_byte_order)); + ret = bt_ctfser_write_string(ctfser, (const char *) string->buf->data); + if (unlikely(ret)) { + BT_LOGE("Cannot serialize string field: ret=%d", ret); + goto end; + } + +end: + return ret; +} + +struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field *field = NULL; + enum bt_ctf_field_type_id type_id; + + BT_CTF_ASSERT_PRE_NON_NULL(type, "Field type"); + BT_ASSERT(field_type_common_has_known_id((void *) type)); + BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_validate((void *) type) == 0, + "Field type is invalid: ft-addr=%p", type); + type_id = bt_ctf_field_type_get_type_id(type); + field = field_create_funcs[type_id](type); + if (!field) { + goto end; + } + + bt_ctf_field_type_common_freeze((void *) type); + +end: + return field; +} + +struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field) +{ + return bt_ctf_object_get_ref(bt_ctf_field_common_borrow_type((void *) field)); +} + +enum bt_ctf_field_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field) +{ + struct bt_ctf_field_common *field_common = (void *) field; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Field"); + return (int) field_common->type->id; +} + +int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field, + struct bt_ctf_field *length_field) +{ + int ret; + struct bt_ctf_field_common *common_length_field = (void *) length_field; + uint64_t length; + + BT_CTF_ASSERT_PRE_NON_NULL(length_field, "Length field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) length_field, "Length field"); + BT_CTF_ASSERT_PRE(common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || + common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM, + "Length field must be an integer or enumeration field: field-addr=%p", + length_field); + + if (common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM) { + struct bt_ctf_field_enumeration *enumeration = (void *) + length_field; + + length_field = (void *) enumeration->container; + } + + ret = bt_ctf_field_integer_unsigned_get_value(length_field, &length); + BT_ASSERT(ret == 0); + return bt_ctf_field_common_sequence_set_length((void *) field, + length, (bt_ctf_field_common_create_func) bt_ctf_field_create); +} + +struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index( + struct bt_ctf_field *field, uint64_t index) +{ + return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_index( + (void *) field, index)); +} + +struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name( + struct bt_ctf_field *field, const char *name) +{ + return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_name( + (void *) field, name)); +} + +struct bt_ctf_field *bt_ctf_field_array_get_field( + struct bt_ctf_field *field, uint64_t index) +{ + return bt_ctf_object_get_ref( + bt_ctf_field_common_array_borrow_field((void *) field, index)); +} + +struct bt_ctf_field *bt_ctf_field_sequence_get_field( + struct bt_ctf_field *field, uint64_t index) +{ + return bt_ctf_object_get_ref( + bt_ctf_field_common_sequence_borrow_field((void *) field, index)); +} + +struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field, + struct bt_ctf_field *tag_field) +{ + struct bt_ctf_field_variant *variant_field = (void *) field; + struct bt_ctf_field_enumeration *enum_field = (void *) tag_field; + struct bt_ctf_field_type_common_variant *variant_ft; + struct bt_ctf_field_type_common_enumeration *tag_ft; + struct bt_ctf_field *current_field = NULL; + bt_bool is_signed; + uint64_t tag_uval; + int ret; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Variant field"); + BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) tag_field, "Tag field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID( + (struct bt_ctf_field_common *) tag_field, + BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID( + (struct bt_ctf_field_common *) field, + BT_CTF_FIELD_TYPE_ID_VARIANT, "Field"); + BT_CTF_ASSERT_PRE( + bt_ctf_field_common_validate_recursive((void *) tag_field) == 0, + "Tag field is invalid: field-addr=%p", tag_field); + variant_ft = BT_CTF_FROM_COMMON(variant_field->common.common.type); + BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare( + BT_CTF_TO_COMMON(variant_ft->tag_ft), enum_field->common.type) == 0, + "Unexpected tag field's type: expected-ft-addr=%p, " + "tag-ft-addr=%p", variant_ft->tag_ft, + enum_field->common.type); + tag_ft = BT_CTF_FROM_COMMON(enum_field->common.type); + is_signed = tag_ft->container_ft->is_signed; + + if (is_signed) { + int64_t tag_ival; + + ret = bt_ctf_field_integer_signed_get_value( + (void *) enum_field->container, &tag_ival); + tag_uval = (uint64_t) tag_ival; + } else { + ret = bt_ctf_field_integer_unsigned_get_value( + (void *) enum_field->container, &tag_uval); + } + + BT_ASSERT(ret == 0); + ret = bt_ctf_field_common_variant_set_tag((void *) field, tag_uval, + is_signed); + if (ret) { + goto end; + } + + bt_ctf_object_put_ref(variant_field->tag); + variant_field->tag = bt_ctf_object_get_ref(tag_field); + current_field = bt_ctf_field_variant_get_current_field(field); + BT_ASSERT(current_field); + +end: + return current_field; +} + +struct bt_ctf_field *bt_ctf_field_variant_get_current_field( + struct bt_ctf_field *variant_field) +{ + return bt_ctf_object_get_ref(bt_ctf_field_common_variant_borrow_current_field( + (void *) variant_field)); +} + +BT_HIDDEN +struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container( + struct bt_ctf_field *field) +{ + struct bt_ctf_field_enumeration *enumeration = (void *) field; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Enumeration field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID((struct bt_ctf_field_common *) field, + BT_CTF_FIELD_TYPE_ID_ENUM, "Field"); + BT_ASSERT(enumeration->container); + return (void *) enumeration->container; +} + +struct bt_ctf_field *bt_ctf_field_enumeration_get_container( + struct bt_ctf_field *field) +{ + return bt_ctf_object_get_ref(bt_ctf_field_enumeration_borrow_container(field)); +} + +int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field, + int64_t *value) +{ + struct bt_ctf_field_common_integer *integer = (void *) field; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), + BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); + BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_integer_is_signed( + integer->common.type), + "Field's type is unsigned: field-addr=%p", field); + *value = integer->payload.signd; + return 0; +} + +int bt_ctf_field_integer_signed_set_value(struct bt_ctf_field *field, + int64_t value) +{ + int ret = 0; + struct bt_ctf_field_common_integer *integer = (void *) field; + struct bt_ctf_field_type_common_integer *integer_type; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), + BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); + integer_type = BT_CTF_FROM_COMMON(integer->common.type); + BT_CTF_ASSERT_PRE( + bt_ctf_field_type_common_integer_is_signed(integer->common.type), + "Field's type is unsigned: field-addr=%p", field); + BT_CTF_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value), + "Value is out of bounds: value=%" PRId64 ", field-addr=%p", + value, field); + integer->payload.signd = value; + bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true); + return ret; +} + +int bt_ctf_field_integer_unsigned_get_value(struct bt_ctf_field *field, + uint64_t *value) +{ + struct bt_ctf_field_common_integer *integer = (void *) field; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), + BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); + BT_CTF_ASSERT_PRE( + !bt_ctf_field_type_common_integer_is_signed(integer->common.type), + "Field's type is signed: field-addr=%p", field); + *value = integer->payload.unsignd; + return 0; +} + +int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field, + uint64_t value) +{ + struct bt_ctf_field_common_integer *integer = (void *) field; + struct bt_ctf_field_type_common_integer *integer_type; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), + BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); + integer_type = BT_CTF_FROM_COMMON(integer->common.type); + BT_CTF_ASSERT_PRE( + !bt_ctf_field_type_common_integer_is_signed(integer->common.type), + "Field's type is signed: field-addr=%p", field); + BT_CTF_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value), + "Value is out of bounds: value=%" PRIu64 ", field-addr=%p", + value, field); + integer->payload.unsignd = value; + bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true); + return 0; +} + +int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field, + double *value) +{ + return bt_ctf_field_common_floating_point_get_value((void *) field, value); +} + +int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field, + double value) +{ + return bt_ctf_field_common_floating_point_set_value((void *) field, value); +} + +const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field) +{ + return bt_ctf_field_common_string_get_value((void *) field); +} + +int bt_ctf_field_string_set_value(struct bt_ctf_field *field, const char *value) +{ + return bt_ctf_field_common_string_set_value((void *) field, value); +} + +int bt_ctf_field_string_append(struct bt_ctf_field *field, const char *value) +{ + return bt_ctf_field_common_string_append((void *) field, value); +} + +int bt_ctf_field_string_append_len(struct bt_ctf_field *field, + const char *value, unsigned int length) +{ + return bt_ctf_field_common_string_append_len((void *) field, value, length); +} + +struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field) +{ + return (void *) bt_ctf_field_common_copy((void *) field); +} + +static +struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_common_integer *integer = + g_new0(struct bt_ctf_field_common_integer, 1); + + BT_LOGD("Creating CTF writer integer field object: ft-addr=%p", type); + + if (integer) { + bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(integer), (void *) type, + true, + (bt_ctf_object_release_func) bt_ctf_field_integer_destroy, + &bt_ctf_field_integer_methods); + integer->common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) bt_ctf_field_integer_serialize; + BT_LOGD("Created CTF writer integer field object: addr=%p, ft-addr=%p", + integer, type); + } else { + BT_LOGE_STR("Failed to allocate one integer field."); + } + + return (void *) integer; +} + +static +struct bt_ctf_field *bt_ctf_field_enumeration_create( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) type; + struct bt_ctf_field_enumeration *enumeration = g_new0( + struct bt_ctf_field_enumeration, 1); + + BT_LOGD("Creating CTF writer enumeration field object: ft-addr=%p", type); + + if (!enumeration) { + BT_LOGE_STR("Failed to allocate one enumeration field."); + goto end; + } + + bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(enumeration), + (void *) type, + true, (bt_ctf_object_release_func) + bt_ctf_field_enumeration_destroy_recursive, + &bt_ctf_field_enumeration_methods); + enumeration->container = (void *) bt_ctf_field_create( + BT_CTF_FROM_COMMON(enum_ft->container_ft)); + if (!enumeration->container) { + BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration); + goto end; + } + + enumeration->common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) + bt_ctf_field_enumeration_serialize_recursive; + BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p", + enumeration, type); + +end: + return (void *) enumeration; +} + +static +struct bt_ctf_field *bt_ctf_field_floating_point_create( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_common_floating_point *floating_point; + + BT_LOGD("Creating CTF writer floating point number field object: ft-addr=%p", type); + floating_point = g_new0(struct bt_ctf_field_common_floating_point, 1); + + if (floating_point) { + bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(floating_point), + (void *) type, + true, (bt_ctf_object_release_func) + bt_ctf_field_floating_point_destroy, + &bt_ctf_field_floating_point_methods); + floating_point->common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) bt_ctf_field_floating_point_serialize; + BT_LOGD("Created CTF writer floating point number field object: addr=%p, ft-addr=%p", + floating_point, type); + } else { + BT_LOGE_STR("Failed to allocate one floating point number field."); + } + + return (void *) floating_point; +} + +static +struct bt_ctf_field *bt_ctf_field_structure_create( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_common_structure *structure = g_new0( + struct bt_ctf_field_common_structure, 1); + int iret; + + BT_LOGD("Creating CTF writer structure field object: ft-addr=%p", type); + + if (!structure) { + BT_LOGE_STR("Failed to allocate one structure field."); + goto end; + } + + iret = bt_ctf_field_common_structure_initialize(BT_CTF_TO_COMMON(structure), + (void *) type, + true, (bt_ctf_object_release_func) + bt_ctf_field_structure_destroy_recursive, + &bt_ctf_field_structure_methods, + (bt_ctf_field_common_create_func) bt_ctf_field_create, + (GDestroyNotify) bt_ctf_object_put_ref); + structure->common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) bt_ctf_field_structure_serialize_recursive; + if (iret) { + BT_CTF_OBJECT_PUT_REF_AND_RESET(structure); + goto end; + } + + BT_LOGD("Created CTF writer structure field object: addr=%p, ft-addr=%p", + structure, type); + +end: + return (void *) structure; +} + +static +struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_common_variant *var_ft = (void *) type; + struct bt_ctf_field_variant *variant = g_new0( + struct bt_ctf_field_variant, 1); + + BT_LOGD("Creating CTF writer variant field object: ft-addr=%p", type); + + if (!variant) { + BT_LOGE_STR("Failed to allocate one variant field."); + goto end; + } + + bt_ctf_field_common_variant_initialize(BT_CTF_TO_COMMON(BT_CTF_TO_COMMON(variant)), + (void *) type, + true, (bt_ctf_object_release_func) + bt_ctf_field_variant_destroy_recursive, + &bt_ctf_field_variant_methods, + (bt_ctf_field_common_create_func) bt_ctf_field_create, + (GDestroyNotify) bt_ctf_object_put_ref); + variant->tag = (void *) bt_ctf_field_create( + BT_CTF_FROM_COMMON(var_ft->tag_ft)); + variant->common.common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive; + BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p", + variant, type); + +end: + return (void *) variant; +} + +static +struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_common_array *array = + g_new0(struct bt_ctf_field_common_array, 1); + int ret; + + BT_LOGD("Creating CTF writer array field object: ft-addr=%p", type); + BT_ASSERT(type); + + if (!array) { + BT_LOGE_STR("Failed to allocate one array field."); + goto end; + } + + ret = bt_ctf_field_common_array_initialize(BT_CTF_TO_COMMON(array), + (void *) type, + true, (bt_ctf_object_release_func) + bt_ctf_field_array_destroy_recursive, + &bt_ctf_field_array_methods, + (bt_ctf_field_common_create_func) bt_ctf_field_create, + (GDestroyNotify) bt_ctf_object_put_ref); + array->common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) bt_ctf_field_array_serialize_recursive; + if (ret) { + BT_CTF_OBJECT_PUT_REF_AND_RESET(array); + goto end; + } + + BT_LOGD("Created CTF writer array field object: addr=%p, ft-addr=%p", + array, type); + +end: + return (void *) array; +} + +static +struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_common_sequence *sequence = g_new0( + struct bt_ctf_field_common_sequence, 1); + + BT_LOGD("Creating CTF writer sequence field object: ft-addr=%p", type); + + if (sequence) { + bt_ctf_field_common_sequence_initialize(BT_CTF_TO_COMMON(sequence), + (void *) type, + true, (bt_ctf_object_release_func) + bt_ctf_field_sequence_destroy_recursive, + &bt_ctf_field_sequence_methods, + (GDestroyNotify) bt_ctf_object_put_ref); + sequence->common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) bt_ctf_field_sequence_serialize_recursive; + BT_LOGD("Created CTF writer sequence field object: addr=%p, ft-addr=%p", + sequence, type); + } else { + BT_LOGE_STR("Failed to allocate one sequence field."); + } + + return (void *) sequence; +} + +static +struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_common_string *string = g_new0( + struct bt_ctf_field_common_string, 1); + + BT_LOGD("Creating CTF writer string field object: ft-addr=%p", type); + + if (string) { + bt_ctf_field_common_string_initialize(BT_CTF_TO_COMMON(string), + (void *) type, + true, (bt_ctf_object_release_func) + bt_ctf_field_string_destroy, + &bt_ctf_field_string_methods); + string->common.spec.writer.serialize_func = + (bt_ctf_field_serialize_recursive_func) bt_ctf_field_string_serialize; + BT_LOGD("Created CTF writer string field object: addr=%p, ft-addr=%p", + string, type); + } else { + BT_LOGE_STR("Failed to allocate one string field."); + } + + return (void *) string; +} + +static +void bt_ctf_field_enumeration_set_is_frozen_recursive( + struct bt_ctf_field_common *field, bool is_frozen) +{ + struct bt_ctf_field_enumeration *enumeration = (void *) field; + + if (enumeration->container) { + bt_ctf_field_common_set_is_frozen_recursive( + (void *) enumeration->container, is_frozen); + } + + bt_ctf_field_common_generic_set_is_frozen((void *) field, is_frozen); +} + +static +int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field) +{ + int ret = -1; + struct bt_ctf_field_enumeration *enumeration = (void *) field; + + if (enumeration->container) { + ret = bt_ctf_field_common_validate_recursive( + (void *) enumeration->container); + } + + return ret; +} + +static +bt_bool bt_ctf_field_enumeration_is_set_recursive(struct bt_ctf_field_common *field) +{ + bt_bool is_set = BT_FALSE; + struct bt_ctf_field_enumeration *enumeration = (void *) field; + + if (enumeration->container) { + is_set = bt_ctf_field_common_is_set_recursive( + (void *) enumeration->container); + } + + return is_set; +} + +static +void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field) +{ + struct bt_ctf_field_enumeration *enumeration = (void *) field; + + if (enumeration->container) { + bt_ctf_field_common_reset_recursive( + (void *) enumeration->container); + } + + bt_ctf_field_common_generic_reset((void *) field); +} + +static +void bt_ctf_field_variant_set_is_frozen_recursive( + struct bt_ctf_field_common *field, bool is_frozen) +{ + struct bt_ctf_field_variant *variant = (void *) field; + + if (variant->tag) { + bt_ctf_field_common_set_is_frozen_recursive( + (void *) variant->tag, is_frozen); + } + + bt_ctf_field_common_variant_set_is_frozen_recursive((void *) field, + is_frozen); +} + +static +int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field) +{ + int ret; + struct bt_ctf_field_variant *variant = (void *) field; + + if (variant->tag) { + ret = bt_ctf_field_common_validate_recursive( + (void *) variant->tag); + if (ret) { + goto end; + } + } + + ret = bt_ctf_field_common_variant_validate_recursive((void *) field); + +end: + return ret; +} + +static +bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field) +{ + bt_bool is_set; + struct bt_ctf_field_variant *variant = (void *) field; + + if (variant->tag) { + is_set = bt_ctf_field_common_is_set_recursive( + (void *) variant->tag); + if (is_set) { + goto end; + } + } + + is_set = bt_ctf_field_common_variant_is_set_recursive((void *) field); + +end: + return is_set; +} + +static +void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field) +{ + struct bt_ctf_field_variant *variant = (void *) field; + + if (variant->tag) { + bt_ctf_field_common_reset_recursive( + (void *) variant->tag); + } + + bt_ctf_field_common_variant_reset_recursive((void *) field); +} + +BT_CTF_ASSERT_PRE_FUNC +static inline bool field_to_set_has_expected_type( + struct bt_ctf_field_common *struct_field, + const char *name, struct bt_ctf_field_common *value) +{ + bool ret = true; + struct bt_ctf_field_type_common *expected_field_type = NULL; + + expected_field_type = + bt_ctf_field_type_common_structure_borrow_field_type_by_name( + struct_field->type, name); + + if (bt_ctf_field_type_common_compare(expected_field_type, value->type)) { + BT_CTF_ASSERT_PRE_MSG("Value field's type is different from the expected field type: " + "value-ft-addr=%p, expected-ft-addr=%p", value->type, + expected_field_type); + ret = false; + goto end; + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field, + const char *name, struct bt_ctf_field *value) +{ + int ret = 0; + GQuark field_quark; + struct bt_ctf_field_common *common_field = (void *) field; + struct bt_ctf_field_common_structure *structure = + BT_CTF_FROM_COMMON(common_field); + struct bt_ctf_field_common *common_value = (void *) value; + size_t index; + GHashTable *field_name_to_index; + struct bt_ctf_field_type_common_structure *structure_ft; + + BT_CTF_ASSERT_PRE_NON_NULL(field, "Parent field"); + BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(common_field, + BT_CTF_FIELD_TYPE_ID_STRUCT, "Parent field"); + BT_CTF_ASSERT_PRE(field_to_set_has_expected_type(common_field, + name, common_value), + "Value field's type is different from the expected field type."); + field_quark = g_quark_from_string(name); + structure_ft = BT_CTF_FROM_COMMON(common_field->type); + field_name_to_index = structure_ft->field_name_to_index; + if (!g_hash_table_lookup_extended(field_name_to_index, + GUINT_TO_POINTER(field_quark), NULL, + (gpointer *) &index)) { + BT_LOGV("Invalid parameter: no such field in structure field's type: " + "struct-field-addr=%p, struct-ft-addr=%p, " + "field-ft-addr=%p, name=\"%s\"", + field, common_field->type, common_value->type, name); + ret = -1; + goto end; + } + bt_ctf_object_get_ref(value); + BT_CTF_OBJECT_MOVE_REF(structure->fields->pdata[index], value); + +end: + return ret; +} diff --git a/ctf-writer/functor.c b/ctf-writer/functor.c new file mode 100644 index 00000000..e8ad20f8 --- /dev/null +++ b/ctf-writer/functor.c @@ -0,0 +1,39 @@ +/* + * functor.c + * + * Babeltrace CTF Writer + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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 + +BT_HIDDEN +void value_exists(gpointer element, gpointer search_query) +{ + if (element == ((struct bt_ctf_search_query *)search_query)->value) { + ((struct bt_ctf_search_query *)search_query)->found = 1; + } +} diff --git a/ctf-writer/logging.c b/ctf-writer/logging.c new file mode 100644 index 00000000..641d5d99 --- /dev/null +++ b/ctf-writer/logging.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_OUTPUT_LEVEL bt_lib_ctf_writer_log_level +#include "logging.h" + +BT_LOG_INIT_LOG_LEVEL(bt_lib_ctf_writer_log_level, + "BABELTRACE_CTF_WRITER_LOG_LEVEL"); diff --git a/ctf-writer/logging.h b/ctf-writer/logging.h new file mode 100644 index 00000000..a6cf543d --- /dev/null +++ b/ctf-writer/logging.h @@ -0,0 +1,31 @@ +#ifndef BABELTRACE_CTF_WRITER_LOGGING_H +#define BABELTRACE_CTF_WRITER_LOGGING_H + +/* + * Copyright (c) 2017 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_OUTPUT_LEVEL bt_lib_ctf_writer_log_level +#include + +BT_LOG_LEVEL_EXTERN_SYMBOL(bt_lib_ctf_writer_log_level); + +#endif /* BABELTRACE_CTF_WRITER_LOGGING_H */ diff --git a/ctf-writer/object-pool.c b/ctf-writer/object-pool.c new file mode 100644 index 00000000..2d932ac9 --- /dev/null +++ b/ctf-writer/object-pool.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "OBJECT-POOL" +#include "logging.h" + +#include +#include +#include + +int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool, + bt_ctf_object_pool_new_object_func new_object_func, + bt_ctf_object_pool_destroy_object_func destroy_object_func, + void *data) +{ + int ret = 0; + + BT_ASSERT(new_object_func); + BT_ASSERT(destroy_object_func); + BT_LOGD("Initializing object pool: addr=%p, data-addr=%p", + pool, data); + pool->objects = g_ptr_array_new(); + if (!pool->objects) { + BT_LOGE_STR("Failed to allocate a GPtrArray."); + goto error; + } + + pool->funcs.new_object = new_object_func; + pool->funcs.destroy_object = destroy_object_func; + pool->data = data; + pool->size = 0; + BT_LOGD("Initialized object pool."); + goto end; + +error: + if (pool) { + bt_ctf_object_pool_finalize(pool); + } + + ret = -1; + +end: + return ret; +} + +void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool) +{ + uint64_t i; + + BT_ASSERT(pool); + BT_LOGD("Finalizing object pool."); + + if (pool->objects) { + for (i = 0; i < pool->size; i++) { + void *obj = pool->objects->pdata[i]; + + if (obj) { + pool->funcs.destroy_object(obj, pool->data); + } + } + + g_ptr_array_free(pool->objects, TRUE); + pool->objects = NULL; + } +} diff --git a/ctf-writer/object.c b/ctf-writer/object.c new file mode 100644 index 00000000..b6185121 --- /dev/null +++ b/ctf-writer/object.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 Jérémie Galarneau + * + * 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 + +void *bt_ctf_object_get_ref(void *obj) +{ + if (unlikely(!obj)) { + goto end; + } + + bt_ctf_object_get_no_null_check(obj); + +end: + return obj; +} + +void bt_ctf_object_put_ref(void *obj) +{ + if (unlikely(!obj)) { + return; + } + + bt_ctf_object_put_no_null_check(obj); +} diff --git a/ctf-writer/resolve.c b/ctf-writer/resolve.c new file mode 100644 index 00000000..b0a5e156 --- /dev/null +++ b/ctf-writer/resolve.c @@ -0,0 +1,1339 @@ +/* + * resolve.c + * + * Babeltrace - CTF writer: Type resolving internal + * + * Copyright 2015 Jérémie Galarneau + * Copyright 2016 Philippe Proulx + * + * Authors: Jérémie Galarneau + * Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-RESOLVE" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef GPtrArray type_stack; + +/* + * A stack frame. + * + * `type` contains a compound field type (structure, variant, array, + * or sequence) and `index` indicates the index of the field type in + * the upper frame (-1 for array and sequence field types). + * + * `type` is owned by the stack frame. + */ +struct type_stack_frame { + struct bt_ctf_field_type_common *type; + int index; +}; + +/* + * The current context of the resolving engine. + * + * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2) + * in the following order: + * + * * Packet header + * * Packet context + * * Event header + * * Stream event context + * * Event context + * * Event payload + */ +struct resolve_context { + struct bt_ctf_private_value *environment; + struct bt_ctf_field_type_common *scopes[6]; + + /* Root scope being visited */ + enum bt_ctf_scope root_scope; + type_stack *type_stack; + struct bt_ctf_field_type_common *cur_field_type; +}; + +/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */ +static const char * const absolute_path_prefixes[] = { + [BT_CTF_SCOPE_ENV] = "env.", + [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = "trace.packet.header.", + [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = "stream.packet.context.", + [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = "stream.event.header.", + [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = "stream.event.context.", + [BT_CTF_SCOPE_EVENT_CONTEXT] = "event.context.", + [BT_CTF_SCOPE_EVENT_FIELDS] = "event.fields.", +}; + +/* Number of path tokens used for the absolute prefixes */ +static const int absolute_path_prefix_ptoken_counts[] = { + [BT_CTF_SCOPE_ENV] = 1, + [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = 3, + [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = 3, + [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = 3, + [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = 3, + [BT_CTF_SCOPE_EVENT_CONTEXT] = 2, + [BT_CTF_SCOPE_EVENT_FIELDS] = 2, +}; + +/* + * Destroys a type stack frame. + */ +static +void type_stack_destroy_notify(gpointer data) +{ + struct type_stack_frame *frame = data; + + BT_CTF_OBJECT_PUT_REF_AND_RESET(frame->type); + g_free(frame); +} + +/* + * Creates a type stack. + * + * Return value is owned by the caller. + */ +static +type_stack *type_stack_create(void) +{ + return g_ptr_array_new_with_free_func(type_stack_destroy_notify); +} + +/* + * Destroys a type stack. + */ +static +void type_stack_destroy(type_stack *stack) +{ + g_ptr_array_free(stack, TRUE); +} + +/* + * Pushes a field type onto a type stack. + * + * `type` is owned by the caller (stack frame gets a new reference). + */ +static +int type_stack_push(type_stack *stack, struct bt_ctf_field_type_common *type) +{ + int ret = 0; + struct type_stack_frame *frame = NULL; + + if (!stack || !type) { + BT_LOGW("Invalid parameter: stack or type is NULL."); + ret = -1; + goto end; + } + + frame = g_new0(struct type_stack_frame, 1); + if (!frame) { + BT_LOGE_STR("Failed to allocate one field type stack frame."); + ret = -1; + goto end; + } + + BT_LOGV("Pushing field type on context's stack: " + "ft-addr=%p, stack-size-before=%u", type, stack->len); + frame->type = bt_ctf_object_get_ref(type); + g_ptr_array_add(stack, frame); + +end: + return ret; +} + +/* + * Checks whether or not `stack` is empty. + */ +static +bt_bool type_stack_empty(type_stack *stack) +{ + return stack->len == 0; +} + +/* + * Returns the number of frames in `stack`. + */ +static +size_t type_stack_size(type_stack *stack) +{ + return stack->len; +} + +/* + * Returns the top frame of `stack`. + * + * Return value is owned by `stack`. + */ +static +struct type_stack_frame *type_stack_peek(type_stack *stack) +{ + struct type_stack_frame *entry = NULL; + + if (!stack || type_stack_empty(stack)) { + goto end; + } + + entry = g_ptr_array_index(stack, stack->len - 1); +end: + return entry; +} + +/* + * Returns the frame at index `index` in `stack`. + * + * Return value is owned by `stack`. + */ +static +struct type_stack_frame *type_stack_at(type_stack *stack, + size_t index) +{ + struct type_stack_frame *entry = NULL; + + if (!stack || index >= stack->len) { + goto end; + } + + entry = g_ptr_array_index(stack, index); + +end: + return entry; +} + +/* + * Removes the top frame of `stack`. + */ +static +void type_stack_pop(type_stack *stack) +{ + if (!type_stack_empty(stack)) { + /* + * This will call the frame's destructor and free it, as + * well as put its contained field type. + */ + BT_LOGV("Popping context's stack: stack-size-before=%u", + stack->len); + g_ptr_array_set_size(stack, stack->len - 1); + } +} + +/* + * Returns the scope field type of `scope` in the context `ctx`. + * + * Return value is owned by `ctx` on success. + */ +static +struct bt_ctf_field_type_common *get_type_from_ctx(struct resolve_context *ctx, + enum bt_ctf_scope scope) +{ + BT_ASSERT(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER && + scope <= BT_CTF_SCOPE_EVENT_FIELDS); + + return ctx->scopes[scope - BT_CTF_SCOPE_TRACE_PACKET_HEADER]; +} + +/* + * Returns the CTF scope from a path string. May return + * CTF_NODE_UNKNOWN if the path is found to be relative. + */ +static +enum bt_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr) +{ + enum bt_ctf_scope scope; + enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN; + const size_t prefixes_count = sizeof(absolute_path_prefixes) / + sizeof(*absolute_path_prefixes); + + for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_SCOPE_ENV + + prefixes_count; scope++) { + /* + * Chech if path string starts with a known absolute + * path prefix. + * + * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES. + */ + if (strncmp(pathstr, absolute_path_prefixes[scope], + strlen(absolute_path_prefixes[scope]))) { + /* Prefix does not match: try the next one */ + BT_LOGV("Prefix does not match: trying the next one: " + "path=\"%s\", path-prefix=\"%s\", scope=%s", + pathstr, absolute_path_prefixes[scope], + bt_ctf_scope_string(scope)); + continue; + } + + /* Found it! */ + ret = scope; + BT_LOGV("Found root scope from absolute path: " + "path=\"%s\", scope=%s", pathstr, + bt_ctf_scope_string(scope)); + goto end; + } + +end: + return ret; +} + +/* + * Destroys a path token. + */ +static +void ptokens_destroy_func(gpointer ptoken, gpointer data) +{ + g_string_free(ptoken, TRUE); +} + +/* + * Destroys a path token list. + */ +static +void ptokens_destroy(GList *ptokens) +{ + if (!ptokens) { + return; + } + + g_list_foreach(ptokens, ptokens_destroy_func, NULL); + g_list_free(ptokens); +} + +/* + * Returns the string contained in a path token. + */ +static +const char *ptoken_get_string(GList *ptoken) +{ + GString *tokenstr = (GString *) ptoken->data; + + return tokenstr->str; +} + +/* + * Converts a path string to a path token list, that is, splits the + * individual words of a path string into a list of individual + * strings. + * + * Return value is owned by the caller on success. + */ +static +GList *pathstr_to_ptokens(const char *pathstr) +{ + const char *at = pathstr; + const char *last = at; + GList *ptokens = NULL; + + for (;;) { + if (*at == '.' || *at == '\0') { + GString *tokenstr; + + if (at == last) { + /* Error: empty token */ + BT_LOGW("Empty path token: path=\"%s\", pos=%u", + pathstr, (int) (at - pathstr)); + goto error; + } + + tokenstr = g_string_new(NULL); + g_string_append_len(tokenstr, last, at - last); + ptokens = g_list_append(ptokens, tokenstr); + last = at + 1; + } + + if (*at == '\0') { + break; + } + + at++; + } + + return ptokens; + +error: + ptokens_destroy(ptokens); + return NULL; +} + +/* + * Converts a path token list to a field path object. The path token + * list is relative from `type`. The index of the source looking for + * its target within `type` is indicated by `src_index`. This can be + * `INT_MAX` if the source is contained in `type`. + * + * `ptokens` is owned by the caller. `field_path` is an output parameter + * owned by the caller that must be filled here. `type` is owned by the + * caller. + */ +static +int ptokens_to_field_path(GList *ptokens, struct bt_ctf_field_path *field_path, + struct bt_ctf_field_type_common *type, int src_index) +{ + int ret = 0; + GList *cur_ptoken = ptokens; + bt_bool first_level_done = BT_FALSE; + + /* Get our own reference */ + bt_ctf_object_get_ref(type); + + /* Locate target */ + while (cur_ptoken) { + int child_index; + struct bt_ctf_field_type_common *child_type; + const char *field_name = ptoken_get_string(cur_ptoken); + enum bt_ctf_field_type_id type_id = + bt_ctf_field_type_common_get_type_id(type); + + BT_LOGV("Current path token: token=\"%s\"", field_name); + + /* Find to which index corresponds the current path token */ + if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY || + type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) { + child_index = -1; + } else { + child_index = bt_ctf_field_type_common_get_field_index(type, + field_name); + if (child_index < 0) { + /* + * Error: field name does not exist or + * wrong current type. + */ + BT_LOGW("Cannot get index of field type: " + "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d", + field_name, src_index, child_index, first_level_done); + ret = -1; + goto end; + } else if (child_index > src_index && + !first_level_done) { + BT_LOGW("Child field type is located after source field type: " + "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d", + field_name, src_index, child_index, first_level_done); + ret = -1; + goto end; + } + + /* Next path token */ + cur_ptoken = g_list_next(cur_ptoken); + first_level_done = BT_TRUE; + } + + /* Create new field path entry */ + g_array_append_val(field_path->indexes, child_index); + + /* Get child field type */ + child_type = bt_ctf_field_type_common_borrow_field_at_index(type, + child_index); + if (!child_type) { + BT_LOGW("Cannot get child field type: " + "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d", + field_name, src_index, child_index, first_level_done); + ret = -1; + goto end; + } + + /* Move child type to current type */ + bt_ctf_object_get_ref(child_type); + BT_CTF_OBJECT_MOVE_REF(type, child_type); + } + +end: + bt_ctf_object_put_ref(type); + return ret; +} + +/* + * Converts a known absolute path token list to a field path object + * within the resolving context `ctx`. + * + * `ptokens` is owned by the caller. `field_path` is an output parameter + * owned by the caller that must be filled here. + */ +static +int absolute_ptokens_to_field_path(GList *ptokens, + struct bt_ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int ret = 0; + GList *cur_ptoken; + struct bt_ctf_field_type_common *type; + + /* Skip absolute path tokens */ + cur_ptoken = g_list_nth(ptokens, + absolute_path_prefix_ptoken_counts[field_path->root]); + + /* Start with root type */ + type = get_type_from_ctx(ctx, field_path->root); + if (!type) { + /* Error: root type is not available */ + BT_LOGW("Root field type is not available: " + "root-scope=%s", + bt_ctf_scope_string(field_path->root)); + ret = -1; + goto end; + } + + /* Locate target */ + ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX); + +end: + return ret; +} + +/* + * Converts a known relative path token list to a field path object + * within the resolving context `ctx`. + * + * `ptokens` is owned by the caller. `field_path` is an output parameter + * owned by the caller that must be filled here. + */ +static +int relative_ptokens_to_field_path(GList *ptokens, + struct bt_ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int ret = 0; + int parent_pos_in_stack; + struct bt_ctf_field_path *tail_field_path = bt_ctf_field_path_create(); + + if (!tail_field_path) { + BT_LOGE_STR("Cannot create empty field path."); + ret = -1; + goto end; + } + + parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1; + + while (parent_pos_in_stack >= 0) { + struct bt_ctf_field_type_common *parent_type = + type_stack_at(ctx->type_stack, + parent_pos_in_stack)->type; + int cur_index = type_stack_at(ctx->type_stack, + parent_pos_in_stack)->index; + + BT_LOGV("Locating target field type from current parent field type: " + "parent-pos=%d, parent-ft-addr=%p, cur-index=%d", + parent_pos_in_stack, parent_type, cur_index); + + /* Locate target from current parent type */ + ret = ptokens_to_field_path(ptokens, tail_field_path, + parent_type, cur_index); + if (ret) { + /* Not found... yet */ + BT_LOGV_STR("Not found at this point."); + bt_ctf_field_path_clear(tail_field_path); + } else { + /* Found: stitch tail field path to head field path */ + int i = 0; + int tail_field_path_len = + tail_field_path->indexes->len; + + while (BT_TRUE) { + struct bt_ctf_field_type_common *cur_type = + type_stack_at(ctx->type_stack, i)->type; + int index = type_stack_at( + ctx->type_stack, i)->index; + + if (cur_type == parent_type) { + break; + } + + g_array_append_val(field_path->indexes, + index); + i++; + } + + for (i = 0; i < tail_field_path_len; i++) { + int index = g_array_index( + tail_field_path->indexes, + int, i); + + g_array_append_val(field_path->indexes, + index); + } + break; + } + + parent_pos_in_stack--; + } + + if (parent_pos_in_stack < 0) { + /* Not found: look in previous scopes */ + field_path->root--; + + while (field_path->root >= BT_CTF_SCOPE_TRACE_PACKET_HEADER) { + struct bt_ctf_field_type_common *root_type; + bt_ctf_field_path_clear(field_path); + + BT_LOGV("Looking into potential root scope: scope=%s", + bt_ctf_scope_string(field_path->root)); + root_type = get_type_from_ctx(ctx, field_path->root); + if (!root_type) { + field_path->root--; + continue; + } + + /* Locate target in previous scope */ + ret = ptokens_to_field_path(ptokens, field_path, + root_type, INT_MAX); + if (ret) { + /* Not found yet */ + BT_LOGV_STR("Not found in this scope."); + field_path->root--; + continue; + } + + /* Found */ + BT_LOGV_STR("Found in this scope."); + break; + } + } + +end: + BT_CTF_OBJECT_PUT_REF_AND_RESET(tail_field_path); + return ret; +} + +/* + * Converts a path string to a field path object within the resolving + * context `ctx`. + * + * Return value is owned by the caller on success. + */ +static +struct bt_ctf_field_path *pathstr_to_field_path(const char *pathstr, + struct resolve_context *ctx) +{ + int ret; + enum bt_ctf_scope root_scope; + GList *ptokens = NULL; + struct bt_ctf_field_path *field_path = NULL; + + /* Create field path */ + field_path = bt_ctf_field_path_create(); + if (!field_path) { + BT_LOGE_STR("Cannot create empty field path."); + ret = -1; + goto end; + } + + /* Convert path string to path tokens */ + ptokens = pathstr_to_ptokens(pathstr); + if (!ptokens) { + BT_LOGW("Cannot convert path string to path tokens: " + "path=\"%s\"", pathstr); + ret = -1; + goto end; + } + + /* Absolute or relative path? */ + root_scope = get_root_scope_from_absolute_pathstr(pathstr); + + if (root_scope == BT_CTF_SCOPE_UNKNOWN) { + /* Relative path: start with current root scope */ + field_path->root = ctx->root_scope; + BT_LOGV("Detected relative path: starting with current root scope: " + "scope=%s", bt_ctf_scope_string(field_path->root)); + ret = relative_ptokens_to_field_path(ptokens, field_path, ctx); + if (ret) { + BT_LOGW("Cannot get relative field path of path string: " + "path=\"%s\", start-scope=%s, end-scope=%s", + pathstr, bt_ctf_scope_string(ctx->root_scope), + bt_ctf_scope_string(field_path->root)); + goto end; + } + } else if (root_scope == BT_CTF_SCOPE_ENV) { + BT_LOGW("Sequence field types referring the trace environment are not supported as of this version: " + "path=\"%s\"", pathstr); + ret = -1; + goto end; + } else { + /* Absolute path: use found root scope */ + field_path->root = root_scope; + BT_LOGV("Detected absolute path: using root scope: " + "scope=%s", bt_ctf_scope_string(field_path->root)); + ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx); + if (ret) { + BT_LOGW("Cannot get absolute field path of path string: " + "path=\"%s\", root-scope=%s", + pathstr, bt_ctf_scope_string(root_scope)); + goto end; + } + } + + if (ret == 0) { + GString *field_path_pretty = + bt_ctf_field_path_string(field_path); + const char *field_path_pretty_str = + field_path_pretty ? field_path_pretty->str : NULL; + + BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"", + pathstr, field_path_pretty_str); + + if (field_path_pretty) { + g_string_free(field_path_pretty, TRUE); + } + } + +end: + if (ret) { + BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path); + } + + ptokens_destroy(ptokens); + return field_path; +} + +/* + * Retrieves a field type by following the field path `field_path` in + * the resolving context `ctx`. + * + * Return value is owned by the caller on success. + */ +static +struct bt_ctf_field_type_common *field_path_to_field_type( + struct bt_ctf_field_path *field_path, + struct resolve_context *ctx) +{ + int i; + struct bt_ctf_field_type_common *type; + + /* Start with root type */ + type = get_type_from_ctx(ctx, field_path->root); + bt_ctf_object_get_ref(type); + if (!type) { + /* Error: root type is not available */ + BT_LOGW("Root field type is not available: root-scope=%s", + bt_ctf_scope_string(field_path->root)); + goto error; + } + + /* Locate target */ + for (i = 0; i < field_path->indexes->len; i++) { + struct bt_ctf_field_type_common *child_type; + int child_index = + g_array_index(field_path->indexes, int, i); + + /* Get child field type */ + child_type = bt_ctf_field_type_common_borrow_field_at_index(type, + child_index); + if (!child_type) { + BT_LOGW("Cannot get field type: " + "parent-ft-addr=%p, index=%d", type, i); + goto error; + } + + /* Move child type to current type */ + bt_ctf_object_get_ref(child_type); + BT_CTF_OBJECT_MOVE_REF(type, child_type); + } + + return type; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(type); + return type; +} + +/* + * Returns the equivalent field path object of the context type stack. + * + * Return value is owned by the caller on success. + */ +static +struct bt_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx) +{ + int i; + struct bt_ctf_field_path *field_path; + + /* Create field path */ + field_path = bt_ctf_field_path_create(); + if (!field_path) { + BT_LOGE_STR("Cannot create empty field path."); + goto error; + } + + field_path->root = ctx->root_scope; + + for (i = 0; i < type_stack_size(ctx->type_stack); i++) { + struct type_stack_frame *frame; + + frame = type_stack_at(ctx->type_stack, i); + g_array_append_val(field_path->indexes, frame->index); + } + + return field_path; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path); + return field_path; +} + +/* + * Returns the lowest common ancestor of two field path objects + * having the same root scope. + * + * `field_path1` and `field_path2` are owned by the caller. + */ +static +int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1, + struct bt_ctf_field_path *field_path2) +{ + int lca_index = 0; + int field_path1_len, field_path2_len; + + if (BT_LOG_ON_VERBOSE) { + GString *field_path1_pretty = + bt_ctf_field_path_string(field_path1); + GString *field_path2_pretty = + bt_ctf_field_path_string(field_path2); + const char *field_path1_pretty_str = + field_path1_pretty ? field_path1_pretty->str : NULL; + const char *field_path2_pretty_str = + field_path2_pretty ? field_path2_pretty->str : NULL; + + BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: " + "field-path-1=\"%s\", field-path-2=\"%s\"", + field_path1_pretty_str, field_path2_pretty_str); + + if (field_path1_pretty) { + g_string_free(field_path1_pretty, TRUE); + } + + if (field_path2_pretty) { + g_string_free(field_path2_pretty, TRUE); + } + } + + /* + * Start from both roots and find the first mismatch. + */ + BT_ASSERT(field_path1->root == field_path2->root); + field_path1_len = field_path1->indexes->len; + field_path2_len = field_path2->indexes->len; + + while (BT_TRUE) { + int target_index, ctx_index; + + if (lca_index == field_path2_len || + lca_index == field_path1_len) { + /* + * This means that both field paths never split. + * This is invalid because the target cannot be + * an ancestor of the source. + */ + BT_LOGW("Source field type is an ancestor of target field type or vice versa: " + "lca-index=%d, field-path-1-len=%d, " + "field-path-2-len=%d", + lca_index, field_path1_len, field_path2_len); + lca_index = -1; + break; + } + + target_index = g_array_index(field_path1->indexes, int, + lca_index); + ctx_index = g_array_index(field_path2->indexes, int, + lca_index); + + if (target_index != ctx_index) { + /* LCA index is the previous */ + break; + } + + lca_index++; + } + + BT_LOGV("Found LCA: lca-index=%d", lca_index); + return lca_index; +} + +/* + * Validates a target field path. + * + * `target_field_path` and `target_type` are owned by the caller. + */ +static +int validate_target_field_path(struct bt_ctf_field_path *target_field_path, + struct bt_ctf_field_type_common *target_type, + struct resolve_context *ctx) +{ + int ret = 0; + struct bt_ctf_field_path *ctx_field_path; + int target_field_path_len = target_field_path->indexes->len; + int lca_index; + enum bt_ctf_field_type_id ctx_cur_field_type_id; + enum bt_ctf_field_type_id target_type_id; + + /* Get context field path */ + ctx_field_path = get_ctx_stack_field_path(ctx); + if (!ctx_field_path) { + BT_LOGW_STR("Cannot get field path from context's stack."); + ret = -1; + goto end; + } + + /* + * Make sure the target is not a root. + */ + if (target_field_path_len == 0) { + BT_LOGW_STR("Target field path's length is 0 (targeting the root)."); + ret = -1; + goto end; + } + + /* + * Make sure the root of the target field path is not located + * after the context field path's root. + */ + if (target_field_path->root > ctx_field_path->root) { + BT_LOGW("Target field type is located after source field type: " + "target-root=%s, source-root=%s", + bt_ctf_scope_string(target_field_path->root), + bt_ctf_scope_string(ctx_field_path->root)); + ret = -1; + goto end; + } + + if (target_field_path->root == ctx_field_path->root) { + int target_index, ctx_index; + + /* + * Find the index of the lowest common ancestor of both field + * paths. + */ + lca_index = get_field_paths_lca_index(target_field_path, + ctx_field_path); + if (lca_index < 0) { + BT_LOGW_STR("Cannot get least common ancestor."); + ret = -1; + goto end; + } + + /* + * Make sure the target field path is located before the + * context field path. + */ + target_index = g_array_index(target_field_path->indexes, + int, lca_index); + ctx_index = g_array_index(ctx_field_path->indexes, + int, lca_index); + + if (target_index >= ctx_index) { + BT_LOGW("Target field type's index is greater than or equal to source field type's index in LCA: " + "lca-index=%d, target-index=%d, source-index=%d", + lca_index, target_index, ctx_index); + ret = -1; + goto end; + } + } + + /* + * Make sure the target type has the right type and properties. + */ + ctx_cur_field_type_id = bt_ctf_field_type_common_get_type_id( + ctx->cur_field_type); + target_type_id = bt_ctf_field_type_common_get_type_id(target_type); + + switch (ctx_cur_field_type_id) { + case BT_CTF_FIELD_TYPE_ID_VARIANT: + if (target_type_id != BT_CTF_FIELD_TYPE_ID_ENUM) { + BT_LOGW("Variant field type's tag field type is not an enumeration field type: " + "tag-ft-addr=%p, tag-ft-id=%s", + target_type, + bt_ctf_field_type_id_string(target_type_id)); + ret = -1; + goto end; + } + break; + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + if (target_type_id != BT_CTF_FIELD_TYPE_ID_INTEGER || + bt_ctf_field_type_common_integer_is_signed(target_type)) { + BT_LOGW("Sequence field type's length field type is not an unsigned integer field type: " + "length-ft-addr=%p, length-ft-id=%s", + target_type, + bt_ctf_field_type_id_string(target_type_id)); + ret = -1; + goto end; + } + break; + default: + abort(); + } + +end: + BT_CTF_OBJECT_PUT_REF_AND_RESET(ctx_field_path); + return ret; +} + +/* + * Resolves a variant or sequence field type `type`. + * + * `type` is owned by the caller. + */ +static +int resolve_sequence_or_variant_type(struct bt_ctf_field_type_common *type, + struct resolve_context *ctx) +{ + int ret = 0; + const char *pathstr; + enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type); + struct bt_ctf_field_path *target_field_path = NULL; + struct bt_ctf_field_type_common *target_type = NULL; + GString *target_field_path_pretty = NULL; + const char *target_field_path_pretty_str; + + + /* Get path string */ + switch (type_id) { + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + pathstr = + bt_ctf_field_type_common_sequence_get_length_field_name(type); + break; + case BT_CTF_FIELD_TYPE_ID_VARIANT: + pathstr = + bt_ctf_field_type_common_variant_get_tag_name(type); + break; + default: + abort(); + } + + if (!pathstr) { + BT_LOGW_STR("Cannot get path string."); + ret = -1; + goto end; + } + + /* Get target field path out of path string */ + target_field_path = pathstr_to_field_path(pathstr, ctx); + if (!target_field_path) { + BT_LOGW("Cannot get target field path for path string: " + "path=\"%s\"", pathstr); + ret = -1; + goto end; + } + + target_field_path_pretty = bt_ctf_field_path_string(target_field_path); + target_field_path_pretty_str = + target_field_path_pretty ? target_field_path_pretty->str : NULL; + + /* Get target field type */ + target_type = field_path_to_field_type(target_field_path, ctx); + if (!target_type) { + BT_LOGW("Cannot get target field type for path string: " + "path=\"%s\", target-field-path=\"%s\"", + pathstr, target_field_path_pretty_str); + ret = -1; + goto end; + } + + ret = validate_target_field_path(target_field_path, target_type, ctx); + if (ret) { + BT_LOGW("Invalid target field path for path string: " + "path=\"%s\", target-field-path=\"%s\"", + pathstr, target_field_path_pretty_str); + goto end; + } + + /* Set target field path and target field type */ + switch (type_id) { + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + ret = bt_ctf_field_type_common_sequence_set_length_field_path( + type, target_field_path); + if (ret) { + BT_LOGW("Cannot set sequence field type's length field path: " + "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"", + ret, type, pathstr, + target_field_path_pretty_str); + goto end; + } + break; + case BT_CTF_FIELD_TYPE_ID_VARIANT: + ret = bt_ctf_field_type_common_variant_set_tag_field_path( + type, target_field_path); + if (ret) { + BT_LOGW("Cannot set varaint field type's tag field path: " + "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"", + ret, type, pathstr, + target_field_path_pretty_str); + goto end; + } + + ret = bt_ctf_field_type_common_variant_set_tag_field_type( + type, target_type); + if (ret) { + BT_LOGW("Cannot set varaint field type's tag field type: " + "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"", + ret, type, pathstr, + target_field_path_pretty_str); + goto end; + } + break; + default: + abort(); + } + +end: + if (target_field_path_pretty) { + g_string_free(target_field_path_pretty, TRUE); + } + + BT_CTF_OBJECT_PUT_REF_AND_RESET(target_field_path); + BT_CTF_OBJECT_PUT_REF_AND_RESET(target_type); + return ret; +} + +/* + * Resolves a field type `type`. + * + * `type` is owned by the caller. + */ +static +int resolve_type(struct bt_ctf_field_type_common *type, struct resolve_context *ctx) +{ + int ret = 0; + enum bt_ctf_field_type_id type_id; + + if (!type) { + /* Type is not available; still valid */ + goto end; + } + + type_id = bt_ctf_field_type_common_get_type_id(type); + ctx->cur_field_type = type; + + /* Resolve sequence/variant field type */ + switch (type_id) { + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + case BT_CTF_FIELD_TYPE_ID_VARIANT: + ret = resolve_sequence_or_variant_type(type, ctx); + if (ret) { + BT_LOGW("Cannot resolve sequence field type's length or variant field type's tag: " + "ret=%d, ft-addr=%p", ret, type); + goto end; + } + break; + default: + break; + } + + /* Recurse into compound types */ + switch (type_id) { + case BT_CTF_FIELD_TYPE_ID_STRUCT: + case BT_CTF_FIELD_TYPE_ID_VARIANT: + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + case BT_CTF_FIELD_TYPE_ID_ARRAY: + { + int64_t field_count, f_index; + + ret = type_stack_push(ctx->type_stack, type); + if (ret) { + BT_LOGW("Cannot push field type on context's stack: " + "ft-addr=%p", type); + goto end; + } + + field_count = bt_ctf_field_type_common_get_field_count(type); + if (field_count < 0) { + BT_LOGW("Cannot get field type's field count: " + "ret=%" PRId64 ", ft-addr=%p", + field_count, type); + ret = field_count; + goto end; + } + + for (f_index = 0; f_index < field_count; f_index++) { + struct bt_ctf_field_type_common *child_type = + bt_ctf_field_type_common_borrow_field_at_index(type, + f_index); + + if (!child_type) { + BT_LOGW("Cannot get field type's child field: " + "ft-addr=%p, index=%" PRId64 ", " + "count=%" PRId64, type, f_index, + field_count); + ret = -1; + goto end; + } + + if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY|| + type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) { + type_stack_peek(ctx->type_stack)->index = -1; + } else { + type_stack_peek(ctx->type_stack)->index = + f_index; + } + + BT_LOGV("Resolving field type's child field type: " + "parent-ft-addr=%p, child-ft-addr=%p, " + "index=%" PRId64 ", count=%" PRId64, + type, child_type, f_index, field_count); + ret = resolve_type(child_type, ctx); + if (ret) { + goto end; + } + } + + type_stack_pop(ctx->type_stack); + break; + } + default: + break; + } + +end: + return ret; +} + +/* + * Resolves the root field type corresponding to the scope `root_scope`. + */ +static +int resolve_root_type(enum bt_ctf_scope root_scope, struct resolve_context *ctx) +{ + int ret; + + BT_ASSERT(type_stack_size(ctx->type_stack) == 0); + ctx->root_scope = root_scope; + ret = resolve_type(get_type_from_ctx(ctx, root_scope), ctx); + ctx->root_scope = BT_CTF_SCOPE_UNKNOWN; + + return ret; +} + +BT_HIDDEN +int bt_ctf_resolve_types( + struct bt_ctf_private_value *environment, + struct bt_ctf_field_type_common *packet_header_type, + struct bt_ctf_field_type_common *packet_context_type, + struct bt_ctf_field_type_common *event_header_type, + struct bt_ctf_field_type_common *stream_event_ctx_type, + struct bt_ctf_field_type_common *event_context_type, + struct bt_ctf_field_type_common *event_payload_type, + enum bt_ctf_resolve_flag flags) +{ + int ret = 0; + struct resolve_context ctx = { + .environment = environment, + .scopes = { + packet_header_type, + packet_context_type, + event_header_type, + stream_event_ctx_type, + event_context_type, + event_payload_type, + }, + .root_scope = BT_CTF_SCOPE_UNKNOWN, + }; + + BT_LOGV("Resolving field types: " + "packet-header-ft-addr=%p, " + "packet-context-ft-addr=%p, " + "event-header-ft-addr=%p, " + "stream-event-context-ft-addr=%p, " + "event-context-ft-addr=%p, " + "event-payload-ft-addr=%p", + packet_header_type, packet_context_type, event_header_type, + stream_event_ctx_type, event_context_type, event_payload_type); + + /* Initialize type stack */ + ctx.type_stack = type_stack_create(); + if (!ctx.type_stack) { + BT_LOGE_STR("Cannot create field type stack."); + ret = -1; + goto end; + } + + /* Resolve packet header type */ + if (flags & BT_CTF_RESOLVE_FLAG_PACKET_HEADER) { + ret = resolve_root_type(BT_CTF_SCOPE_TRACE_PACKET_HEADER, &ctx); + if (ret) { + BT_LOGW("Cannot resolve trace packet header field type: " + "ret=%d", ret); + goto end; + } + } + + /* Resolve packet context type */ + if (flags & BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT) { + ret = resolve_root_type(BT_CTF_SCOPE_STREAM_PACKET_CONTEXT, &ctx); + if (ret) { + BT_LOGW("Cannot resolve stream packet context field type: " + "ret=%d", ret); + goto end; + } + } + + /* Resolve event header type */ + if (flags & BT_CTF_RESOLVE_FLAG_EVENT_HEADER) { + ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_HEADER, &ctx); + if (ret) { + BT_LOGW("Cannot resolve stream event header field type: " + "ret=%d", ret); + goto end; + } + } + + /* Resolve stream event context type */ + if (flags & BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) { + ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_CONTEXT, &ctx); + if (ret) { + BT_LOGW("Cannot resolve stream event context field type: " + "ret=%d", ret); + goto end; + } + } + + /* Resolve event context type */ + if (flags & BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT) { + ret = resolve_root_type(BT_CTF_SCOPE_EVENT_CONTEXT, &ctx); + if (ret) { + BT_LOGW("Cannot resolve event context field type: " + "ret=%d", ret); + goto end; + } + } + + /* Resolve event payload type */ + if (flags & BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) { + ret = resolve_root_type(BT_CTF_SCOPE_EVENT_FIELDS, &ctx); + if (ret) { + BT_LOGW("Cannot resolve event payload field type: " + "ret=%d", ret); + goto end; + } + } + + BT_LOGV_STR("Resolved field types."); + +end: + type_stack_destroy(ctx.type_stack); + + return ret; +} diff --git a/ctf-writer/stream-class.c b/ctf-writer/stream-class.c new file mode 100644 index 00000000..4b61a7ec --- /dev/null +++ b/ctf-writer/stream-class.c @@ -0,0 +1,1145 @@ +/* + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2017-2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-STREAM-CLASS" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BT_HIDDEN +int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class, + const char *name, bt_ctf_object_release_func release_func) +{ + BT_LOGD("Initializing common stream class object: name=\"%s\"", name); + + bt_ctf_object_init_shared_with_parent(&stream_class->base, release_func); + stream_class->name = g_string_new(name); + stream_class->event_classes = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_ctf_object_try_spec_release); + if (!stream_class->event_classes) { + BT_LOGE_STR("Failed to allocate a GPtrArray."); + goto error; + } + + stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash, + g_int64_equal, g_free, NULL); + if (!stream_class->event_classes_ht) { + BT_LOGE_STR("Failed to allocate a GHashTable."); + goto error; + } + + BT_LOGD("Initialized common stream class object: addr=%p, name=\"%s\"", + stream_class, name); + return 0; + +error: + return -1; +} + +BT_HIDDEN +void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class) +{ + BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64, + stream_class, bt_ctf_stream_class_common_get_name(stream_class), + bt_ctf_stream_class_common_get_id(stream_class)); + bt_ctf_object_put_ref(stream_class->clock_class); + + if (stream_class->event_classes_ht) { + g_hash_table_destroy(stream_class->event_classes_ht); + } + if (stream_class->event_classes) { + BT_LOGD_STR("Destroying event classes."); + g_ptr_array_free(stream_class->event_classes, TRUE); + } + + if (stream_class->name) { + g_string_free(stream_class->name, TRUE); + } + + BT_LOGD_STR("Putting event header field type."); + bt_ctf_object_put_ref(stream_class->event_header_field_type); + BT_LOGD_STR("Putting packet context field type."); + bt_ctf_object_put_ref(stream_class->packet_context_field_type); + BT_LOGD_STR("Putting event context field type."); + bt_ctf_object_put_ref(stream_class->event_context_field_type); +} + +static +void event_class_exists(gpointer element, gpointer query) +{ + struct bt_ctf_event_class_common *event_class_a = element; + struct bt_ctf_search_query *search_query = query; + struct bt_ctf_event_class_common *event_class_b = search_query->value; + int64_t id_a, id_b; + + if (search_query->value == element) { + search_query->found = 1; + goto end; + } + + /* + * Two event classes cannot share the same ID in a given + * stream class. + */ + id_a = bt_ctf_event_class_common_get_id(event_class_a); + id_b = bt_ctf_event_class_common_get_id(event_class_b); + + if (id_a < 0 || id_b < 0) { + /* at least one ID is not set: will be automatically set later */ + goto end; + } + + if (id_a == id_b) { + BT_LOGW("Event class with this ID already exists in the stream class: " + "id=%" PRId64 ", name=\"%s\"", + id_a, bt_ctf_event_class_common_get_name(event_class_a)); + search_query->found = 1; + goto end; + } + +end: + return; +} + +BT_HIDDEN +int bt_ctf_stream_class_common_add_event_class( + struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_event_class_common *event_class, + bt_ctf_validation_flag_copy_field_type_func copy_field_type_func) +{ + int ret = 0; + int64_t *event_id = NULL; + struct bt_ctf_trace_common *trace = NULL; + struct bt_ctf_stream_class_common *old_stream_class = NULL; + struct bt_ctf_validation_output validation_output = { 0 }; + struct bt_ctf_field_type_common *packet_header_type = NULL; + struct bt_ctf_field_type_common *packet_context_type = NULL; + struct bt_ctf_field_type_common *event_header_type = NULL; + struct bt_ctf_field_type_common *stream_event_ctx_type = NULL; + struct bt_ctf_field_type_common *event_context_type = NULL; + struct bt_ctf_field_type_common *event_payload_type = NULL; + const enum bt_ctf_validation_flag validation_flags = + BT_CTF_VALIDATION_FLAG_EVENT; + struct bt_ctf_clock_class *expected_clock_class = NULL; + + BT_ASSERT(copy_field_type_func); + + if (!stream_class || !event_class) { + BT_LOGW("Invalid parameter: stream class or event class is NULL: " + "stream-class-addr=%p, event-class-addr=%p", + stream_class, event_class); + ret = -1; + goto end; + } + + BT_LOGD("Adding event class to stream class: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", event-class-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64, + stream_class, bt_ctf_stream_class_common_get_name(stream_class), + bt_ctf_stream_class_common_get_id(stream_class), + event_class, + bt_ctf_event_class_common_get_name(event_class), + bt_ctf_event_class_common_get_id(event_class)); + trace = bt_ctf_stream_class_common_borrow_trace(stream_class); + + if (stream_class->frozen) { + /* + * We only check that the event class to be added has a + * single class which matches the stream class's + * expected clock class if the stream class is frozen. + * If it's not, then this event class is added "as is" + * and the validation will be performed when calling + * either bt_ctf_trace_add_stream_class() or + * bt_ctf_event_create(). This is because the stream class's + * field types (packet context, event header, event + * context) could change before the next call to one of + * those two functions. + */ + expected_clock_class = bt_ctf_object_get_ref(stream_class->clock_class); + + /* + * At this point, `expected_clock_class` can be NULL, + * and bt_ctf_event_class_validate_single_clock_class() + * below can set it. + */ + ret = bt_ctf_event_class_common_validate_single_clock_class( + event_class, &expected_clock_class); + if (ret) { + BT_LOGW("Event class contains a field type which is not " + "recursively mapped to its stream class's " + "expected clock class: " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", " + "stream-class-name=\"%s\", " + "expected-clock-class-addr=%p, " + "expected-clock-class-name=\"%s\"", + stream_class, + bt_ctf_stream_class_common_get_id(stream_class), + bt_ctf_stream_class_common_get_name(stream_class), + expected_clock_class, + expected_clock_class ? + bt_ctf_clock_class_get_name(expected_clock_class) : + NULL); + goto end; + } + } + + event_id = g_new(int64_t, 1); + if (!event_id) { + BT_LOGE_STR("Failed to allocate one int64_t."); + ret = -1; + goto end; + } + + /* Check for duplicate event classes */ + struct bt_ctf_search_query query = { .value = event_class, .found = 0 }; + g_ptr_array_foreach(stream_class->event_classes, event_class_exists, + &query); + if (query.found) { + BT_LOGW_STR("Another event class part of this stream class has the same ID."); + ret = -1; + goto end; + } + + old_stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class); + if (old_stream_class) { + /* Event class is already associated to a stream class. */ + BT_LOGW("Event class is already part of another stream class: " + "event-class-stream-class-addr=%p, " + "event-class-stream-class-name=\"%s\", " + "event-class-stream-class-id=%" PRId64, + old_stream_class, + bt_ctf_stream_class_common_get_name(old_stream_class), + bt_ctf_stream_class_common_get_id(old_stream_class)); + ret = -1; + goto end; + } + + if (trace) { + /* + * If the stream class is associated with a trace, then + * both those objects are frozen. Also, this event class + * is about to be frozen. + * + * Therefore the event class must be validated here. + * The trace and stream class should be valid at this + * point. + */ + BT_ASSERT(trace->valid); + BT_ASSERT(stream_class->valid); + packet_header_type = + bt_ctf_trace_common_borrow_packet_header_field_type(trace); + packet_context_type = + bt_ctf_stream_class_common_borrow_packet_context_field_type( + stream_class); + event_header_type = + bt_ctf_stream_class_common_borrow_event_header_field_type( + stream_class); + stream_event_ctx_type = + bt_ctf_stream_class_common_borrow_event_context_field_type( + stream_class); + event_context_type = + bt_ctf_event_class_common_borrow_context_field_type( + event_class); + event_payload_type = + bt_ctf_event_class_common_borrow_payload_field_type( + event_class); + ret = bt_ctf_validate_class_types( + trace->environment, packet_header_type, + packet_context_type, event_header_type, + stream_event_ctx_type, event_context_type, + event_payload_type, trace->valid, + stream_class->valid, event_class->valid, + &validation_output, validation_flags, + copy_field_type_func); + + if (ret) { + /* + * This means something went wrong during the + * validation process, not that the objects are + * invalid. + */ + BT_LOGE("Failed to validate event class: ret=%d", ret); + goto end; + } + + if ((validation_output.valid_flags & validation_flags) != + validation_flags) { + /* Invalid event class */ + BT_LOGW("Invalid trace, stream class, or event class: " + "valid-flags=0x%x", + validation_output.valid_flags); + ret = -1; + goto end; + } + } + + /* Only set an event ID if none was explicitly set before */ + *event_id = bt_ctf_event_class_common_get_id(event_class); + if (*event_id < 0) { + BT_LOGV("Event class has no ID: automatically setting it: " + "id=%" PRId64, stream_class->next_event_id); + + if (bt_ctf_event_class_common_set_id(event_class, + stream_class->next_event_id)) { + BT_LOGE("Cannot set event class's ID: id=%" PRId64, + stream_class->next_event_id); + ret = -1; + goto end; + } + stream_class->next_event_id++; + *event_id = stream_class->next_event_id; + } + + bt_ctf_object_set_parent(&event_class->base, &stream_class->base); + + if (trace) { + /* + * At this point we know that the function will be + * successful. Therefore we can replace the event + * class's field types with what's in the validation + * output structure and mark this event class as valid. + */ + bt_ctf_validation_replace_types(NULL, NULL, event_class, + &validation_output, validation_flags); + event_class->valid = 1; + + /* + * Put what was not moved in + * bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&validation_output); + } + + /* Add to the event classes of the stream class */ + g_ptr_array_add(stream_class->event_classes, event_class); + g_hash_table_insert(stream_class->event_classes_ht, event_id, + event_class); + event_id = NULL; + + /* Freeze the event class */ + bt_ctf_event_class_common_freeze(event_class); + + /* + * It is safe to set the stream class's unique clock class + * now if the stream class is frozen. + */ + if (stream_class->frozen && expected_clock_class) { + BT_ASSERT(!stream_class->clock_class || + stream_class->clock_class == expected_clock_class); + BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class); + } + + BT_LOGD("Added event class to stream class: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", event-class-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64, + stream_class, bt_ctf_stream_class_common_get_name(stream_class), + bt_ctf_stream_class_common_get_id(stream_class), + event_class, + bt_ctf_event_class_common_get_name(event_class), + bt_ctf_event_class_common_get_id(event_class)); + +end: + bt_ctf_validation_output_put_types(&validation_output); + bt_ctf_object_put_ref(expected_clock_class); + g_free(event_id); + return ret; +} + +static +int64_t get_event_class_count(void *element) +{ + return bt_ctf_stream_class_get_event_class_count( + (struct bt_ctf_stream_class *) element); +} + +static +void *get_event_class(void *element, int i) +{ + return bt_ctf_stream_class_get_event_class_by_index( + (struct bt_ctf_stream_class *) element, i); +} + +static +int visit_event_class(void *object, bt_ctf_visitor visitor,void *data) +{ + struct bt_ctf_visitor_object obj = { + .object = object, + .type = BT_CTF_VISITOR_OBJECT_TYPE_EVENT_CLASS + }; + + return visitor(&obj, data); +} + +BT_HIDDEN +int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class, + bt_ctf_visitor visitor, void *data) +{ + int ret; + struct bt_ctf_visitor_object obj = { + .object = stream_class, + .type = BT_CTF_VISITOR_OBJECT_TYPE_STREAM_CLASS + }; + + if (!stream_class || !visitor) { + BT_LOGW("Invalid parameter: stream class or visitor is NULL: " + "stream-class-addr=%p, visitor=%p", + stream_class, visitor); + ret = -1; + goto end; + } + + ret = bt_ctf_visitor_helper(&obj, get_event_class_count, + get_event_class, + visit_event_class, visitor, data); + BT_LOGV("bt_ctf_visitor_helper() returned: ret=%d", ret); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class, + bt_ctf_visitor visitor, void *data) +{ + return bt_ctf_stream_class_common_visit(BT_CTF_FROM_COMMON(stream_class), + visitor, data); +} + +BT_HIDDEN +void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class) +{ + if (!stream_class || stream_class->frozen) { + return; + } + + BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64, + stream_class, bt_ctf_stream_class_common_get_name(stream_class), + bt_ctf_stream_class_common_get_id(stream_class)); + stream_class->frozen = 1; + bt_ctf_field_type_common_freeze(stream_class->event_header_field_type); + bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type); + bt_ctf_field_type_common_freeze(stream_class->event_context_field_type); + bt_ctf_clock_class_freeze(stream_class->clock_class); +} + +BT_HIDDEN +int bt_ctf_stream_class_common_validate_single_clock_class( + struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_clock_class **expected_clock_class) +{ + int ret; + uint64_t i; + + BT_ASSERT(stream_class); + BT_ASSERT(expected_clock_class); + ret = bt_ctf_field_type_common_validate_single_clock_class( + stream_class->packet_context_field_type, + expected_clock_class); + if (ret) { + BT_LOGW("Stream class's packet context field type " + "is not recursively mapped to the " + "expected clock class: " + "stream-class-addr=%p, " + "stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", " + "ft-addr=%p", + stream_class, + bt_ctf_stream_class_common_get_name(stream_class), + stream_class->id, + stream_class->packet_context_field_type); + goto end; + } + + ret = bt_ctf_field_type_common_validate_single_clock_class( + stream_class->event_header_field_type, + expected_clock_class); + if (ret) { + BT_LOGW("Stream class's event header field type " + "is not recursively mapped to the " + "expected clock class: " + "stream-class-addr=%p, " + "stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", " + "ft-addr=%p", + stream_class, + bt_ctf_stream_class_common_get_name(stream_class), + stream_class->id, + stream_class->event_header_field_type); + goto end; + } + + ret = bt_ctf_field_type_common_validate_single_clock_class( + stream_class->event_context_field_type, + expected_clock_class); + if (ret) { + BT_LOGW("Stream class's event context field type " + "is not recursively mapped to the " + "expected clock class: " + "stream-class-addr=%p, " + "stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", " + "ft-addr=%p", + stream_class, + bt_ctf_stream_class_common_get_name(stream_class), + stream_class->id, + stream_class->event_context_field_type); + goto end; + } + + for (i = 0; i < stream_class->event_classes->len; i++) { + struct bt_ctf_event_class_common *event_class = + g_ptr_array_index(stream_class->event_classes, i); + + BT_ASSERT(event_class); + ret = bt_ctf_event_class_common_validate_single_clock_class( + event_class, expected_clock_class); + if (ret) { + BT_LOGW("Stream class's event class contains a " + "field type which is not recursively mapped to " + "the expected clock class: " + "stream-class-addr=%p, " + "stream-class-name=\"%s\", " + "stream-class-id=%" PRId64, + stream_class, + bt_ctf_stream_class_common_get_name(stream_class), + stream_class->id); + goto end; + } + } + +end: + return ret; +} + +static +int init_event_header(struct bt_ctf_stream_class *stream_class) +{ + int ret = 0; + struct bt_ctf_field_type *event_header_type = + bt_ctf_field_type_structure_create(); + struct bt_ctf_field_type *_uint32_t = + get_field_type(FIELD_TYPE_ALIAS_UINT32_T); + struct bt_ctf_field_type *_uint64_t = + get_field_type(FIELD_TYPE_ALIAS_UINT64_T); + + if (!event_header_type) { + BT_LOGE_STR("Cannot create empty structure field type."); + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(event_header_type, + _uint32_t, "id"); + if (ret) { + BT_LOGE_STR("Cannot add `id` field to event header field type."); + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(event_header_type, + _uint64_t, "timestamp"); + if (ret) { + BT_LOGE_STR("Cannot add `timestamp` field to event header field type."); + goto end; + } + + bt_ctf_object_put_ref(stream_class->common.event_header_field_type); + stream_class->common.event_header_field_type = + (void *) event_header_type; + event_header_type = NULL; + +end: + if (ret) { + bt_ctf_object_put_ref(event_header_type); + } + + bt_ctf_object_put_ref(_uint32_t); + bt_ctf_object_put_ref(_uint64_t); + return ret; +} + +static +int init_packet_context(struct bt_ctf_stream_class *stream_class) +{ + int ret = 0; + struct bt_ctf_field_type *packet_context_type = + bt_ctf_field_type_structure_create(); + struct bt_ctf_field_type *_uint64_t = + get_field_type(FIELD_TYPE_ALIAS_UINT64_T); + struct bt_ctf_field_type *ts_begin_end_uint64_t; + + if (!packet_context_type) { + BT_LOGE_STR("Cannot create empty structure field type."); + ret = -1; + goto end; + } + + ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t); + if (!ts_begin_end_uint64_t) { + BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields."); + ret = -1; + goto end; + } + + /* + * We create a stream packet context as proposed in the CTF + * specification. + */ + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + ts_begin_end_uint64_t, "timestamp_begin"); + if (ret) { + BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type."); + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + ts_begin_end_uint64_t, "timestamp_end"); + if (ret) { + BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type."); + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "content_size"); + if (ret) { + BT_LOGE_STR("Cannot add `content_size` field to event header field type."); + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "packet_size"); + if (ret) { + BT_LOGE_STR("Cannot add `packet_size` field to event header field type."); + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(packet_context_type, + _uint64_t, "events_discarded"); + if (ret) { + BT_LOGE_STR("Cannot add `events_discarded` field to event header field type."); + goto end; + } + + bt_ctf_object_put_ref(stream_class->common.packet_context_field_type); + stream_class->common.packet_context_field_type = + (void *) packet_context_type; + packet_context_type = NULL; + +end: + if (ret) { + bt_ctf_object_put_ref(packet_context_type); + goto end; + } + + bt_ctf_object_put_ref(_uint64_t); + bt_ctf_object_put_ref(ts_begin_end_uint64_t); + return ret; +} + +static +void bt_ctf_stream_class_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_stream_class *stream_class; + + stream_class = (void *) obj; + BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64, + stream_class, bt_ctf_stream_class_get_name(stream_class), + bt_ctf_stream_class_get_id(stream_class)); + bt_ctf_stream_class_common_finalize(BT_CTF_TO_COMMON(stream_class)); + bt_ctf_object_put_ref(stream_class->clock); + g_free(stream_class); +} + +struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name) +{ + struct bt_ctf_stream_class *stream_class; + int ret; + + BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name); + stream_class = g_new0(struct bt_ctf_stream_class, 1); + if (!stream_class) { + BT_LOGE_STR("Failed to allocate one CTF writer stream class."); + goto error; + } + + ret = bt_ctf_stream_class_common_initialize(BT_CTF_TO_COMMON(stream_class), + name, bt_ctf_stream_class_destroy); + if (ret) { + /* bt_ctf_stream_class_common_initialize() logs errors */ + goto error; + } + + ret = init_event_header(stream_class); + if (ret) { + BT_LOGE_STR("Cannot initialize stream class's event header field type."); + goto error; + } + + ret = init_packet_context(stream_class); + if (ret) { + BT_LOGE_STR("Cannot initialize stream class's packet context field type."); + goto error; + } + + BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"", + stream_class, name); + return stream_class; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_class); + return stream_class; +} + +static +int try_map_clock_class(struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *parent_ft, const char *field_name) +{ + struct bt_ctf_clock_class *mapped_clock_class = NULL; + int ret = 0; + struct bt_ctf_field_type *ft = + bt_ctf_field_type_structure_get_field_type_by_name(parent_ft, + field_name); + + BT_ASSERT(stream_class->clock); + + if (!ft) { + /* Field does not exist: not an error */ + goto end; + } + + BT_ASSERT(((struct bt_ctf_field_type_common *) ft)->id == + BT_CTF_FIELD_TYPE_ID_INTEGER); + mapped_clock_class = + bt_ctf_field_type_integer_get_mapped_clock_class(ft); + if (!mapped_clock_class) { + struct bt_ctf_field_type *ft_copy; + + if (!stream_class->clock) { + BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", ft-addr=%p", + stream_class, + bt_ctf_stream_class_get_name(stream_class), + bt_ctf_stream_class_get_id(stream_class), ft); + ret = -1; + goto end; + } + + ft_copy = bt_ctf_field_type_copy(ft); + if (!ft_copy) { + BT_LOGE("Failed to copy integer field type: ft-addr=%p", + ft); + } + + ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen( + (void *) ft_copy, stream_class->clock->clock_class); + BT_ASSERT(ret == 0); + + ret = bt_ctf_field_type_common_structure_replace_field( + (void *) parent_ft, field_name, (void *) ft_copy); + bt_ctf_object_put_ref(ft_copy); + BT_LOGV("Automatically mapped field type to stream class's clock class: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", ft-addr=%p, " + "ft-copy-addr=%p", + stream_class, + bt_ctf_stream_class_get_name(stream_class), + bt_ctf_stream_class_get_id(stream_class), ft, ft_copy); + } + +end: + bt_ctf_object_put_ref(ft); + bt_ctf_object_put_ref(mapped_clock_class); + return ret; +} + +BT_HIDDEN +int bt_ctf_stream_class_map_clock_class( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *packet_context_type, + struct bt_ctf_field_type *event_header_type) +{ + int ret = 0; + + BT_ASSERT(stream_class); + + if (!stream_class->clock) { + /* No clock class to map to */ + goto end; + } + + if (packet_context_type) { + if (try_map_clock_class(stream_class, packet_context_type, + "timestamp_begin")) { + BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class."); + ret = -1; + goto end; + } + + if (try_map_clock_class(stream_class, packet_context_type, + "timestamp_end")) { + BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class."); + ret = -1; + goto end; + } + } + + if (event_header_type) { + if (try_map_clock_class(stream_class, event_header_type, + "timestamp")) { + BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class."); + ret = -1; + goto end; + } + } + +end: + return ret; +} + +struct bt_ctf_clock *bt_ctf_stream_class_get_clock( + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_clock *clock = NULL; + + if (!stream_class) { + BT_LOGW_STR("Invalid parameter: stream class is NULL."); + goto end; + } + + if (!stream_class->clock) { + BT_LOGV("Stream class has no clock: " + "addr=%p, name=\"%s\", id=%" PRId64, + stream_class, + bt_ctf_stream_class_get_name(stream_class), + bt_ctf_stream_class_get_id(stream_class)); + goto end; + } + + clock = bt_ctf_object_get_ref(stream_class->clock); + +end: + return clock; +} + +int bt_ctf_stream_class_set_clock( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_clock *clock) +{ + int ret = 0; + + if (!stream_class || !clock) { + BT_LOGW("Invalid parameter: stream class or clock is NULL: " + "stream-class-addr=%p, clock-addr=%p", + stream_class, clock); + ret = -1; + goto end; + } + + if (stream_class->common.frozen) { + BT_LOGW("Invalid parameter: stream class is frozen: " + "addr=%p, name=\"%s\", id=%" PRId64, + stream_class, + bt_ctf_stream_class_get_name(stream_class), + bt_ctf_stream_class_get_id(stream_class)); + ret = -1; + goto end; + } + + /* Replace the current clock of this stream class. */ + bt_ctf_object_put_ref(stream_class->clock); + stream_class->clock = bt_ctf_object_get_ref(clock); + BT_LOGV("Set stream class's clock: " + "addr=%p, name=\"%s\", id=%" PRId64 ", " + "clock-addr=%p, clock-name=\"%s\"", + stream_class, + bt_ctf_stream_class_get_name(stream_class), + bt_ctf_stream_class_get_id(stream_class), + stream_class->clock, + bt_ctf_clock_get_name(stream_class->clock)); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class, + struct metadata_context *context) +{ + int ret = 0; + size_t i; + struct bt_ctf_trace *trace; + struct bt_ctf_field_type *packet_header_type = NULL; + + BT_LOGD("Serializing stream class's metadata: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-class-id=%" PRId64 ", metadata-context-addr=%p", + stream_class, + bt_ctf_stream_class_get_name(stream_class), + bt_ctf_stream_class_get_id(stream_class), context); + g_string_assign(context->field_name, ""); + context->current_indentation_level = 1; + if (!stream_class->common.id_set) { + BT_LOGW_STR("Stream class's ID is not set."); + ret = -1; + goto end; + } + + g_string_append(context->string, "stream {\n"); + + /* + * The reference to the trace is only borrowed since the + * serialization of the stream class might have been triggered + * by the trace's destruction. In such a case, the trace's + * reference count would, unexepectedly, go through the sequence + * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction + * and serialization. + */ + trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace( + BT_CTF_TO_COMMON(stream_class))); + BT_ASSERT(trace); + packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace); + trace = NULL; + if (packet_header_type) { + struct bt_ctf_field_type *stream_id_type; + + stream_id_type = + bt_ctf_field_type_structure_get_field_type_by_name( + packet_header_type, "stream_id"); + if (stream_id_type) { + /* + * Only set the stream's id if the trace's packet header + * contains a stream_id field. This field is only + * needed if the trace contains only one stream + * class. + */ + g_string_append_printf(context->string, + "\tid = %" PRId64 ";\n", + stream_class->common.id); + } + bt_ctf_object_put_ref(stream_id_type); + } + if (stream_class->common.event_header_field_type) { + BT_LOGD_STR("Serializing stream class's event header field type's metadata."); + g_string_append(context->string, "\tevent.header := "); + ret = bt_ctf_field_type_serialize_recursive( + (void *) stream_class->common.event_header_field_type, + context); + if (ret) { + BT_LOGW("Cannot serialize stream class's event header field type's metadata: " + "ret=%d", ret); + goto end; + } + g_string_append(context->string, ";"); + } + + + if (stream_class->common.packet_context_field_type) { + BT_LOGD_STR("Serializing stream class's packet context field type's metadata."); + g_string_append(context->string, "\n\n\tpacket.context := "); + ret = bt_ctf_field_type_serialize_recursive( + (void *) stream_class->common.packet_context_field_type, + context); + if (ret) { + BT_LOGW("Cannot serialize stream class's packet context field type's metadata: " + "ret=%d", ret); + goto end; + } + g_string_append(context->string, ";"); + } + + if (stream_class->common.event_context_field_type) { + BT_LOGD_STR("Serializing stream class's event context field type's metadata."); + g_string_append(context->string, "\n\n\tevent.context := "); + ret = bt_ctf_field_type_serialize_recursive( + (void *) stream_class->common.event_context_field_type, + context); + if (ret) { + BT_LOGW("Cannot serialize stream class's event context field type's metadata: " + "ret=%d", ret); + goto end; + } + g_string_append(context->string, ";"); + } + + g_string_append(context->string, "\n};\n\n"); + + for (i = 0; i < stream_class->common.event_classes->len; i++) { + struct bt_ctf_event_class *event_class = + stream_class->common.event_classes->pdata[i]; + + ret = bt_ctf_event_class_serialize(event_class, context); + if (ret) { + BT_LOGW("Cannot serialize event class's metadata: " + "event-class-addr=%p, event-class-name=\"%s\", " + "event-class-id=%" PRId64, + event_class, + bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class)); + goto end; + } + } + +end: + bt_ctf_object_put_ref(packet_header_type); + context->current_indentation_level = 0; + return ret; +} + +struct bt_ctf_trace *bt_ctf_stream_class_get_trace( + struct bt_ctf_stream_class *stream_class) +{ + return bt_ctf_object_get_ref(bt_ctf_stream_class_common_borrow_trace( + BT_CTF_TO_COMMON(stream_class))); +} + +const char *bt_ctf_stream_class_get_name( + struct bt_ctf_stream_class *stream_class) +{ + return bt_ctf_stream_class_common_get_name(BT_CTF_TO_COMMON(stream_class)); +} + +int bt_ctf_stream_class_set_name( + struct bt_ctf_stream_class *stream_class, const char *name) +{ + return bt_ctf_stream_class_common_set_name(BT_CTF_TO_COMMON(stream_class), + name); +} + +int64_t bt_ctf_stream_class_get_id( + struct bt_ctf_stream_class *stream_class) +{ + return bt_ctf_stream_class_common_get_id(BT_CTF_TO_COMMON(stream_class)); +} + +int bt_ctf_stream_class_set_id( + struct bt_ctf_stream_class *stream_class, uint64_t id) +{ + return bt_ctf_stream_class_common_set_id(BT_CTF_TO_COMMON(stream_class), id); +} + +struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type( + struct bt_ctf_stream_class *stream_class) +{ + return bt_ctf_object_get_ref( + bt_ctf_stream_class_common_borrow_packet_context_field_type( + BT_CTF_TO_COMMON(stream_class))); +} + +int bt_ctf_stream_class_set_packet_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *packet_context_type) +{ + return bt_ctf_stream_class_common_set_packet_context_field_type( + BT_CTF_TO_COMMON(stream_class), (void *) packet_context_type); +} + +struct bt_ctf_field_type * +bt_ctf_stream_class_get_event_header_type( + struct bt_ctf_stream_class *stream_class) +{ + return bt_ctf_object_get_ref( + bt_ctf_stream_class_common_borrow_event_header_field_type( + BT_CTF_TO_COMMON(stream_class))); +} + +int bt_ctf_stream_class_set_event_header_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_header_type) +{ + return bt_ctf_stream_class_common_set_event_header_field_type( + BT_CTF_TO_COMMON(stream_class), (void *) event_header_type); +} + +struct bt_ctf_field_type * +bt_ctf_stream_class_get_event_context_type( + struct bt_ctf_stream_class *stream_class) +{ + return bt_ctf_object_get_ref( + bt_ctf_stream_class_common_borrow_event_context_field_type( + BT_CTF_TO_COMMON(stream_class))); +} + +int bt_ctf_stream_class_set_event_context_type( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_field_type *event_context_type) +{ + return bt_ctf_stream_class_common_set_event_context_field_type( + BT_CTF_TO_COMMON(stream_class), (void *) event_context_type); +} + +int64_t bt_ctf_stream_class_get_event_class_count( + struct bt_ctf_stream_class *stream_class) +{ + return bt_ctf_stream_class_common_get_event_class_count( + BT_CTF_TO_COMMON(stream_class)); +} + +struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index( + struct bt_ctf_stream_class *stream_class, uint64_t index) +{ + return bt_ctf_object_get_ref( + bt_ctf_stream_class_common_borrow_event_class_by_index( + BT_CTF_TO_COMMON(stream_class), index)); +} + +struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id( + struct bt_ctf_stream_class *stream_class, uint64_t id) +{ + return bt_ctf_object_get_ref( + bt_ctf_stream_class_common_borrow_event_class_by_id( + BT_CTF_TO_COMMON(stream_class), id)); +} + +int bt_ctf_stream_class_add_event_class( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_event_class *event_class) +{ + return bt_ctf_stream_class_common_add_event_class( + BT_CTF_TO_COMMON(stream_class), BT_CTF_TO_COMMON(event_class), + (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy); +} diff --git a/ctf-writer/stream.c b/ctf-writer/stream.c new file mode 100644 index 00000000..fc7557ee --- /dev/null +++ b/ctf-writer/stream.c @@ -0,0 +1,1953 @@ +/* + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2017-2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-STREAM" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BT_HIDDEN +void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream) +{ + BT_LOGD("Finalizing common stream object: addr=%p, name=\"%s\"", + stream, bt_ctf_stream_common_get_name(stream)); + + if (stream->name) { + g_string_free(stream->name, TRUE); + } +} + +BT_HIDDEN +int bt_ctf_stream_common_initialize( + struct bt_ctf_stream_common *stream, + struct bt_ctf_stream_class_common *stream_class, const char *name, + uint64_t id, bt_ctf_object_release_func release_func) +{ + int ret = 0; + struct bt_ctf_trace_common *trace = NULL; + + bt_ctf_object_init_shared_with_parent(&stream->base, release_func); + + if (!stream_class) { + BT_LOGW_STR("Invalid parameter: stream class is NULL."); + goto error; + } + + BT_LOGD("Initializing common stream object: stream-class-addr=%p, " + "stream-class-name=\"%s\", stream-name=\"%s\", " + "stream-id=%" PRIu64, + stream_class, bt_ctf_stream_class_common_get_name(stream_class), + name, id); + trace = bt_ctf_stream_class_common_borrow_trace(stream_class); + if (!trace) { + BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-name=\"%s\"", + stream_class, + bt_ctf_stream_class_common_get_name(stream_class), name); + goto error; + } + + if (id != -1ULL) { + /* + * Validate that the given ID is unique amongst all the + * existing trace's streams created from the same stream + * class. + */ + size_t i; + + for (i = 0; i < trace->streams->len; i++) { + struct bt_ctf_stream_common *trace_stream = + g_ptr_array_index(trace->streams, i); + + if (trace_stream->stream_class != (void *) stream_class) { + continue; + } + + if (trace_stream->id == id) { + BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID."); + goto error; + } + } + } + + /* + * Acquire reference to parent since stream will become publicly + * reachable; it needs its parent to remain valid. + */ + bt_ctf_object_set_parent(&stream->base, &trace->base); + stream->stream_class = stream_class; + stream->id = (int64_t) id; + + if (name) { + stream->name = g_string_new(name); + if (!stream->name) { + BT_LOGE_STR("Failed to allocate a GString."); + goto error; + } + } + + BT_LOGD("Set common stream's trace parent: trace-addr=%p", trace); + + /* Add this stream to the trace's streams */ + BT_LOGD("Created common stream object: addr=%p", stream); + goto end; + +error: + ret = -1; + +end: + return ret; +} + +static +void bt_ctf_stream_destroy(struct bt_ctf_object *obj); + +static +int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t); + +static +int set_integer_field_value(struct bt_ctf_field* field, uint64_t value) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + + if (!field) { + BT_LOGW_STR("Invalid parameter: field is NULL."); + ret = -1; + goto end; + } + + field_type = bt_ctf_field_get_type(field); + BT_ASSERT(field_type); + + if (bt_ctf_field_type_get_type_id(field_type) != + BT_CTF_FIELD_TYPE_ID_INTEGER) { + /* Not an integer and the value is unset, error. */ + BT_LOGW("Invalid parameter: field's type is not an integer field type: " + "field-addr=%p, ft-addr=%p, ft-id=%s", + field, field_type, + bt_ctf_field_type_id_string((int) + bt_ctf_field_type_get_type_id(field_type))); + ret = -1; + goto end; + } + + if (bt_ctf_field_type_integer_is_signed(field_type)) { + ret = bt_ctf_field_integer_signed_set_value(field, (int64_t) value); + if (ret) { + /* Value is out of range, error. */ + BT_LOGW("Cannot set signed integer field's value: " + "addr=%p, value=%" PRId64, + field, (int64_t) value); + goto end; + } + } else { + ret = bt_ctf_field_integer_unsigned_set_value(field, value); + if (ret) { + /* Value is out of range, error. */ + BT_LOGW("Cannot set unsigned integer field's value: " + "addr=%p, value=%" PRIu64, + field, value); + goto end; + } + } +end: + bt_ctf_object_put_ref(field_type); + return ret; +} + +static +int set_packet_header_magic(struct bt_ctf_stream *stream) +{ + int ret = 0; + struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field_by_name( + stream->packet_header, "magic"); + const uint32_t magic_value = 0xc1fc1fc1; + + BT_ASSERT(stream); + + if (!magic_field) { + /* No magic field found. Not an error, skip. */ + BT_LOGV("No field named `magic` in packet header: skipping: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + ret = bt_ctf_field_integer_unsigned_set_value(magic_field, + (uint64_t) magic_value); + + if (ret) { + BT_LOGW("Cannot set packet header field's `magic` integer field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + magic_field, (uint64_t) magic_value); + } else { + BT_LOGV("Set packet header field's `magic` field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + magic_field, (uint64_t) magic_value); + } +end: + bt_ctf_object_put_ref(magic_field); + return ret; +} + +static +int set_packet_header_uuid(struct bt_ctf_stream *stream) +{ + int ret = 0; + int64_t i; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field_by_name( + stream->packet_header, "uuid"); + + BT_ASSERT(stream); + + if (!uuid_field) { + /* No uuid field found. Not an error, skip. */ + BT_LOGV("No field named `uuid` in packet header: skipping: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + trace = (struct bt_ctf_trace *) + bt_ctf_object_get_parent(&stream->common.base); + + for (i = 0; i < 16; i++) { + struct bt_ctf_field *uuid_element = + bt_ctf_field_array_get_field(uuid_field, i); + + ret = bt_ctf_field_integer_unsigned_set_value( + uuid_element, (uint64_t) trace->common.uuid[i]); + bt_ctf_object_put_ref(uuid_element); + if (ret) { + BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, " + "value=%" PRIu64 ", index=%" PRId64, + stream, bt_ctf_stream_get_name(stream), + uuid_element, (uint64_t) trace->common.uuid[i], i); + goto end; + } + } + + BT_LOGV("Set packet header field's `uuid` field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p", + stream, bt_ctf_stream_get_name(stream), uuid_field); + +end: + bt_ctf_object_put_ref(uuid_field); + BT_CTF_OBJECT_PUT_REF_AND_RESET(trace); + return ret; +} +static +int set_packet_header_stream_id(struct bt_ctf_stream *stream) +{ + int ret = 0; + uint32_t stream_id; + struct bt_ctf_field *stream_id_field = + bt_ctf_field_structure_get_field_by_name( + stream->packet_header, "stream_id"); + + if (!stream_id_field) { + /* No stream_id field found. Not an error, skip. */ + BT_LOGV("No field named `stream_id` in packet header: skipping: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + stream_id = stream->common.stream_class->id; + ret = bt_ctf_field_integer_unsigned_set_value(stream_id_field, + (uint64_t) stream_id); + if (ret) { + BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + stream_id_field, (uint64_t) stream_id); + } else { + BT_LOGV("Set packet header field's `stream_id` field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + stream_id_field, (uint64_t) stream_id); + } + +end: + bt_ctf_object_put_ref(stream_id_field); + return ret; +} + +static +int auto_populate_packet_header(struct bt_ctf_stream *stream) +{ + int ret = 0; + + if (!stream->packet_header) { + goto end; + } + + ret = set_packet_header_magic(stream); + if (ret) { + BT_LOGW("Cannot set packet header's magic number field: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + ret = set_packet_header_uuid(stream); + if (ret) { + BT_LOGW("Cannot set packet header's UUID field: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + ret = set_packet_header_stream_id(stream); + if (ret) { + BT_LOGW("Cannot set packet header's stream class ID field: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + BT_LOGV("Automatically populated stream's packet header's known fields: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + +end: + return ret; +} + +static +int set_packet_context_packet_size(struct bt_ctf_stream *stream, + uint64_t packet_size_bits) +{ + int ret = 0; + struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "packet_size"); + + ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits); + if (ret) { + BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + field, packet_size_bits); + } else { + BT_LOGV("Set packet context field's `packet_size` field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + field, packet_size_bits); + } + + bt_ctf_object_put_ref(field); + return ret; +} + +static +int set_packet_context_content_size(struct bt_ctf_stream *stream, + uint64_t content_size_bits) +{ + int ret = 0; + struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "content_size"); + + BT_ASSERT(stream); + + if (!field) { + /* No content size field found. Not an error, skip. */ + BT_LOGV("No field named `content_size` in packet context: skipping: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits); + if (ret) { + BT_LOGW("Cannot set packet context field's `content_size` integer field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + field, content_size_bits); + } else { + BT_LOGV("Set packet context field's `content_size` field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + field, content_size_bits); + } + +end: + bt_ctf_object_put_ref(field); + return ret; +} + +static +int set_packet_context_events_discarded(struct bt_ctf_stream *stream) +{ + int ret = 0; + struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "events_discarded"); + + BT_ASSERT(stream); + + if (!field) { + /* No discarded events count field found. Not an error, skip. */ + BT_LOGV("No field named `events_discarded` in packet context: skipping: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + /* + * If the field is set by the user, make sure that the value is + * greater than or equal to the stream's current count of + * discarded events. We do not allow wrapping here. If it's + * valid, update the stream's current count. + */ + if (bt_ctf_field_is_set_recursive(field)) { + uint64_t user_val; + + ret = bt_ctf_field_integer_unsigned_get_value(field, + &user_val); + if (ret) { + BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p", + stream, bt_ctf_stream_get_name(stream), field); + goto end; + } + + if (user_val < stream->discarded_events) { + BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: " + "value is lesser than the stream's current discarded events count: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, " + "value=%" PRIu64 ", " + "stream-discarded-events-count=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), field, + user_val, stream->discarded_events); + goto end; + } + + stream->discarded_events = user_val; + } else { + ret = bt_ctf_field_integer_unsigned_set_value(field, + stream->discarded_events); + if (ret) { + BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + field, stream->discarded_events); + } else { + BT_LOGV("Set packet context field's `events_discarded` field's value: " + "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + field, stream->discarded_events); + } + } + +end: + bt_ctf_object_put_ref(field); + return ret; +} + +static +void update_clock_value(uint64_t *val, uint64_t new_val, + unsigned int new_val_size) +{ + const uint64_t pow2 = 1ULL << new_val_size; + const uint64_t mask = pow2 - 1; + uint64_t val_masked; + +#ifdef BT_LOG_ENABLED_VERBOSE + uint64_t old_val = *val; +#endif + + if (new_val_size == 64) { + *val = new_val; + goto end; + } + + val_masked = *val & mask; + + if (new_val < val_masked) { + /* Wrapped once */ + new_val |= pow2; + } + + *val &= ~mask; + *val |= new_val; + +end: + BT_LOGV("Updated clock value: old-val=%" PRIu64 ", new-val=%" PRIu64, + old_val, *val); + return; +} + +static +int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val) +{ + int ret = 0; + struct bt_ctf_field_common *field_common = (void *) field; + + if (!field) { + goto end; + } + + switch (bt_ctf_field_get_type_id(field)) { + case BT_CTF_FIELD_TYPE_ID_INTEGER: + { + struct bt_ctf_clock_class *cc = + bt_ctf_field_type_integer_get_mapped_clock_class( + (void *) field_common->type); + int val_size; + uint64_t uval; + + if (!cc) { + goto end; + } + + bt_ctf_object_put_ref(cc); + val_size = bt_ctf_field_type_integer_get_size( + (void *) field_common->type); + BT_ASSERT(val_size >= 1); + + if (bt_ctf_field_type_integer_is_signed( + (void *) field_common->type)) { + int64_t ival; + + ret = bt_ctf_field_integer_signed_get_value(field, &ival); + uval = (uint64_t) ival; + } else { + ret = bt_ctf_field_integer_unsigned_get_value(field, &uval); + } + + if (ret) { + /* Not set */ + goto end; + } + + update_clock_value(val, uval, val_size); + break; + } + case BT_CTF_FIELD_TYPE_ID_ENUM: + { + struct bt_ctf_field *int_field = + bt_ctf_field_enumeration_get_container(field); + + BT_ASSERT(int_field); + ret = visit_field_update_clock_value(int_field, val); + bt_ctf_object_put_ref(int_field); + break; + } + case BT_CTF_FIELD_TYPE_ID_ARRAY: + { + uint64_t i; + int64_t len = bt_ctf_field_type_array_get_length( + (void *) field_common->type); + + BT_ASSERT(len >= 0); + + for (i = 0; i < len; i++) { + struct bt_ctf_field *elem_field = + bt_ctf_field_array_get_field(field, i); + + BT_ASSERT(elem_field); + ret = visit_field_update_clock_value(elem_field, val); + bt_ctf_object_put_ref(elem_field); + if (ret) { + goto end; + } + } + break; + } + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + { + uint64_t i; + int64_t len = bt_ctf_field_common_sequence_get_length( + (void *) field); + + if (len < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < len; i++) { + struct bt_ctf_field *elem_field = + bt_ctf_field_sequence_get_field(field, i); + + BT_ASSERT(elem_field); + ret = visit_field_update_clock_value(elem_field, val); + bt_ctf_object_put_ref(elem_field); + if (ret) { + goto end; + } + } + break; + } + case BT_CTF_FIELD_TYPE_ID_STRUCT: + { + uint64_t i; + int64_t len = bt_ctf_field_type_structure_get_field_count( + (void *) field_common->type); + + BT_ASSERT(len >= 0); + + for (i = 0; i < len; i++) { + struct bt_ctf_field *member_field = + bt_ctf_field_structure_get_field_by_index(field, i); + + BT_ASSERT(member_field); + ret = visit_field_update_clock_value(member_field, val); + bt_ctf_object_put_ref(member_field); + if (ret) { + goto end; + } + } + break; + } + case BT_CTF_FIELD_TYPE_ID_VARIANT: + { + struct bt_ctf_field *cur_field = + bt_ctf_field_variant_get_current_field(field); + + if (!cur_field) { + ret = -1; + goto end; + } + + ret = visit_field_update_clock_value(cur_field, val); + bt_ctf_object_put_ref(cur_field); + break; + } + default: + break; + } + +end: + return ret; +} + +int visit_event_update_clock_value(struct bt_ctf_event *event, uint64_t *val) +{ + int ret = 0; + struct bt_ctf_field *field; + + field = bt_ctf_event_get_header(event); + ret = visit_field_update_clock_value(field, val); + bt_ctf_object_put_ref(field); + if (ret) { + BT_LOGW_STR("Cannot automatically update clock value in " + "event's header."); + goto end; + } + + field = bt_ctf_event_get_stream_event_context(event); + ret = visit_field_update_clock_value(field, val); + bt_ctf_object_put_ref(field); + if (ret) { + BT_LOGW_STR("Cannot automatically update clock value in " + "event's stream event context."); + goto end; + } + + field = bt_ctf_event_get_context(event); + ret = visit_field_update_clock_value(field, val); + bt_ctf_object_put_ref(field); + if (ret) { + BT_LOGW_STR("Cannot automatically update clock value in " + "event's context."); + goto end; + } + + field = bt_ctf_event_get_payload_field(event); + ret = visit_field_update_clock_value(field, val); + bt_ctf_object_put_ref(field); + if (ret) { + BT_LOGW_STR("Cannot automatically update clock value in " + "event's payload."); + goto end; + } + +end: + return ret; +} + +static +int set_packet_context_timestamps(struct bt_ctf_stream *stream) +{ + int ret = 0; + uint64_t val; + uint64_t cur_clock_value; + uint64_t init_clock_value = 0; + struct bt_ctf_field *ts_begin_field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "timestamp_begin"); + struct bt_ctf_field *ts_end_field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "timestamp_end"); + struct bt_ctf_field_common *packet_context = + (void *) stream->packet_context; + uint64_t i; + int64_t len; + + if (ts_begin_field && bt_ctf_field_is_set_recursive(ts_begin_field)) { + /* Use provided `timestamp_begin` value as starting value */ + ret = bt_ctf_field_integer_unsigned_get_value(ts_begin_field, &val); + BT_ASSERT(ret == 0); + init_clock_value = val; + } else if (stream->last_ts_end != -1ULL) { + /* Use last packet's ending timestamp as starting value */ + init_clock_value = stream->last_ts_end; + } + + cur_clock_value = init_clock_value; + + if (stream->last_ts_end != -1ULL && + cur_clock_value < stream->last_ts_end) { + BT_LOGW("Packet's initial timestamp is less than previous " + "packet's final timestamp: " + "stream-addr=%p, stream-name=\"%s\", " + "cur-packet-ts-begin=%" PRIu64 ", " + "prev-packet-ts-end=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + cur_clock_value, stream->last_ts_end); + ret = -1; + goto end; + } + + /* + * Visit all the packet context fields, followed by all the + * fields of all the events, in order, updating our current + * clock value as we visit. + * + * While visiting the packet context fields, do not consider + * `timestamp_begin` and `timestamp_end` because this function's + * purpose is to set them anyway. Also do not consider + * `packet_size`, `content_size`, `events_discarded`, and + * `packet_seq_num` if they are not set because those are + * autopopulating fields. + */ + len = bt_ctf_field_type_structure_get_field_count( + (void *) packet_context->type); + BT_ASSERT(len >= 0); + + for (i = 0; i < len; i++) { + const char *member_name; + struct bt_ctf_field *member_field; + + ret = bt_ctf_field_type_structure_get_field_by_index( + (void *) packet_context->type, &member_name, NULL, i); + BT_ASSERT(ret == 0); + + if (strcmp(member_name, "timestamp_begin") == 0 || + strcmp(member_name, "timestamp_end") == 0) { + continue; + } + + member_field = bt_ctf_field_structure_get_field_by_index( + stream->packet_context, i); + BT_ASSERT(member_field); + + if (strcmp(member_name, "packet_size") == 0 && + !bt_ctf_field_is_set_recursive(member_field)) { + bt_ctf_object_put_ref(member_field); + continue; + } + + if (strcmp(member_name, "content_size") == 0 && + !bt_ctf_field_is_set_recursive(member_field)) { + bt_ctf_object_put_ref(member_field); + continue; + } + + if (strcmp(member_name, "events_discarded") == 0 && + !bt_ctf_field_is_set_recursive(member_field)) { + bt_ctf_object_put_ref(member_field); + continue; + } + + if (strcmp(member_name, "packet_seq_num") == 0 && + !bt_ctf_field_is_set_recursive(member_field)) { + bt_ctf_object_put_ref(member_field); + continue; + } + + ret = visit_field_update_clock_value(member_field, + &cur_clock_value); + bt_ctf_object_put_ref(member_field); + if (ret) { + BT_LOGW("Cannot automatically update clock value " + "in stream's packet context: " + "stream-addr=%p, stream-name=\"%s\", " + "field-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream), + member_name); + goto end; + } + } + + for (i = 0; i < stream->events->len; i++) { + struct bt_ctf_event *event = g_ptr_array_index(stream->events, i); + + BT_ASSERT(event); + ret = visit_event_update_clock_value(event, &cur_clock_value); + if (ret) { + BT_LOGW("Cannot automatically update clock value " + "in stream's packet context: " + "stream-addr=%p, stream-name=\"%s\", " + "index=%" PRIu64 ", event-addr=%p, " + "event-class-id=%" PRId64 ", " + "event-class-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream), + i, event, + bt_ctf_event_class_common_get_id(event->common.class), + bt_ctf_event_class_common_get_name(event->common.class)); + goto end; + } + } + + /* + * Everything is visited, thus the current clock value + * corresponds to the ending timestamp. Validate this value + * against the provided value of `timestamp_end`, if any, + * otherwise set it. + */ + if (ts_end_field && bt_ctf_field_is_set_recursive(ts_end_field)) { + ret = bt_ctf_field_integer_unsigned_get_value(ts_end_field, &val); + BT_ASSERT(ret == 0); + + if (val < cur_clock_value) { + BT_LOGW("Packet's final timestamp is less than " + "computed packet's final timestamp: " + "stream-addr=%p, stream-name=\"%s\", " + "cur-packet-ts-end=%" PRIu64 ", " + "computed-packet-ts-end=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), + val, cur_clock_value); + ret = -1; + goto end; + } + + stream->last_ts_end = val; + } + + if (ts_end_field && !bt_ctf_field_is_set_recursive(ts_end_field)) { + ret = set_integer_field_value(ts_end_field, cur_clock_value); + BT_ASSERT(ret == 0); + stream->last_ts_end = cur_clock_value; + } + + if (!ts_end_field) { + stream->last_ts_end = cur_clock_value; + } + + /* Set `timestamp_begin` field to initial clock value */ + if (ts_begin_field && !bt_ctf_field_is_set_recursive(ts_begin_field)) { + ret = set_integer_field_value(ts_begin_field, init_clock_value); + BT_ASSERT(ret == 0); + } + +end: + bt_ctf_object_put_ref(ts_begin_field); + bt_ctf_object_put_ref(ts_end_field); + return ret; +} + +static +int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts, + uint64_t packet_size_bits, uint64_t content_size_bits) +{ + int ret = 0; + + if (!stream->packet_context) { + goto end; + } + + ret = set_packet_context_packet_size(stream, packet_size_bits); + if (ret) { + BT_LOGW("Cannot set packet context's packet size field: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + ret = set_packet_context_content_size(stream, content_size_bits); + if (ret) { + BT_LOGW("Cannot set packet context's content size field: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + if (set_ts) { + ret = set_packet_context_timestamps(stream); + if (ret) { + BT_LOGW("Cannot set packet context's timestamp fields: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + } + + ret = set_packet_context_events_discarded(stream); + if (ret) { + BT_LOGW("Cannot set packet context's discarded events count field: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + goto end; + } + + BT_LOGV("Automatically populated stream's packet context's known fields: " + "stream-addr=%p, stream-name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + +end: + return ret; +} + +static +void release_event(struct bt_ctf_event *event) +{ + if (bt_ctf_object_get_ref_count(&event->common.base)) { + /* + * The event is being orphaned, but it must guarantee the + * existence of its event class for the duration of its + * lifetime. + */ + bt_ctf_object_get_ref(event->common.class); + BT_CTF_OBJECT_PUT_REF_AND_RESET(event->common.base.parent); + } else { + bt_ctf_object_try_spec_release(&event->common.base); + } +} + +static +int create_stream_file(struct bt_ctf_writer *writer, + struct bt_ctf_stream *stream) +{ + int ret = 0; + GString *filename = g_string_new(NULL); + int64_t stream_class_id; + char *file_path = NULL; + + BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, " + "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"", + writer, stream, bt_ctf_stream_get_name(stream), + stream->common.stream_class, + stream->common.stream_class->name->str); + + if (stream->common.name && stream->common.name->len > 0) { + /* Use stream name's base name as prefix */ + gchar *basename = g_path_get_basename(stream->common.name->str); + + BT_ASSERT(basename); + + if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) { + g_string_assign(filename, "stream"); + } else { + g_string_assign(filename, basename); + } + + g_free(basename); + goto append_ids; + } + + if (stream->common.stream_class->name && + stream->common.stream_class->name->len > 0) { + /* Use stream class name's base name as prefix */ + gchar *basename = + g_path_get_basename( + stream->common.stream_class->name->str); + + BT_ASSERT(basename); + + if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) { + g_string_assign(filename, "stream"); + } else { + g_string_assign(filename, basename); + } + + g_free(basename); + goto append_ids; + } + + /* Default to using `stream-` as prefix */ + g_string_assign(filename, "stream"); + +append_ids: + stream_class_id = bt_ctf_stream_class_common_get_id(stream->common.stream_class); + BT_ASSERT(stream_class_id >= 0); + BT_ASSERT(stream->common.id >= 0); + g_string_append_printf(filename, "-%" PRId64 "-%" PRId64, + stream_class_id, stream->common.id); + + file_path = g_build_filename(writer->path->str, filename->str, NULL); + if (file_path == NULL) { + ret = -1; + goto end; + } + + ret = bt_ctfser_init(&stream->ctfser, file_path); + g_free(file_path); + if (ret) { + /* bt_ctfser_init() logs errors */ + goto end; + } + + BT_LOGD("Created stream file for writing: " + "stream-addr=%p, stream-name=\"%s\", " + "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream), + filename->str); + +end: + g_string_free(filename, TRUE); + return ret; +} + +BT_HIDDEN +struct bt_ctf_stream *bt_ctf_stream_create_with_id( + struct bt_ctf_stream_class *stream_class, + const char *name, uint64_t id) +{ + int ret; + int fd; + struct bt_ctf_stream *stream = NULL; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_writer *writer = NULL; + + BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, " + "stream-class-name=\"%s\", stream-name=\"%s\", " + "stream-id=%" PRIu64, + stream_class, bt_ctf_stream_class_get_name(stream_class), + name, id); + stream = g_new0(struct bt_ctf_stream, 1); + if (!stream) { + BT_LOGE_STR("Failed to allocate one stream."); + goto error; + } + + if (id == -1ULL) { + id = stream_class->next_stream_id; + } + + ret = bt_ctf_stream_common_initialize(BT_CTF_TO_COMMON(stream), + BT_CTF_TO_COMMON(stream_class), name, id, bt_ctf_stream_destroy); + if (ret) { + /* bt_ctf_stream_common_initialize() logs errors */ + goto error; + } + + trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace( + BT_CTF_TO_COMMON(stream_class))); + if (!trace) { + BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-name=\"%s\"", + stream_class, bt_ctf_stream_class_get_name(stream_class), + name); + goto error; + } + + writer = (struct bt_ctf_writer *) + bt_ctf_object_get_parent(&trace->common.base); + stream->last_ts_end = -1ULL; + BT_LOGD("CTF writer stream object belongs writer's trace: " + "writer-addr=%p", writer); + BT_ASSERT(writer); + + if (stream_class->common.packet_context_field_type) { + BT_LOGD("Creating stream's packet context field: " + "ft-addr=%p", + stream_class->common.packet_context_field_type); + stream->packet_context = bt_ctf_field_create( + (void *) stream_class->common.packet_context_field_type); + if (!stream->packet_context) { + BT_LOGW_STR("Cannot create stream's packet context field."); + goto error; + } + + /* Initialize events_discarded */ + ret = try_set_structure_field_integer( + stream->packet_context, "events_discarded", 0); + if (ret < 0) { + BT_LOGW("Cannot set `events_discarded` field in packet context: " + "ret=%d, packet-context-field-addr=%p", + ret, stream->packet_context); + goto error; + } + } + + stream->events = g_ptr_array_new_with_free_func( + (GDestroyNotify) release_event); + if (!stream->events) { + BT_LOGE_STR("Failed to allocate a GPtrArray."); + goto error; + } + + if (trace->common.packet_header_field_type) { + BT_LOGD("Creating stream's packet header field: " + "ft-addr=%p", trace->common.packet_header_field_type); + stream->packet_header = + bt_ctf_field_create( + (void *) trace->common.packet_header_field_type); + if (!stream->packet_header) { + BT_LOGW_STR("Cannot create stream's packet header field."); + goto error; + } + } + + /* + * Attempt to populate the default trace packet header fields + * (magic, uuid and stream_id). This will _not_ fail shall the + * fields not be found or be of an incompatible type; they will + * simply not be populated automatically. The user will have to + * make sure to set the trace packet header fields himself + * before flushing. + */ + ret = auto_populate_packet_header(stream); + if (ret) { + BT_LOGW_STR("Cannot automatically populate the stream's packet header."); + goto error; + } + + /* Create file associated with this stream */ + fd = create_stream_file(writer, stream); + if (fd < 0) { + BT_LOGW_STR("Cannot create stream file."); + goto error; + } + + /* Freeze the writer */ + BT_LOGD_STR("Freezing stream's CTF writer."); + bt_ctf_writer_freeze(writer); + + /* Add this stream to the trace's streams */ + g_ptr_array_add(trace->common.streams, stream); + stream_class->next_stream_id++; + BT_LOGD("Created stream object: addr=%p", stream); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(stream); + +end: + bt_ctf_object_put_ref(writer); + return stream; +} + +struct bt_ctf_stream *bt_ctf_stream_create( + struct bt_ctf_stream_class *stream_class, + const char *name, uint64_t id_param) +{ + return bt_ctf_stream_create_with_id(stream_class, + name, id_param); +} + +int bt_ctf_stream_get_discarded_events_count( + struct bt_ctf_stream *stream, uint64_t *count) +{ + int ret = 0; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + ret = -1; + goto end; + } + + if (!count) { + BT_LOGW_STR("Invalid parameter: count is NULL."); + ret = -1; + goto end; + } + + *count = (uint64_t) stream->discarded_events; + +end: + return ret; +} + +static +int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream, + uint64_t count) +{ + int ret = 0; + struct bt_ctf_field *events_discarded_field = NULL; + + if (!stream->packet_context) { + goto end; + } + + events_discarded_field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "events_discarded"); + if (!events_discarded_field) { + goto end; + } + + ret = bt_ctf_field_integer_unsigned_set_value( + events_discarded_field, count); + if (ret) { + BT_LOGW("Cannot set packet context's `events_discarded` field: " + "field-addr=%p, value=%" PRIu64, + events_discarded_field, count); + goto end; + } + +end: + bt_ctf_object_put_ref(events_discarded_field); + return ret; +} + +void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, + uint64_t event_count) +{ + int ret; + uint64_t new_count; + struct bt_ctf_field *events_discarded_field = NULL; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + goto end; + } + + BT_LOGV("Appending discarded events to stream: " + "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), event_count); + + if (!stream->packet_context) { + BT_LOGW_STR("Invalid parameter: stream has no packet context field."); + goto end; + } + + events_discarded_field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "events_discarded"); + if (!events_discarded_field) { + BT_LOGW_STR("No field named `events_discarded` in stream's packet context."); + goto end; + } + + new_count = stream->discarded_events + event_count; + if (new_count < stream->discarded_events) { + BT_LOGW("New discarded events count is less than the stream's current discarded events count: " + "cur-count=%" PRIu64 ", new-count=%" PRIu64, + stream->discarded_events, new_count); + goto end; + } + + ret = set_packet_context_events_discarded_field(stream, new_count); + if (ret) { + /* set_packet_context_events_discarded_field() logs errors */ + goto end; + } + + stream->discarded_events = new_count; + BT_LOGV("Appended discarded events to stream: " + "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64, + stream, bt_ctf_stream_get_name(stream), event_count); + +end: + bt_ctf_object_put_ref(events_discarded_field); +} + +static int auto_populate_event_header(struct bt_ctf_stream *stream, + struct bt_ctf_event *event) +{ + int ret = 0; + struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL; + struct bt_ctf_clock_class *mapped_clock_class = NULL; + struct bt_ctf_stream_class *stream_class = + BT_CTF_FROM_COMMON(bt_ctf_stream_common_borrow_class( + BT_CTF_TO_COMMON(stream))); + int64_t event_class_id; + + BT_ASSERT(event); + + if (!event->common.header_field) { + goto end; + } + + if (event->common.frozen) { + BT_LOGW_STR("Cannot populate event header field: event is frozen."); + ret = -1; + goto end; + } + + BT_LOGV("Automatically populating event's header field: " + "stream-addr=%p, stream-name=\"%s\", event-addr=%p", + stream, bt_ctf_stream_get_name(stream), event); + + id_field = bt_ctf_field_structure_get_field_by_name( + (void *) event->common.header_field->field, "id"); + event_class_id = bt_ctf_event_class_common_get_id(event->common.class); + BT_ASSERT(event_class_id >= 0); + + if (id_field && bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER) { + ret = set_integer_field_value(id_field, event_class_id); + if (ret) { + BT_LOGW("Cannot set event header's `id` field's value: " + "addr=%p, value=%" PRIu64, id_field, + event_class_id); + goto end; + } + } + + /* + * The conditions to automatically set the timestamp are: + * + * 1. The event header field "timestamp" exists and is an + * integer field. + * 2. This stream's class has a registered clock (set with + * bt_ctf_stream_class_set_clock()). + * 3. The "timestamp" field is not set. + */ + timestamp_field = bt_ctf_field_structure_get_field_by_name( + (void *) event->common.header_field->field, "timestamp"); + if (timestamp_field && stream_class->clock && + bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER && + !bt_ctf_field_is_set_recursive(timestamp_field)) { + mapped_clock_class = + bt_ctf_field_type_integer_get_mapped_clock_class( + (void *) ((struct bt_ctf_field_common *) timestamp_field)->type); + if (mapped_clock_class) { + uint64_t timestamp; + + BT_ASSERT(mapped_clock_class == + stream_class->clock->clock_class); + ret = bt_ctf_clock_get_value( + stream_class->clock, + ×tamp); + BT_ASSERT(ret == 0); + ret = set_integer_field_value(timestamp_field, + timestamp); + if (ret) { + BT_LOGW("Cannot set event header's `timestamp` field's value: " + "addr=%p, value=%" PRIu64, + timestamp_field, timestamp); + goto end; + } + } + } + + BT_LOGV("Automatically populated event's header field: " + "stream-addr=%p, stream-name=\"%s\", event-addr=%p", + stream, bt_ctf_stream_get_name(stream), event); + +end: + bt_ctf_object_put_ref(id_field); + bt_ctf_object_put_ref(timestamp_field); + bt_ctf_object_put_ref(mapped_clock_class); + return ret; +} + +int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, + struct bt_ctf_event *event) +{ + int ret = 0; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + ret = -1; + goto end; + } + + if (!event) { + BT_LOGW_STR("Invalid parameter: event is NULL."); + ret = -1; + goto end; + } + + BT_LOGV("Appending event to stream: " + "stream-addr=%p, stream-name=\"%s\", event-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64, + stream, bt_ctf_stream_get_name(stream), event, + bt_ctf_event_class_common_get_name( + bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))), + bt_ctf_event_class_common_get_id( + bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)))); + + /* + * The event is not supposed to have a parent stream at this + * point. The only other way an event can have a parent stream + * is if it was assigned when setting a packet to the event, + * in which case the packet's stream is not a writer stream, + * and thus the user is trying to append an event which belongs + * to another stream. + */ + if (event->common.base.parent) { + ret = -1; + goto end; + } + + bt_ctf_object_set_parent(&event->common.base, &stream->common.base); + BT_LOGV_STR("Automatically populating the header of the event to append."); + ret = auto_populate_event_header(stream, event); + if (ret) { + /* auto_populate_event_header() reports errors */ + goto error; + } + + /* Make sure the various scopes of the event are set */ + BT_LOGV_STR("Validating event to append."); + BT_CTF_ASSERT_PRE(bt_ctf_event_common_validate(BT_CTF_TO_COMMON(event)) == 0, + "Invalid event: event-addr=%p", event); + + /* Save the new event and freeze it */ + BT_LOGV_STR("Freezing the event to append."); + bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true); + g_ptr_array_add(stream->events, event); + + /* + * Event had to hold a reference to its event class as long as it wasn't + * part of the same trace hierarchy. From now on, the event and its + * class share the same lifetime guarantees and the reference is no + * longer needed. + */ + BT_LOGV_STR("Putting the event's class."); + bt_ctf_object_put_ref(event->common.class); + BT_LOGV("Appended event to stream: " + "stream-addr=%p, stream-name=\"%s\", event-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64, + stream, bt_ctf_stream_get_name(stream), event, + bt_ctf_event_class_common_get_name( + bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))), + bt_ctf_event_class_common_get_id( + bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)))); + +end: + return ret; + +error: + /* + * Orphan the event; we were not successful in associating it to + * a stream. + */ + bt_ctf_object_set_parent(&event->common.base, NULL); + return ret; +} + +struct bt_ctf_field *bt_ctf_stream_get_packet_context(struct bt_ctf_stream *stream) +{ + struct bt_ctf_field *packet_context = NULL; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + goto end; + } + + packet_context = stream->packet_context; + if (packet_context) { + bt_ctf_object_get_ref(packet_context); + } +end: + return packet_context; +} + +int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream, + struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_field_type *field_type; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + ret = -1; + goto end; + } + + field_type = bt_ctf_field_get_type(field); + if (bt_ctf_field_type_common_compare((void *) field_type, + stream->common.stream_class->packet_context_field_type)) { + BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: " + "stream-addr=%p, stream-name=\"%s\", " + "packet-context-field-addr=%p, " + "packet-context-ft-addr=%p", + stream, bt_ctf_stream_get_name(stream), + field, field_type); + ret = -1; + goto end; + } + + bt_ctf_object_put_ref(field_type); + bt_ctf_object_put_ref(stream->packet_context); + stream->packet_context = bt_ctf_object_get_ref(field); + BT_LOGV("Set stream's packet context field: " + "stream-addr=%p, stream-name=\"%s\", " + "packet-context-field-addr=%p", + stream, bt_ctf_stream_get_name(stream), field); +end: + return ret; +} + +struct bt_ctf_field *bt_ctf_stream_get_packet_header(struct bt_ctf_stream *stream) +{ + struct bt_ctf_field *packet_header = NULL; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + goto end; + } + + packet_header = stream->packet_header; + if (packet_header) { + bt_ctf_object_get_ref(packet_header); + } +end: + return packet_header; +} + +int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream, + struct bt_ctf_field *field) +{ + int ret = 0; + struct bt_ctf_trace *trace = NULL; + struct bt_ctf_field_type *field_type = NULL; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + ret = -1; + goto end; + } + + trace = (struct bt_ctf_trace *) + bt_ctf_object_get_parent(&stream->common.base); + + if (!field) { + if (trace->common.packet_header_field_type) { + BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: " + "stream-addr=%p, stream-name=\"%s\", " + "packet-header-field-addr=%p, " + "expected-ft-addr=%p", + stream, bt_ctf_stream_get_name(stream), + field, trace->common.packet_header_field_type); + ret = -1; + goto end; + } + + goto skip_validation; + } + + field_type = bt_ctf_field_get_type(field); + BT_ASSERT(field_type); + + if (bt_ctf_field_type_common_compare((void *) field_type, + trace->common.packet_header_field_type)) { + BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: " + "stream-addr=%p, stream-name=\"%s\", " + "packet-header-field-addr=%p, " + "packet-header-ft-addr=%p", + stream, bt_ctf_stream_get_name(stream), + field, field_type); + ret = -1; + goto end; + } + +skip_validation: + bt_ctf_object_put_ref(stream->packet_header); + stream->packet_header = bt_ctf_object_get_ref(field); + BT_LOGV("Set stream's packet header field: " + "stream-addr=%p, stream-name=\"%s\", " + "packet-header-field-addr=%p", + stream, bt_ctf_stream_get_name(stream), field); +end: + BT_CTF_OBJECT_PUT_REF_AND_RESET(trace); + bt_ctf_object_put_ref(field_type); + return ret; +} + +static +void reset_structure_field(struct bt_ctf_field *structure, const char *name) +{ + struct bt_ctf_field *member; + + member = bt_ctf_field_structure_get_field_by_name(structure, name); + if (member) { + bt_ctf_field_common_reset_recursive((void *) member); + bt_ctf_object_put_ref(member); + } +} + +int bt_ctf_stream_flush(struct bt_ctf_stream *stream) +{ + int ret = 0; + size_t i; + uint64_t packet_context_offset_bits = 0; + struct bt_ctf_trace *trace; + enum bt_ctf_byte_order native_byte_order; + bool has_packet_size = false; + uint64_t packet_size_bits = 0; + uint64_t content_size_bits = 0; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + ret = -1; + goto end_no_stream; + } + + if (stream->packet_context) { + struct bt_ctf_field *packet_size_field; + + packet_size_field = bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "packet_size"); + has_packet_size = (packet_size_field != NULL); + bt_ctf_object_put_ref(packet_size_field); + } + + if (stream->flushed_packet_count == 1) { + if (!stream->packet_context) { + BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once."); + ret = -1; + goto end; + } + + if (!has_packet_size) { + BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once."); + ret = -1; + goto end; + } + } + + BT_LOGV("Flushing stream's current packet: stream-addr=%p, " + "stream-name=\"%s\", packet-index=%u", stream, + bt_ctf_stream_get_name(stream), stream->flushed_packet_count); + trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace( + stream->common.stream_class)); + BT_ASSERT(trace); + native_byte_order = bt_ctf_trace_get_native_byte_order(trace); + + ret = auto_populate_packet_header(stream); + if (ret) { + BT_LOGW_STR("Cannot automatically populate the stream's packet header field."); + ret = -1; + goto end; + } + + /* Initialize packet/content sizes to `0`; we will overwrite later */ + ret = auto_populate_packet_context(stream, true, 0, 0); + if (ret) { + BT_LOGW_STR("Cannot automatically populate the stream's packet context field."); + ret = -1; + goto end; + } + + ret = bt_ctfser_open_packet(&stream->ctfser); + if (ret) { + /* bt_ctfser_open_packet() logs errors */ + ret = -1; + goto end; + } + + if (stream->packet_header) { + BT_LOGV_STR("Serializing packet header field (initial)."); + ret = bt_ctf_field_serialize_recursive(stream->packet_header, + &stream->ctfser, native_byte_order); + if (ret) { + BT_LOGW("Cannot serialize stream's packet header field: " + "field-addr=%p", stream->packet_header); + goto end; + } + } + + if (stream->packet_context) { + /* Save packet context's position to overwrite it later */ + packet_context_offset_bits = + bt_ctfser_get_offset_in_current_packet_bits( + &stream->ctfser); + + /* Write packet context */ + BT_LOGV_STR("Serializing packet context field (initial)."); + ret = bt_ctf_field_serialize_recursive(stream->packet_context, + &stream->ctfser, native_byte_order); + if (ret) { + BT_LOGW("Cannot serialize stream's packet context field: " + "field-addr=%p", stream->packet_context); + goto end; + } + } + + BT_LOGV("Serializing events: count=%u", stream->events->len); + + for (i = 0; i < stream->events->len; i++) { + struct bt_ctf_event *event = g_ptr_array_index( + stream->events, i); + struct bt_ctf_event_class *event_class = + BT_CTF_FROM_COMMON(bt_ctf_event_common_borrow_class( + BT_CTF_TO_COMMON(event))); + + BT_LOGV("Serializing event: index=%zu, event-addr=%p, " + "event-class-name=\"%s\", event-class-id=%" PRId64 ", " + "ser-offset=%" PRIu64, + i, event, bt_ctf_event_class_get_name(event_class), + bt_ctf_event_class_get_id(event_class), + bt_ctfser_get_offset_in_current_packet_bits( + &stream->ctfser)); + + /* Write event header */ + if (event->common.header_field) { + BT_LOGV_STR("Serializing event's header field."); + ret = bt_ctf_field_serialize_recursive( + (void *) event->common.header_field->field, + &stream->ctfser, native_byte_order); + if (ret) { + BT_LOGW("Cannot serialize event's header field: " + "field-addr=%p", + event->common.header_field->field); + goto end; + } + } + + /* Write stream event context */ + if (event->common.stream_event_context_field) { + BT_LOGV_STR("Serializing event's stream event context field."); + ret = bt_ctf_field_serialize_recursive( + (void *) event->common.stream_event_context_field, + &stream->ctfser, native_byte_order); + if (ret) { + BT_LOGW("Cannot serialize event's stream event context field: " + "field-addr=%p", + event->common.stream_event_context_field); + goto end; + } + } + + /* Write event content */ + ret = bt_ctf_event_serialize(event, &stream->ctfser, + native_byte_order); + if (ret) { + /* bt_ctf_event_serialize() logs errors */ + goto end; + } + } + + content_size_bits = bt_ctfser_get_offset_in_current_packet_bits( + &stream->ctfser); + + if (!has_packet_size && content_size_bits % 8 != 0) { + BT_LOGW("Stream's packet context field type has no `packet_size` field, " + "but current content size is not a multiple of 8 bits: " + "content-size=%" PRIu64 ", " + "packet-size=%" PRIu64, + content_size_bits, + packet_size_bits); + ret = -1; + goto end; + } + + /* Set packet size; make it a multiple of 8 */ + packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7); + + if (stream->packet_context) { + /* + * The whole packet is serialized at this point. Make + * sure that, if `packet_size` is missing, the current + * content size is equal to the current packet size. + */ + struct bt_ctf_field *field = + bt_ctf_field_structure_get_field_by_name( + stream->packet_context, "content_size"); + + bt_ctf_object_put_ref(field); + if (!field) { + if (content_size_bits != packet_size_bits) { + BT_LOGW("Stream's packet context's `content_size` field is missing, " + "but current packet's content size is not equal to its packet size: " + "content-size=%" PRIu64 ", " + "packet-size=%" PRIu64, + bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser), + packet_size_bits); + ret = -1; + goto end; + } + } + + /* + * Overwrite the packet context now that the stream + * position's packet and content sizes have the correct + * values. + */ + bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser, + packet_context_offset_bits); + ret = auto_populate_packet_context(stream, false, + packet_size_bits, content_size_bits); + if (ret) { + BT_LOGW_STR("Cannot automatically populate the stream's packet context field."); + ret = -1; + goto end; + } + + BT_LOGV("Rewriting (serializing) packet context field."); + ret = bt_ctf_field_serialize_recursive(stream->packet_context, + &stream->ctfser, native_byte_order); + if (ret) { + BT_LOGW("Cannot serialize stream's packet context field: " + "field-addr=%p", stream->packet_context); + goto end; + } + } + + g_ptr_array_set_size(stream->events, 0); + stream->flushed_packet_count++; + bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8); + +end: + /* Reset automatically-set fields. */ + if (stream->packet_context) { + reset_structure_field(stream->packet_context, "timestamp_begin"); + reset_structure_field(stream->packet_context, "timestamp_end"); + reset_structure_field(stream->packet_context, "packet_size"); + reset_structure_field(stream->packet_context, "content_size"); + reset_structure_field(stream->packet_context, "events_discarded"); + } + + if (ret == 0) { + BT_LOGV("Flushed stream's current packet: " + "content-size=%" PRIu64 ", packet-size=%" PRIu64, + content_size_bits, packet_size_bits); + } + +end_no_stream: + return ret; +} + +static +void bt_ctf_stream_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_stream *stream = (void *) obj; + + BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"", + stream, bt_ctf_stream_get_name(stream)); + + bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream)); + bt_ctfser_fini(&stream->ctfser); + + if (stream->events) { + BT_LOGD_STR("Putting events."); + g_ptr_array_free(stream->events, TRUE); + } + + BT_LOGD_STR("Putting packet header field."); + bt_ctf_object_put_ref(stream->packet_header); + BT_LOGD_STR("Putting packet context field."); + bt_ctf_object_put_ref(stream->packet_context); + g_free(stream); +} + +static +int _set_structure_field_integer(struct bt_ctf_field *structure, char *name, + uint64_t value, bt_bool force) +{ + int ret = 0; + struct bt_ctf_field_type *field_type = NULL; + struct bt_ctf_field *integer; + + BT_ASSERT(structure); + BT_ASSERT(name); + + integer = bt_ctf_field_structure_get_field_by_name(structure, name); + if (!integer) { + /* Field not found, not an error. */ + BT_LOGV("Field not found: struct-field-addr=%p, " + "name=\"%s\", force=%d", structure, name, force); + goto end; + } + + /* Make sure the payload has not already been set. */ + if (!force && bt_ctf_field_is_set_recursive(integer)) { + /* Payload already set, not an error */ + BT_LOGV("Field's payload is already set: struct-field-addr=%p, " + "name=\"%s\", force=%d", structure, name, force); + goto end; + } + + field_type = bt_ctf_field_get_type(integer); + BT_ASSERT(field_type); + if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { + /* + * The user most likely meant for us to populate this field + * automatically. However, we can only do this if the field + * is an integer. Return an error. + */ + BT_LOGW("Invalid parameter: field's type is not an integer field type: " + "field-addr=%p, ft-addr=%p, ft-id=%s", + integer, field_type, + bt_ctf_field_type_id_string((int) + bt_ctf_field_type_get_type_id(field_type))); + ret = -1; + goto end; + } + + if (bt_ctf_field_type_integer_is_signed(field_type)) { + ret = bt_ctf_field_integer_signed_set_value(integer, + (int64_t) value); + } else { + ret = bt_ctf_field_integer_unsigned_set_value(integer, value); + } + ret = !ret ? 1 : ret; +end: + bt_ctf_object_put_ref(integer); + bt_ctf_object_put_ref(field_type); + return ret; +} + +/* + * Returns the following codes: + * 1 if the field was found and set, + * 0 if nothing was done (field not found, or was already set), + * <0 if an error was encoutered + */ +static +int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name, + uint64_t value) +{ + return _set_structure_field_integer(structure, name, value, BT_FALSE); +} + +struct bt_ctf_stream_class *bt_ctf_stream_get_class( + struct bt_ctf_stream *stream) +{ + return bt_ctf_object_get_ref(bt_ctf_stream_common_borrow_class(BT_CTF_TO_COMMON(stream))); +} + +const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream) +{ + return bt_ctf_stream_common_get_name(BT_CTF_TO_COMMON(stream)); +} + +int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream) +{ + return bt_ctf_stream_common_get_id(BT_CTF_TO_COMMON(stream)); +} diff --git a/ctf-writer/trace.c b/ctf-writer/trace.c new file mode 100644 index 00000000..8737470c --- /dev/null +++ b/ctf-writer/trace.c @@ -0,0 +1,1883 @@ +/* + * Copyright 2013, 2014 Jérémie Galarneau + * Copyright 2017-2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-TRACE" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_IDENTIFIER_SIZE 128 +#define DEFAULT_METADATA_STRING_SIZE 4096 + +BT_HIDDEN +int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace, + bt_ctf_object_release_func release_func) +{ + int ret = 0; + + BT_LOGD_STR("Initializing common trace object."); + trace->native_byte_order = BT_CTF_BYTE_ORDER_UNSPECIFIED; + bt_ctf_object_init_shared_with_parent(&trace->base, release_func); + trace->clock_classes = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_ctf_object_put_ref); + if (!trace->clock_classes) { + BT_LOGE_STR("Failed to allocate one GPtrArray."); + goto error; + } + + trace->streams = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_ctf_object_try_spec_release); + if (!trace->streams) { + BT_LOGE_STR("Failed to allocate one GPtrArray."); + goto error; + } + + trace->stream_classes = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_ctf_object_try_spec_release); + if (!trace->stream_classes) { + BT_LOGE_STR("Failed to allocate one GPtrArray."); + goto error; + } + + /* Create the environment array object */ + trace->environment = bt_ctf_attributes_create(); + if (!trace->environment) { + BT_LOGE_STR("Cannot create empty attributes object."); + goto error; + } + + BT_LOGD("Initialized common trace object: addr=%p", trace); + goto end; + +error: + ret = -1; + +end: + return ret; +} + +BT_HIDDEN +void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace) +{ + BT_LOGD("Finalizing common trace object: addr=%p, name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace)); + + if (trace->environment) { + BT_LOGD_STR("Destroying environment attributes."); + bt_ctf_attributes_destroy(trace->environment); + } + + if (trace->name) { + g_string_free(trace->name, TRUE); + } + + if (trace->clock_classes) { + BT_LOGD_STR("Putting clock classes."); + g_ptr_array_free(trace->clock_classes, TRUE); + } + + if (trace->streams) { + BT_LOGD_STR("Destroying streams."); + g_ptr_array_free(trace->streams, TRUE); + } + + if (trace->stream_classes) { + BT_LOGD_STR("Destroying stream classes."); + g_ptr_array_free(trace->stream_classes, TRUE); + } + + BT_LOGD_STR("Putting packet header field type."); + bt_ctf_object_put_ref(trace->packet_header_field_type); +} + +BT_HIDDEN +int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *name) +{ + int ret = 0; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (!name) { + BT_LOGW_STR("Invalid parameter: name is NULL."); + ret = -1; + goto end; + } + + if (trace->frozen) { + BT_LOGW("Invalid parameter: trace is frozen: " + "addr=%p, name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace)); + ret = -1; + goto end; + } + + trace->name = trace->name ? g_string_assign(trace->name, name) : + g_string_new(name); + if (!trace->name) { + BT_LOGE_STR("Failed to allocate one GString."); + ret = -1; + goto end; + } + + BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace, + const unsigned char *uuid) +{ + int ret = 0; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (!uuid) { + BT_LOGW_STR("Invalid parameter: UUID is NULL."); + ret = -1; + goto end; + } + + if (trace->frozen) { + BT_LOGW("Invalid parameter: trace is frozen: " + "addr=%p, name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace)); + ret = -1; + goto end; + } + + memcpy(trace->uuid, uuid, BABELTRACE_UUID_LEN); + trace->uuid_set = BT_TRUE; + BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", " + "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", + trace, bt_ctf_trace_common_get_name(trace), + (unsigned int) uuid[0], + (unsigned int) uuid[1], + (unsigned int) uuid[2], + (unsigned int) uuid[3], + (unsigned int) uuid[4], + (unsigned int) uuid[5], + (unsigned int) uuid[6], + (unsigned int) uuid[7], + (unsigned int) uuid[8], + (unsigned int) uuid[9], + (unsigned int) uuid[10], + (unsigned int) uuid[11], + (unsigned int) uuid[12], + (unsigned int) uuid[13], + (unsigned int) uuid[14], + (unsigned int) uuid[15]); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace, + const char *name, struct bt_ctf_private_value *value) +{ + int ret = 0; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (!name) { + BT_LOGW_STR("Invalid parameter: name is NULL."); + ret = -1; + goto end; + } + + if (!value) { + BT_LOGW_STR("Invalid parameter: value is NULL."); + ret = -1; + goto end; + } + + if (!bt_ctf_identifier_is_valid(name)) { + BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: " + "trace-addr=%p, trace-name=\"%s\", " + "env-name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace), name); + ret = -1; + goto end; + } + + if (!bt_ctf_value_is_integer(bt_ctf_private_value_as_value(value)) && + !bt_ctf_value_is_string(bt_ctf_private_value_as_value(value))) { + BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: " + "trace-addr=%p, trace-name=\"%s\", " + "env-name=\"%s\", env-value-type=%s", + trace, bt_ctf_trace_common_get_name(trace), name, + bt_ctf_value_type_string( + bt_ctf_value_get_type( + bt_ctf_private_value_as_value(value)))); + ret = -1; + goto end; + } + + if (trace->frozen) { + /* + * New environment fields may be added to a frozen trace, + * but existing fields may not be changed. + * + * The object passed is frozen like all other attributes. + */ + struct bt_ctf_private_value *attribute = + bt_ctf_attributes_borrow_field_value_by_name( + trace->environment, name); + + if (attribute) { + BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: " + "trace-addr=%p, trace-name=\"%s\", " + "env-name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace), name); + ret = -1; + goto end; + } + + bt_ctf_value_freeze(bt_ctf_private_value_as_value(value)); + } + + ret = bt_ctf_attributes_set_field_value(trace->environment, name, + value); + if (ret) { + BT_LOGE("Cannot set environment field's value: " + "trace-addr=%p, trace-name=\"%s\", " + "env-name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace), name); + } else { + BT_LOGV("Set environment field's value: " + "trace-addr=%p, trace-name=\"%s\", " + "env-name=\"%s\", value-addr=%p", + trace, bt_ctf_trace_common_get_name(trace), name, value); + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace, + const char *name, const char *value) +{ + int ret = 0; + struct bt_ctf_private_value *env_value_string_obj = NULL; + + if (!value) { + BT_LOGW_STR("Invalid parameter: value is NULL."); + ret = -1; + goto end; + } + + env_value_string_obj = bt_ctf_private_value_string_create_init(value); + if (!env_value_string_obj) { + BT_LOGE_STR("Cannot create string value object."); + ret = -1; + goto end; + } + + /* bt_ctf_trace_common_set_environment_field() logs errors */ + ret = bt_ctf_trace_common_set_environment_field(trace, name, + env_value_string_obj); + +end: + bt_ctf_object_put_ref(env_value_string_obj); + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_common_set_environment_field_integer( + struct bt_ctf_trace_common *trace, const char *name, int64_t value) +{ + int ret = 0; + struct bt_ctf_private_value *env_value_integer_obj = NULL; + + env_value_integer_obj = bt_ctf_private_value_integer_create_init(value); + if (!env_value_integer_obj) { + BT_LOGE_STR("Cannot create integer value object."); + ret = -1; + goto end; + } + + /* bt_ctf_trace_common_set_environment_field() logs errors */ + ret = bt_ctf_trace_common_set_environment_field(trace, name, + env_value_integer_obj); + +end: + bt_ctf_object_put_ref(env_value_integer_obj); + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace, + struct bt_ctf_clock_class *clock_class) +{ + int ret = 0; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (!bt_ctf_clock_class_is_valid(clock_class)) { + BT_LOGW("Invalid parameter: clock class is invalid: " + "trace-addr=%p, trace-name=\"%s\", " + "clock-class-addr=%p, clock-class-name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace), + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + /* Check for duplicate clock classes */ + if (bt_ctf_trace_common_has_clock_class(trace, clock_class)) { + BT_LOGW("Invalid parameter: clock class already exists in trace: " + "trace-addr=%p, trace-name=\"%s\", " + "clock-class-addr=%p, clock-class-name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace), + clock_class, bt_ctf_clock_class_get_name(clock_class)); + ret = -1; + goto end; + } + + bt_ctf_object_get_ref(clock_class); + g_ptr_array_add(trace->clock_classes, clock_class); + + if (trace->frozen) { + BT_LOGV_STR("Freezing added clock class because trace is frozen."); + bt_ctf_clock_class_freeze(clock_class); + } + + BT_LOGV("Added clock class to trace: " + "trace-addr=%p, trace-name=\"%s\", " + "clock-class-addr=%p, clock-class-name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace), + clock_class, bt_ctf_clock_class_get_name(clock_class)); + +end: + return ret; +} + +static +bool packet_header_field_type_is_valid(struct bt_ctf_trace_common *trace, + struct bt_ctf_field_type_common *packet_header_type) +{ + int ret; + bool is_valid = true; + struct bt_ctf_field_type_common *field_type = NULL; + + if (!packet_header_type) { + /* + * No packet header field type: trace must have only + * one stream. At this point the stream class being + * added is not part of the trace yet, so we validate + * that the trace contains no stream classes yet. + */ + if (trace->stream_classes->len >= 1) { + BT_LOGW_STR("Invalid packet header field type: " + "packet header field type does not exist but there's more than one stream class in the trace."); + goto invalid; + } + + /* No packet header field type: valid at this point */ + goto end; + } + + /* Packet header field type, if it exists, must be a structure */ + if (packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { + BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: " + "ft-addr=%p, ft-id=%s", + packet_header_type, + bt_ctf_field_type_id_string(packet_header_type->id)); + goto invalid; + } + + /* + * If there's a `magic` field, it must be a 32-bit unsigned + * integer field type. Also it must be the first field of the + * packet header field type. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_header_type, "magic"); + if (field_type) { + const char *field_name; + + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: " + "magic-ft-addr=%p, magic-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: " + "magic-ft-addr=%p", field_type); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_get_size(field_type) != 32) { + BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: " + "magic-ft-addr=%p, magic-ft-size=%u", + field_type, + bt_ctf_field_type_common_integer_get_size(field_type)); + goto invalid; + } + + ret = bt_ctf_field_type_common_structure_borrow_field_by_index( + packet_header_type, &field_name, NULL, 0); + BT_ASSERT(ret == 0); + + if (strcmp(field_name, "magic") != 0) { + BT_LOGW("Invalid packet header field type: `magic` field must be the first field: " + "magic-ft-addr=%p, first-field-name=\"%s\"", + field_type, field_name); + goto invalid; + } + } + + /* + * If there's a `uuid` field, it must be an array field type of + * length 16 with an 8-bit unsigned integer element field type. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_header_type, "uuid"); + if (field_type) { + struct bt_ctf_field_type_common *elem_ft; + + if (field_type->id != BT_CTF_FIELD_TYPE_ID_ARRAY) { + BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: " + "uuid-ft-addr=%p, uuid-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_array_get_length(field_type) != 16) { + BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: " + "uuid-ft-addr=%p, uuid-ft-length=%" PRId64, + field_type, + bt_ctf_field_type_common_array_get_length(field_type)); + goto invalid; + } + + elem_ft = bt_ctf_field_type_common_array_borrow_element_field_type(field_type); + BT_ASSERT(elem_ft); + + if (elem_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: " + "elem-ft-addr=%p, elem-ft-id=%s", + elem_ft, + bt_ctf_field_type_id_string(elem_ft->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(elem_ft)) { + BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: " + "elem-ft-addr=%p", elem_ft); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_get_size(elem_ft) != 8) { + BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: " + "elem-ft-addr=%p, elem-ft-size=%u", + elem_ft, + bt_ctf_field_type_common_integer_get_size(elem_ft)); + goto invalid; + } + } + + /* + * The `stream_id` field must exist if there's more than one + * stream classes in the trace. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_header_type, "stream_id"); + + if (!field_type && trace->stream_classes->len >= 1) { + BT_LOGW_STR("Invalid packet header field type: " + "`stream_id` field does not exist but there's more than one stream class in the trace."); + goto invalid; + } + + /* + * If there's a `stream_id` field, it must be an unsigned + * integer field type. + */ + if (field_type) { + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: " + "stream-id-ft-addr=%p, stream-id-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: " + "stream-id-ft-addr=%p", field_type); + goto invalid; + } + } + + /* + * If there's a `packet_seq_num` field, it must be an unsigned + * integer field type. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_header_type, "packet_seq_num"); + if (field_type) { + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: " + "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: " + "packet-seq-num-ft-addr=%p", field_type); + goto invalid; + } + } + + goto end; + +invalid: + is_valid = false; + +end: + return is_valid; +} + +static +bool packet_context_field_type_is_valid(struct bt_ctf_trace_common *trace, + struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_field_type_common *packet_context_type, + bool check_ts_begin_end_mapped) +{ + bool is_valid = true; + struct bt_ctf_field_type_common *field_type = NULL; + + if (!packet_context_type) { + /* No packet context field type: valid at this point */ + goto end; + } + + /* Packet context field type, if it exists, must be a structure */ + if (packet_context_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { + BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: " + "ft-addr=%p, ft-id=%s", + packet_context_type, + bt_ctf_field_type_id_string(packet_context_type->id)); + goto invalid; + } + + /* + * If there's a `packet_size` field, it must be an unsigned + * integer field type. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_context_type, "packet_size"); + if (field_type) { + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: " + "packet-size-ft-addr=%p, packet-size-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: " + "packet-size-ft-addr=%p", field_type); + goto invalid; + } + } + + /* + * If there's a `content_size` field, it must be an unsigned + * integer field type. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_context_type, "content_size"); + if (field_type) { + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: " + "content-size-ft-addr=%p, content-size-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: " + "content-size-ft-addr=%p", field_type); + goto invalid; + } + } + + /* + * If there's a `events_discarded` field, it must be an unsigned + * integer field type. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_context_type, "events_discarded"); + if (field_type) { + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: " + "events-discarded-ft-addr=%p, events-discarded-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: " + "events-discarded-ft-addr=%p", field_type); + goto invalid; + } + } + + /* + * If there's a `timestamp_begin` field, it must be an unsigned + * integer field type. Also, if the trace is not a CTF writer's + * trace, then we cannot automatically set the mapped clock + * class of this field, so it must have a mapped clock class. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_context_type, "timestamp_begin"); + if (field_type) { + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: " + "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: " + "timestamp-begin-ft-addr=%p", field_type); + goto invalid; + } + + if (check_ts_begin_end_mapped) { + struct bt_ctf_clock_class *clock_class = + bt_ctf_field_type_common_integer_borrow_mapped_clock_class( + field_type); + + if (!clock_class) { + BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: " + "timestamp-begin-ft-addr=%p", field_type); + goto invalid; + } + } + } + + /* + * If there's a `timestamp_end` field, it must be an unsigned + * integer field type. Also, if the trace is not a CTF writer's + * trace, then we cannot automatically set the mapped clock + * class of this field, so it must have a mapped clock class. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + packet_context_type, "timestamp_end"); + if (field_type) { + if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { + BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: " + "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + if (bt_ctf_field_type_common_integer_is_signed(field_type)) { + BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: " + "timestamp-end-ft-addr=%p", field_type); + goto invalid; + } + + if (check_ts_begin_end_mapped) { + struct bt_ctf_clock_class *clock_class = + bt_ctf_field_type_common_integer_borrow_mapped_clock_class( + field_type); + + if (!clock_class) { + BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: " + "timestamp-end-ft-addr=%p", field_type); + goto invalid; + } + } + } + + goto end; + +invalid: + is_valid = false; + +end: + return is_valid; +} + +static +bool event_header_field_type_is_valid(struct bt_ctf_trace_common *trace, + struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_field_type_common *event_header_type) +{ + bool is_valid = true; + struct bt_ctf_field_type_common *field_type = NULL; + + /* + * We do not validate that the `timestamp` field exists here + * because CTF does not require this exact name to be mapped to + * a clock class. + */ + + if (!event_header_type) { + /* + * No event header field type: stream class must have + * only one event class. + */ + if (bt_ctf_stream_class_common_get_event_class_count(stream_class) > 1) { + BT_LOGW_STR("Invalid event header field type: " + "event header field type does not exist but there's more than one event class in the stream class."); + goto invalid; + } + + /* No event header field type: valid at this point */ + goto end; + } + + /* Event header field type, if it exists, must be a structure */ + if (event_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { + BT_LOGW("Invalid event header field type: must be a structure field type if it exists: " + "ft-addr=%p, ft-id=%s", + event_header_type, + bt_ctf_field_type_id_string(event_header_type->id)); + goto invalid; + } + + /* + * If there's an `id` field, it must be an unsigned integer + * field type or an enumeration field type with an unsigned + * integer container field type. + */ + field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( + event_header_type, "id"); + if (field_type) { + struct bt_ctf_field_type_common *int_ft; + + if (field_type->id == BT_CTF_FIELD_TYPE_ID_INTEGER) { + int_ft = field_type; + } else if (field_type->id == BT_CTF_FIELD_TYPE_ID_ENUM) { + int_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type( + field_type); + } else { + BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: " + "id-ft-addr=%p, id-ft-id=%s", + field_type, + bt_ctf_field_type_id_string(field_type->id)); + goto invalid; + } + + BT_ASSERT(int_ft); + if (bt_ctf_field_type_common_integer_is_signed(int_ft)) { + BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: " + "id-ft-addr=%p", int_ft); + goto invalid; + } + } + + goto end; + +invalid: + is_valid = false; + +end: + return is_valid; +} + +static +int check_packet_header_type_has_no_clock_class(struct bt_ctf_trace_common *trace) +{ + int ret = 0; + + if (trace->packet_header_field_type) { + struct bt_ctf_clock_class *clock_class = NULL; + + ret = bt_ctf_field_type_common_validate_single_clock_class( + trace->packet_header_field_type, + &clock_class); + bt_ctf_object_put_ref(clock_class); + if (ret || clock_class) { + BT_LOGW("Trace's packet header field type cannot " + "contain a field type which is mapped to " + "a clock class: " + "trace-addr=%p, trace-name=\"%s\", " + "clock-class-name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace), + clock_class ? + bt_ctf_clock_class_get_name(clock_class) : + NULL); + ret = -1; + } + } + + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace, + struct bt_ctf_stream_class_common *stream_class, + bt_ctf_validation_flag_copy_field_type_func copy_field_type_func, + struct bt_ctf_clock_class *init_expected_clock_class, + int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_field_type_common *packet_context_field_type, + struct bt_ctf_field_type_common *event_header_field_type), + bool check_ts_begin_end_mapped) +{ + int ret; + int64_t i; + int64_t stream_id; + struct bt_ctf_validation_output trace_sc_validation_output = { 0 }; + struct bt_ctf_validation_output *ec_validation_outputs = NULL; + const enum bt_ctf_validation_flag trace_sc_validation_flags = + BT_CTF_VALIDATION_FLAG_TRACE | + BT_CTF_VALIDATION_FLAG_STREAM; + const enum bt_ctf_validation_flag ec_validation_flags = + BT_CTF_VALIDATION_FLAG_EVENT; + struct bt_ctf_field_type_common *packet_header_type = NULL; + struct bt_ctf_field_type_common *packet_context_type = NULL; + struct bt_ctf_field_type_common *event_header_type = NULL; + struct bt_ctf_field_type_common *stream_event_ctx_type = NULL; + int64_t event_class_count; + struct bt_ctf_trace_common *current_parent_trace = NULL; + struct bt_ctf_clock_class *expected_clock_class = + bt_ctf_object_get_ref(init_expected_clock_class); + + BT_ASSERT(copy_field_type_func); + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (!stream_class) { + BT_LOGW_STR("Invalid parameter: stream class is NULL."); + ret = -1; + goto end; + } + + BT_LOGD("Adding stream class to trace: " + "trace-addr=%p, trace-name=\"%s\", " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-class-id=%" PRId64, + trace, bt_ctf_trace_common_get_name(trace), + stream_class, bt_ctf_stream_class_common_get_name(stream_class), + bt_ctf_stream_class_common_get_id(stream_class)); + + current_parent_trace = bt_ctf_stream_class_common_borrow_trace(stream_class); + if (current_parent_trace) { + /* Stream class is already associated to a trace, abort. */ + BT_LOGW("Invalid parameter: stream class is already part of a trace: " + "stream-class-trace-addr=%p, " + "stream-class-trace-name=\"%s\"", + current_parent_trace, + bt_ctf_trace_common_get_name(current_parent_trace)); + ret = -1; + goto end; + } + + event_class_count = + bt_ctf_stream_class_common_get_event_class_count(stream_class); + BT_ASSERT(event_class_count >= 0); + + if (!stream_class->frozen) { + /* + * Stream class is not frozen yet. Validate that the + * stream class contains at most a single clock class + * because the previous + * bt_ctf_stream_class_common_add_event_class() calls did + * not make this validation since the stream class's + * direct field types (packet context, event header, + * event context) could change afterwards. This stream + * class is about to be frozen and those field types + * won't be changed if this function succeeds. + * + * At this point we're also sure that the stream class's + * clock, if any, has the same class as the stream + * class's expected clock class, if any. This is why, if + * bt_ctf_stream_class_common_validate_single_clock_class() + * succeeds below, the call to + * bt_ctf_stream_class_map_clock_class() at the end of this + * function is safe because it maps to the same, single + * clock class. + */ + ret = bt_ctf_stream_class_common_validate_single_clock_class( + stream_class, &expected_clock_class); + if (ret) { + BT_LOGW("Invalid parameter: stream class or one of its " + "event classes contains a field type which is " + "not recursively mapped to the expected " + "clock class: " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", " + "stream-class-name=\"%s\", " + "expected-clock-class-addr=%p, " + "expected-clock-class-name=\"%s\"", + stream_class, bt_ctf_stream_class_common_get_id(stream_class), + bt_ctf_stream_class_common_get_name(stream_class), + expected_clock_class, + expected_clock_class ? + bt_ctf_clock_class_get_name(expected_clock_class) : + NULL); + goto end; + } + } + + ret = check_packet_header_type_has_no_clock_class(trace); + if (ret) { + /* check_packet_header_type_has_no_clock_class() logs errors */ + goto end; + } + + /* + * We're about to freeze both the trace and the stream class. + * Also, each event class contained in this stream class are + * already frozen. + * + * This trace, this stream class, and all its event classes + * should be valid at this point. + * + * Validate trace and stream class first, then each event + * class of this stream class can be validated individually. + */ + packet_header_type = + bt_ctf_trace_common_borrow_packet_header_field_type(trace); + packet_context_type = + bt_ctf_stream_class_common_borrow_packet_context_field_type(stream_class); + event_header_type = + bt_ctf_stream_class_common_borrow_event_header_field_type(stream_class); + stream_event_ctx_type = + bt_ctf_stream_class_common_borrow_event_context_field_type(stream_class); + + BT_LOGD("Validating trace and stream class field types."); + ret = bt_ctf_validate_class_types(trace->environment, + packet_header_type, packet_context_type, event_header_type, + stream_event_ctx_type, NULL, NULL, trace->valid, + stream_class->valid, 1, &trace_sc_validation_output, + trace_sc_validation_flags, copy_field_type_func); + + if (ret) { + /* + * This means something went wrong during the validation + * process, not that the objects are invalid. + */ + BT_LOGE("Failed to validate trace and stream class field types: " + "ret=%d", ret); + goto end; + } + + if ((trace_sc_validation_output.valid_flags & + trace_sc_validation_flags) != + trace_sc_validation_flags) { + /* Invalid trace/stream class */ + BT_LOGW("Invalid trace or stream class field types: " + "valid-flags=0x%x", + trace_sc_validation_output.valid_flags); + ret = -1; + goto end; + } + + if (event_class_count > 0) { + ec_validation_outputs = g_new0(struct bt_ctf_validation_output, + event_class_count); + if (!ec_validation_outputs) { + BT_LOGE_STR("Failed to allocate one validation output structure."); + ret = -1; + goto end; + } + } + + /* Validate each event class individually */ + for (i = 0; i < event_class_count; i++) { + struct bt_ctf_event_class_common *event_class = + bt_ctf_stream_class_common_borrow_event_class_by_index( + stream_class, i); + struct bt_ctf_field_type_common *event_context_type = NULL; + struct bt_ctf_field_type_common *event_payload_type = NULL; + + event_context_type = + bt_ctf_event_class_common_borrow_context_field_type( + event_class); + event_payload_type = + bt_ctf_event_class_common_borrow_payload_field_type( + event_class); + + /* + * It is important to use the field types returned by + * the previous trace and stream class validation here + * because copies could have been made. + */ + BT_LOGD("Validating event class's field types: " + "addr=%p, name=\"%s\", id=%" PRId64, + event_class, bt_ctf_event_class_common_get_name(event_class), + bt_ctf_event_class_common_get_id(event_class)); + ret = bt_ctf_validate_class_types(trace->environment, + trace_sc_validation_output.packet_header_type, + trace_sc_validation_output.packet_context_type, + trace_sc_validation_output.event_header_type, + trace_sc_validation_output.stream_event_ctx_type, + event_context_type, event_payload_type, + 1, 1, event_class->valid, &ec_validation_outputs[i], + ec_validation_flags, copy_field_type_func); + + if (ret) { + BT_LOGE("Failed to validate event class field types: " + "ret=%d", ret); + goto end; + } + + if ((ec_validation_outputs[i].valid_flags & + ec_validation_flags) != ec_validation_flags) { + /* Invalid event class */ + BT_LOGW("Invalid event class field types: " + "valid-flags=0x%x", + ec_validation_outputs[i].valid_flags); + ret = -1; + goto end; + } + } + + stream_id = bt_ctf_stream_class_common_get_id(stream_class); + if (stream_id < 0) { + stream_id = trace->next_stream_id++; + if (stream_id < 0) { + BT_LOGE_STR("No more stream class IDs available."); + ret = -1; + goto end; + } + + /* Try to assign a new stream id */ + for (i = 0; i < trace->stream_classes->len; i++) { + if (stream_id == bt_ctf_stream_class_common_get_id( + trace->stream_classes->pdata[i])) { + /* Duplicate stream id found */ + BT_LOGW("Duplicate stream class ID: " + "id=%" PRId64, (int64_t) stream_id); + ret = -1; + goto end; + } + } + + if (bt_ctf_stream_class_common_set_id_no_check(stream_class, + stream_id)) { + /* TODO Should retry with a different stream id */ + BT_LOGE("Cannot set stream class's ID: " + "id=%" PRId64, (int64_t) stream_id); + ret = -1; + goto end; + } + } + + /* + * At this point all the field types in the validation output + * are valid. Validate the semantics of some scopes according to + * the CTF specification. + */ + if (!packet_header_field_type_is_valid(trace, + trace_sc_validation_output.packet_header_type)) { + BT_LOGW_STR("Invalid trace's packet header field type."); + ret = -1; + goto end; + } + + if (!packet_context_field_type_is_valid(trace, + stream_class, + trace_sc_validation_output.packet_context_type, + check_ts_begin_end_mapped)) { + BT_LOGW_STR("Invalid stream class's packet context field type."); + ret = -1; + goto end; + } + + if (!event_header_field_type_is_valid(trace, + stream_class, + trace_sc_validation_output.event_header_type)) { + BT_LOGW_STR("Invalid steam class's event header field type."); + ret = -1; + goto end; + } + + /* + * Now is the time to automatically map specific field types of + * the stream class's packet context and event header field + * types to the stream class's clock's class if they are not + * mapped to a clock class yet. We do it here because we know + * that after this point, everything is frozen so it won't be + * possible for the user to modify the stream class's clock, or + * to map those field types to other clock classes. + */ + if (map_clock_classes_func) { + if (map_clock_classes_func(stream_class, + trace_sc_validation_output.packet_context_type, + trace_sc_validation_output.event_header_type)) { + /* map_clock_classes_func() logs errors */ + ret = -1; + goto end; + } + } + + bt_ctf_object_set_parent(&stream_class->base, &trace->base); + g_ptr_array_add(trace->stream_classes, stream_class); + + /* + * At this point we know that the function will be successful. + * Therefore we can replace the trace and stream class field + * types with what's in their validation output structure and + * mark them as valid. We can also replace the field types of + * all the event classes of the stream class and mark them as + * valid. + */ + bt_ctf_validation_replace_types(trace, stream_class, NULL, + &trace_sc_validation_output, trace_sc_validation_flags); + trace->valid = 1; + stream_class->valid = 1; + + /* + * Put what was not moved in bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&trace_sc_validation_output); + + for (i = 0; i < event_class_count; i++) { + struct bt_ctf_event_class_common *event_class = + bt_ctf_stream_class_common_borrow_event_class_by_index( + stream_class, i); + + bt_ctf_validation_replace_types(NULL, NULL, event_class, + &ec_validation_outputs[i], ec_validation_flags); + event_class->valid = 1; + + /* + * Put what was not moved in + * bt_ctf_validation_replace_types(). + */ + bt_ctf_validation_output_put_types(&ec_validation_outputs[i]); + } + + /* + * Freeze the trace and the stream class. + */ + bt_ctf_stream_class_common_freeze(stream_class); + bt_ctf_trace_common_freeze(trace); + + /* + * It is safe to set the stream class's unique clock class + * now because the stream class is frozen. + */ + if (expected_clock_class) { + BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class); + } + + BT_LOGD("Added stream class to trace: " + "trace-addr=%p, trace-name=\"%s\", " + "stream-class-addr=%p, stream-class-name=\"%s\", " + "stream-class-id=%" PRId64, + trace, bt_ctf_trace_common_get_name(trace), + stream_class, bt_ctf_stream_class_common_get_name(stream_class), + bt_ctf_stream_class_common_get_id(stream_class)); + +end: + if (ret) { + bt_ctf_object_set_parent(&stream_class->base, NULL); + + if (ec_validation_outputs) { + for (i = 0; i < event_class_count; i++) { + bt_ctf_validation_output_put_types( + &ec_validation_outputs[i]); + } + } + } + + g_free(ec_validation_outputs); + bt_ctf_validation_output_put_types(&trace_sc_validation_output); + bt_ctf_object_put_ref(expected_clock_class); + return ret; +} + +BT_HIDDEN +bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace, + struct bt_ctf_clock_class *clock_class) +{ + struct bt_ctf_search_query query = { .value = clock_class, .found = 0 }; + + BT_ASSERT(trace); + BT_ASSERT(clock_class); + + g_ptr_array_foreach(trace->clock_classes, value_exists, &query); + return query.found; +} + +BT_HIDDEN +int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace, + enum bt_ctf_byte_order byte_order, bool allow_unspecified) +{ + int ret = 0; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (trace->frozen) { + BT_LOGW("Invalid parameter: trace is frozen: " + "addr=%p, name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace)); + ret = -1; + goto end; + } + + if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) { + BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: " + "addr=%p, name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace)); + ret = -1; + goto end; + } + + if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN && + byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN && + byte_order != BT_CTF_BYTE_ORDER_NETWORK) { + BT_LOGW("Invalid parameter: invalid byte order: " + "addr=%p, name=\"%s\", bo=%s", + trace, bt_ctf_trace_common_get_name(trace), + bt_ctf_byte_order_string(byte_order)); + ret = -1; + goto end; + } + + trace->native_byte_order = byte_order; + BT_LOGV("Set trace's native byte order: " + "addr=%p, name=\"%s\", bo=%s", + trace, bt_ctf_trace_common_get_name(trace), + bt_ctf_byte_order_string(byte_order)); + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace, + struct bt_ctf_field_type_common *packet_header_type) +{ + int ret = 0; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (trace->frozen) { + BT_LOGW("Invalid parameter: trace is frozen: " + "addr=%p, name=\"%s\"", + trace, bt_ctf_trace_common_get_name(trace)); + ret = -1; + goto end; + } + + /* packet_header_type must be a structure. */ + if (packet_header_type && + packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { + BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: " + "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s", + trace, bt_ctf_trace_common_get_name(trace), + packet_header_type, + bt_ctf_field_type_id_string(packet_header_type->id)); + ret = -1; + goto end; + } + + bt_ctf_object_put_ref(trace->packet_header_field_type); + trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type); + BT_LOGV("Set trace's packet header field type: " + "addr=%p, name=\"%s\", packet-context-ft-addr=%p", + trace, bt_ctf_trace_common_get_name(trace), packet_header_type); +end: + return ret; +} + +static +int64_t get_stream_class_count(void *element) +{ + return bt_ctf_trace_get_stream_class_count( + (struct bt_ctf_trace *) element); +} + +static +void *get_stream_class(void *element, int i) +{ + return bt_ctf_trace_get_stream_class_by_index( + (struct bt_ctf_trace *) element, i); +} + +static +int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data) +{ + return bt_ctf_stream_class_visit(object, visitor, data); +} + +int bt_ctf_trace_visit(struct bt_ctf_trace *trace, + bt_ctf_visitor visitor, void *data) +{ + int ret; + struct bt_ctf_visitor_object obj = { + .object = trace, + .type = BT_CTF_VISITOR_OBJECT_TYPE_TRACE + }; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (!visitor) { + BT_LOGW_STR("Invalid parameter: visitor is NULL."); + ret = -1; + goto end; + } + + BT_LOGV("Visiting trace: addr=%p, name=\"%s\"", + trace, bt_ctf_trace_get_name(trace)); + ret = bt_ctf_visitor_helper(&obj, get_stream_class_count, + get_stream_class, visit_stream_class, visitor, data); +end: + return ret; +} + +static +void bt_ctf_trace_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_trace *trace = (void *) obj; + + BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"", + trace, bt_ctf_trace_get_name(trace)); + bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace)); + g_free(trace); +} + +BT_HIDDEN +struct bt_ctf_trace *bt_ctf_trace_create(void) +{ + struct bt_ctf_trace *trace = NULL; + int ret; + + BT_LOGD_STR("Creating CTF writer trace object."); + trace = g_new0(struct bt_ctf_trace, 1); + if (!trace) { + BT_LOGE_STR("Failed to allocate one CTF writer trace."); + goto error; + } + + ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace), + bt_ctf_trace_destroy); + if (ret) { + /* bt_ctf_trace_common_initialize() logs errors */ + goto error; + } + + BT_LOGD("Created CTF writer trace object: addr=%p", trace); + return trace; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(trace); + return trace; +} + +const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace) +{ + return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace)); +} + +int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace, + const unsigned char *uuid) +{ + return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid); +} + +int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace, + const char *name, const char *value) +{ + return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace), + name, value); +} + +int bt_ctf_trace_set_environment_field_integer( + struct bt_ctf_trace *trace, const char *name, int64_t value) +{ + return bt_ctf_trace_common_set_environment_field_integer( + BT_CTF_TO_COMMON(trace), name, value); +} + +int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace) +{ + return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace)); +} + +const char * +bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace, + uint64_t index) +{ + return bt_ctf_trace_common_get_environment_field_name_by_index( + BT_CTF_TO_COMMON(trace), index); +} + +struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index( + struct bt_ctf_trace *trace, uint64_t index) +{ + return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index( + BT_CTF_TO_COMMON(trace), index)); +} + +struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name( + struct bt_ctf_trace *trace, const char *name) +{ + return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name( + BT_CTF_TO_COMMON(trace), name)); +} + +BT_HIDDEN +int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace, + struct bt_ctf_clock_class *clock_class) +{ + return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace), + (void *) clock_class); +} + +BT_HIDDEN +int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace) +{ + return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace)); +} + +BT_HIDDEN +struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index( + struct bt_ctf_trace *trace, uint64_t index) +{ + return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index( + BT_CTF_TO_COMMON(trace), index)); +} + +static +int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_field_type_common *packet_context_type, + struct bt_ctf_field_type_common *event_header_type) +{ + int ret = bt_ctf_stream_class_map_clock_class( + BT_CTF_FROM_COMMON(stream_class), + BT_CTF_FROM_COMMON(packet_context_type), + BT_CTF_FROM_COMMON(event_header_type)); + + if (ret) { + BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class."); + } + + return ret; +} + +int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace, + struct bt_ctf_stream_class *stream_class) +{ + int ret = 0; + struct bt_ctf_clock_class *expected_clock_class = NULL; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + ret = -1; + goto end; + } + + if (!stream_class) { + BT_LOGW_STR("Invalid parameter: stream class is NULL."); + ret = -1; + goto end; + } + + if (stream_class->clock) { + struct bt_ctf_clock_class *stream_clock_class = + stream_class->clock->clock_class; + + /* + * Make sure this clock was also added to the + * trace (potentially through its CTF writer + * owner). + */ + size_t i; + + for (i = 0; i < trace->common.clock_classes->len; i++) { + if (trace->common.clock_classes->pdata[i] == + stream_clock_class) { + /* Found! */ + break; + } + } + + if (i == trace->common.clock_classes->len) { + /* Not found */ + BT_LOGW("Stream class's clock's class is not part of the trace: " + "clock-class-addr=%p, clock-class-name=\"%s\"", + stream_clock_class, + bt_ctf_clock_class_get_name(stream_clock_class)); + ret = -1; + goto end; + } + + if (stream_class->common.clock_class && + stream_class->common.clock_class != + stream_class->clock->clock_class) { + /* + * Stream class already has an expected clock + * class, but it does not match its clock's + * class. + */ + BT_LOGW("Invalid parameter: stream class's clock's " + "class does not match stream class's " + "expected clock class: " + "stream-class-addr=%p, " + "stream-class-id=%" PRId64 ", " + "stream-class-name=\"%s\", " + "expected-clock-class-addr=%p, " + "expected-clock-class-name=\"%s\"", + stream_class, + bt_ctf_stream_class_get_id(stream_class), + bt_ctf_stream_class_get_name(stream_class), + stream_class->common.clock_class, + bt_ctf_clock_class_get_name(stream_class->common.clock_class)); + } else if (!stream_class->common.clock_class) { + /* + * Set expected clock class to stream class's + * clock's class. + */ + expected_clock_class = stream_class->clock->clock_class; + } + } + + + ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace), + BT_CTF_TO_COMMON(stream_class), + (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy, + expected_clock_class, map_clock_classes_func, + false); + +end: + return ret; +} + +int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace) +{ + return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace)); +} + +struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index( + struct bt_ctf_trace *trace, uint64_t index) +{ + return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index( + BT_CTF_TO_COMMON(trace), index)); +} + +int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace) +{ + return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace)); +} + +struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index( + struct bt_ctf_trace *trace, uint64_t index) +{ + return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index( + BT_CTF_TO_COMMON(trace), index)); +} + +struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id( + struct bt_ctf_trace *trace, uint64_t id) +{ + return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id( + BT_CTF_TO_COMMON(trace), id)); +} + +BT_HIDDEN +struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name( + struct bt_ctf_trace *trace, const char *name) +{ + return bt_ctf_object_get_ref( + bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace), + name)); +} + +static +int append_trace_metadata(struct bt_ctf_trace *trace, + struct metadata_context *context) +{ + unsigned char *uuid = trace->common.uuid; + int ret = 0; + + if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE || + trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) { + BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; " + "set it with bt_ctf_trace_set_native_byte_order(): " + "addr=%p, name=\"%s\"", + trace, bt_ctf_trace_get_name(trace)); + ret = -1; + goto end; + } + + g_string_append(context->string, "trace {\n"); + g_string_append(context->string, "\tmajor = 1;\n"); + g_string_append(context->string, "\tminor = 8;\n"); + BT_ASSERT(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN || + trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN || + trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK); + + if (trace->common.uuid_set) { + g_string_append_printf(context->string, + "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + } + + g_string_append_printf(context->string, "\tbyte_order = %s;\n", + bt_ctf_get_byte_order_string(trace->common.native_byte_order)); + + if (trace->common.packet_header_field_type) { + g_string_append(context->string, "\tpacket.header := "); + context->current_indentation_level++; + g_string_assign(context->field_name, ""); + BT_LOGD_STR("Serializing trace's packet header field type's metadata."); + ret = bt_ctf_field_type_serialize_recursive( + (void *) trace->common.packet_header_field_type, + context); + if (ret) { + goto end; + } + context->current_indentation_level--; + } + + g_string_append(context->string, ";\n};\n\n"); +end: + return ret; +} + +static +void append_env_metadata(struct bt_ctf_trace *trace, + struct metadata_context *context) +{ + int64_t i; + int64_t env_size; + + env_size = bt_ctf_attributes_get_count(trace->common.environment); + if (env_size <= 0) { + return; + } + + g_string_append(context->string, "env {\n"); + + for (i = 0; i < env_size; i++) { + struct bt_ctf_private_value *env_field_value_obj = NULL; + const char *entry_name; + + entry_name = bt_ctf_attributes_get_field_name( + trace->common.environment, i); + env_field_value_obj = bt_ctf_attributes_borrow_field_value( + trace->common.environment, i); + + BT_ASSERT(entry_name); + BT_ASSERT(env_field_value_obj); + + switch (bt_ctf_value_get_type( + bt_ctf_private_value_as_value(env_field_value_obj))) { + case BT_CTF_VALUE_TYPE_INTEGER: + { + int64_t int_value; + + int_value = bt_ctf_value_integer_get( + bt_ctf_private_value_as_value( + env_field_value_obj)); + g_string_append_printf(context->string, + "\t%s = %" PRId64 ";\n", entry_name, + int_value); + break; + } + case BT_CTF_VALUE_TYPE_STRING: + { + const char *str_value; + char *escaped_str = NULL; + + str_value = bt_ctf_value_string_get( + bt_ctf_private_value_as_value( + env_field_value_obj)); + escaped_str = g_strescape(str_value, NULL); + if (!escaped_str) { + BT_LOGE("Cannot escape string: string=\"%s\"", + str_value); + continue; + } + + g_string_append_printf(context->string, + "\t%s = \"%s\";\n", entry_name, escaped_str); + free(escaped_str); + break; + } + default: + continue; + } + } + + g_string_append(context->string, "};\n\n"); +} + +char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace) +{ + char *metadata = NULL; + struct metadata_context *context = NULL; + int err = 0; + size_t i; + + if (!trace) { + BT_LOGW_STR("Invalid parameter: trace is NULL."); + goto end; + } + + context = g_new0(struct metadata_context, 1); + if (!context) { + BT_LOGE_STR("Failed to allocate one metadata context."); + goto end; + } + + context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE); + context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE); + g_string_append(context->string, "/* CTF 1.8 */\n\n"); + if (append_trace_metadata(trace, context)) { + /* append_trace_metadata() logs errors */ + goto error; + } + append_env_metadata(trace, context); + g_ptr_array_foreach(trace->common.clock_classes, + (GFunc) bt_ctf_clock_class_serialize, context); + + for (i = 0; i < trace->common.stream_classes->len; i++) { + /* bt_ctf_stream_class_serialize() logs details */ + err = bt_ctf_stream_class_serialize( + trace->common.stream_classes->pdata[i], context); + if (err) { + /* bt_ctf_stream_class_serialize() logs errors */ + goto error; + } + } + + metadata = context->string->str; + +error: + g_string_free(context->string, err ? TRUE : FALSE); + g_string_free(context->field_name, TRUE); + g_free(context); + +end: + return metadata; +} + +enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order( + struct bt_ctf_trace *trace) +{ + return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace)); +} + +int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace, + enum bt_ctf_byte_order byte_order) +{ + return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace), + (int) byte_order, false); +} + +struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type( + struct bt_ctf_trace *trace) +{ + return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type( + BT_CTF_TO_COMMON(trace))); +} + +int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace, + struct bt_ctf_field_type *packet_header_type) +{ + return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace), + (void *) packet_header_type); +} + +const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace) +{ + return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace)); +} diff --git a/ctf-writer/utils.c b/ctf-writer/utils.c new file mode 100644 index 00000000..fdf0a933 --- /dev/null +++ b/ctf-writer/utils.c @@ -0,0 +1,122 @@ +/* + * utils.c + * + * Babeltrace CTF writer - Utilities + * + * Copyright 2015 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-UTILS" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include + +static +const char * const reserved_keywords_str[] = {"align", "callsite", + "const", "char", "clock", "double", "enum", "env", "event", + "floating_point", "float", "integer", "int", "long", "short", "signed", + "stream", "string", "struct", "trace", "typealias", "typedef", + "unsigned", "variant", "void" "_Bool", "_Complex", "_Imaginary"}; + +static GHashTable *reserved_keywords_set; +static int init_done; + +static +void try_init_reserved_keywords(void) +{ + size_t i; + const size_t reserved_keywords_count = + sizeof(reserved_keywords_str) / sizeof(char *); + + if (reserved_keywords_set) { + return; + } + + reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal); + BT_ASSERT(reserved_keywords_set); + + for (i = 0; i < reserved_keywords_count; 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; +} + +static __attribute__((destructor)) +void trace_finalize(void) +{ + if (reserved_keywords_set) { + g_hash_table_destroy(reserved_keywords_set); + } +} + +bt_bool bt_ctf_identifier_is_valid(const char *identifier) +{ + bt_bool is_valid = BT_TRUE; + char *string = NULL; + char *save_ptr, *token; + + if (!identifier) { + BT_LOGV_STR("Invalid parameter: input string is NULL."); + is_valid = BT_FALSE; + goto end; + } + + try_init_reserved_keywords(); + + if (identifier[0] == '\0') { + is_valid = BT_FALSE; + goto end; + } + + string = strdup(identifier); + if (!string) { + BT_LOGE("strdup() failed."); + is_valid = BT_FALSE; + goto end; + } + + token = strtok_r(string, " ", &save_ptr); + while (token) { + if (g_hash_table_lookup_extended(reserved_keywords_set, + GINT_TO_POINTER(g_quark_from_string(token)), + NULL, NULL)) { + is_valid = BT_FALSE; + goto end; + } + + token = strtok_r(NULL, " ", &save_ptr); + } +end: + free(string); + return is_valid; +} diff --git a/ctf-writer/validation.c b/ctf-writer/validation.c new file mode 100644 index 00000000..9c4276eb --- /dev/null +++ b/ctf-writer/validation.c @@ -0,0 +1,652 @@ +/* + * validation.c + * + * Babeltrace - CTF writer: Validation of trace, stream class, and event class + * + * Copyright 2016-2018 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-VALIDATION" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This function resolves and validates the field types of an event + * class. Only `event_context_type` and `event_payload_type` are + * resolved and validated; the other field types are used as eventual + * resolving targets. + * + * All parameters are owned by the caller. + */ +static +int validate_event_class_types(struct bt_ctf_private_value *environment, + struct bt_ctf_field_type_common *packet_header_type, + struct bt_ctf_field_type_common *packet_context_type, + struct bt_ctf_field_type_common *event_header_type, + struct bt_ctf_field_type_common *stream_event_ctx_type, + struct bt_ctf_field_type_common *event_context_type, + struct bt_ctf_field_type_common *event_payload_type) +{ + int ret = 0; + + BT_LOGV("Validating event class field types: " + "packet-header-ft-addr=%p, " + "packet-context-ft-addr=%p, " + "event-header-ft-addr=%p, " + "stream-event-context-ft-addr=%p, " + "event-context-ft-addr=%p, " + "event-payload-ft-addr=%p", + packet_header_type, packet_context_type, event_header_type, + stream_event_ctx_type, event_context_type, event_payload_type); + + /* Resolve sequence type lengths and variant type tags first */ + ret = bt_ctf_resolve_types(environment, packet_header_type, + packet_context_type, event_header_type, stream_event_ctx_type, + event_context_type, event_payload_type, + BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT | + BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD); + if (ret) { + BT_LOGW("Cannot resolve event class field types: ret=%d", + ret); + goto end; + } + + /* Validate field types individually */ + if (event_context_type) { + ret = bt_ctf_field_type_common_validate(event_context_type); + if (ret) { + BT_LOGW("Invalid event class's context field type: " + "ret=%d", ret); + goto end; + } + } + + if (event_payload_type) { + ret = bt_ctf_field_type_common_validate(event_payload_type); + if (ret) { + BT_LOGW("Invalid event class's payload field type: " + "ret=%d", ret); + goto end; + } + } + +end: + return ret; +} + +/* + * This function resolves and validates the field types of a stream + * class. Only `packet_context_type`, `event_header_type`, and + * `stream_event_ctx_type` are resolved and validated; the other field + * type is used as an eventual resolving target. + * + * All parameters are owned by the caller. + */ +static +int validate_stream_class_types(struct bt_ctf_private_value *environment, + struct bt_ctf_field_type_common *packet_header_type, + struct bt_ctf_field_type_common *packet_context_type, + struct bt_ctf_field_type_common *event_header_type, + struct bt_ctf_field_type_common *stream_event_ctx_type) +{ + int ret = 0; + + BT_LOGV("Validating stream class field types: " + "packet-header-ft-addr=%p, " + "packet-context-ft-addr=%p, " + "event-header-ft-addr=%p, " + "stream-event-context-ft-addr=%p", + packet_header_type, packet_context_type, event_header_type, + stream_event_ctx_type); + + /* Resolve sequence type lengths and variant type tags first */ + ret = bt_ctf_resolve_types(environment, packet_header_type, + packet_context_type, event_header_type, stream_event_ctx_type, + NULL, NULL, + BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT | + BT_CTF_RESOLVE_FLAG_EVENT_HEADER | + BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX); + if (ret) { + BT_LOGW("Cannot resolve stream class field types: ret=%d", + ret); + goto end; + } + + /* Validate field types individually */ + if (packet_context_type) { + ret = bt_ctf_field_type_common_validate(packet_context_type); + if (ret) { + BT_LOGW("Invalid stream class's packet context field type: " + "ret=%d", ret); + goto end; + } + } + + if (event_header_type) { + ret = bt_ctf_field_type_common_validate(event_header_type); + if (ret) { + BT_LOGW("Invalid stream class's event header field type: " + "ret=%d", ret); + goto end; + } + } + + if (stream_event_ctx_type) { + ret = bt_ctf_field_type_common_validate( + stream_event_ctx_type); + if (ret) { + BT_LOGW("Invalid stream class's event context field type: " + "ret=%d", ret); + goto end; + } + } + +end: + return ret; +} + +/* + * This function resolves and validates the field types of a trace. + * + * All parameters are owned by the caller. + */ +static +int validate_trace_types(struct bt_ctf_private_value *environment, + struct bt_ctf_field_type_common *packet_header_type) +{ + int ret = 0; + + BT_LOGV("Validating event class field types: " + "packet-header-ft-addr=%p", packet_header_type); + + /* Resolve sequence type lengths and variant type tags first */ + ret = bt_ctf_resolve_types(environment, packet_header_type, + NULL, NULL, NULL, NULL, NULL, + BT_CTF_RESOLVE_FLAG_PACKET_HEADER); + if (ret) { + BT_LOGW("Cannot resolve trace field types: ret=%d", + ret); + goto end; + } + + /* Validate field types individually */ + if (packet_header_type) { + ret = bt_ctf_field_type_common_validate(packet_header_type); + if (ret) { + BT_LOGW("Invalid trace's packet header field type: " + "ret=%d", ret); + goto end; + } + } + +end: + return ret; +} + +/* + * Checks whether or not `field_type` contains a variant or a sequence + * field type, recursively. Returns 1 if it's the case. + * + * `field_type` is owned by the caller. + */ +static +int field_type_contains_sequence_or_variant_ft(struct bt_ctf_field_type_common *type) +{ + int ret = 0; + enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type); + + switch (type_id) { + case BT_CTF_FIELD_TYPE_ID_SEQUENCE: + case BT_CTF_FIELD_TYPE_ID_VARIANT: + ret = 1; + goto end; + case BT_CTF_FIELD_TYPE_ID_ARRAY: + case BT_CTF_FIELD_TYPE_ID_STRUCT: + { + int i; + int field_count = bt_ctf_field_type_common_get_field_count(type); + + if (field_count < 0) { + ret = -1; + goto end; + } + + for (i = 0; i < field_count; ++i) { + struct bt_ctf_field_type_common *child_type = + bt_ctf_field_type_common_borrow_field_at_index( + type, i); + + ret = field_type_contains_sequence_or_variant_ft( + child_type); + if (ret != 0) { + goto end; + } + } + break; + } + default: + break; + } + +end: + return ret; +} + +BT_HIDDEN +int bt_ctf_validate_class_types(struct bt_ctf_private_value *environment, + struct bt_ctf_field_type_common *packet_header_type, + struct bt_ctf_field_type_common *packet_context_type, + struct bt_ctf_field_type_common *event_header_type, + struct bt_ctf_field_type_common *stream_event_ctx_type, + struct bt_ctf_field_type_common *event_context_type, + struct bt_ctf_field_type_common *event_payload_type, + int trace_valid, int stream_class_valid, int event_class_valid, + struct bt_ctf_validation_output *output, + enum bt_ctf_validation_flag validate_flags, + bt_ctf_validation_flag_copy_field_type_func copy_field_type_func) +{ + int ret = 0; + int contains_seq_var; + int valid_ret; + + BT_LOGV("Validating field types: " + "packet-header-ft-addr=%p, " + "packet-context-ft-addr=%p, " + "event-header-ft-addr=%p, " + "stream-event-context-ft-addr=%p, " + "event-context-ft-addr=%p, " + "event-payload-ft-addr=%p, " + "trace-is-valid=%d, stream-class-is-valid=%d, " + "event-class-is-valid=%d, validation-flags=%x", + packet_header_type, packet_context_type, event_header_type, + stream_event_ctx_type, event_context_type, event_payload_type, + trace_valid, stream_class_valid, event_class_valid, + (unsigned int) validate_flags); + + /* Clean output values */ + memset(output, 0, sizeof(*output)); + + /* Set initial valid flags according to valid parameters */ + if (trace_valid) { + output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE; + } + + if (stream_class_valid) { + output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM; + } + + if (event_class_valid) { + output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT; + } + + /* Own the type parameters */ + bt_ctf_object_get_ref(packet_header_type); + bt_ctf_object_get_ref(packet_context_type); + bt_ctf_object_get_ref(event_header_type); + bt_ctf_object_get_ref(stream_event_ctx_type); + bt_ctf_object_get_ref(event_context_type); + bt_ctf_object_get_ref(event_payload_type); + + /* Validate trace */ + if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) { + struct bt_ctf_field_type_common *packet_header_type_copy = NULL; + + /* Create field type copies */ + if (packet_header_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + packet_header_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + packet_header_type_copy = packet_header_type; + bt_ctf_object_get_ref(packet_header_type_copy); + goto skip_packet_header_type_copy; + } + + BT_LOGV_STR("Copying packet header field type because it contains at least one sequence or variant field type."); + packet_header_type_copy = + copy_field_type_func(packet_header_type); + if (!packet_header_type_copy) { + ret = -1; + BT_LOGE_STR("Cannot copy packet header field type."); + goto error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_common_freeze(packet_header_type_copy); + } + +skip_packet_header_type_copy: + /* Put original reference and move copy */ + BT_CTF_OBJECT_MOVE_REF(packet_header_type, packet_header_type_copy); + + /* Validate trace field types */ + valid_ret = validate_trace_types(environment, + packet_header_type); + if (valid_ret == 0) { + /* Trace is valid */ + output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE; + } + } + + /* Validate stream class */ + if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) && + !stream_class_valid) { + struct bt_ctf_field_type_common *packet_context_type_copy = NULL; + struct bt_ctf_field_type_common *event_header_type_copy = NULL; + struct bt_ctf_field_type_common *stream_event_ctx_type_copy = NULL; + + if (packet_context_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + packet_context_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + packet_context_type_copy = packet_context_type; + bt_ctf_object_get_ref(packet_context_type_copy); + goto skip_packet_context_type_copy; + } + + BT_LOGV_STR("Copying packet context field type because it contains at least one sequence or variant field type."); + packet_context_type_copy = + copy_field_type_func(packet_context_type); + if (!packet_context_type_copy) { + BT_LOGE_STR("Cannot copy packet context field type."); + goto sc_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_common_freeze(packet_context_type_copy); + } + +skip_packet_context_type_copy: + if (event_header_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + event_header_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + event_header_type_copy = event_header_type; + bt_ctf_object_get_ref(event_header_type_copy); + goto skip_event_header_type_copy; + } + + BT_LOGV_STR("Copying event header field type because it contains at least one sequence or variant field type."); + event_header_type_copy = + copy_field_type_func(event_header_type); + if (!event_header_type_copy) { + BT_LOGE_STR("Cannot copy event header field type."); + goto sc_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_common_freeze(event_header_type_copy); + } + +skip_event_header_type_copy: + if (stream_event_ctx_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + stream_event_ctx_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + stream_event_ctx_type_copy = + stream_event_ctx_type; + bt_ctf_object_get_ref(stream_event_ctx_type_copy); + goto skip_stream_event_ctx_type_copy; + } + + BT_LOGV_STR("Copying stream event context field type because it contains at least one sequence or variant field type."); + stream_event_ctx_type_copy = + copy_field_type_func(stream_event_ctx_type); + if (!stream_event_ctx_type_copy) { + BT_LOGE_STR("Cannot copy stream event context field type."); + goto sc_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_common_freeze(stream_event_ctx_type_copy); + } + +skip_stream_event_ctx_type_copy: + /* Put original references and move copies */ + BT_CTF_OBJECT_MOVE_REF(packet_context_type, packet_context_type_copy); + BT_CTF_OBJECT_MOVE_REF(event_header_type, event_header_type_copy); + BT_CTF_OBJECT_MOVE_REF(stream_event_ctx_type, stream_event_ctx_type_copy); + + /* Validate stream class field types */ + valid_ret = validate_stream_class_types(environment, + packet_header_type, packet_context_type, + event_header_type, stream_event_ctx_type); + if (valid_ret == 0) { + /* Stream class is valid */ + output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM; + } + + goto sc_validation_done; + +sc_validation_error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type_copy); + BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type_copy); + BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type_copy); + ret = -1; + goto error; + } + +sc_validation_done: + /* Validate event class */ + if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) && + !event_class_valid) { + struct bt_ctf_field_type_common *event_context_type_copy = NULL; + struct bt_ctf_field_type_common *event_payload_type_copy = NULL; + + if (event_context_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + event_context_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + event_context_type_copy = event_context_type; + bt_ctf_object_get_ref(event_context_type_copy); + goto skip_event_context_type_copy; + } + + BT_LOGV_STR("Copying event context field type because it contains at least one sequence or variant field type."); + event_context_type_copy = + copy_field_type_func(event_context_type); + if (!event_context_type_copy) { + BT_LOGE_STR("Cannot copy event context field type."); + goto ec_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_common_freeze(event_context_type_copy); + } + +skip_event_context_type_copy: + if (event_payload_type) { + contains_seq_var = + field_type_contains_sequence_or_variant_ft( + event_payload_type); + if (contains_seq_var < 0) { + ret = contains_seq_var; + goto error; + } else if (!contains_seq_var) { + /* No copy is needed */ + event_payload_type_copy = event_payload_type; + bt_ctf_object_get_ref(event_payload_type_copy); + goto skip_event_payload_type_copy; + } + + BT_LOGV_STR("Copying event payload field type because it contains at least one sequence or variant field type."); + event_payload_type_copy = + copy_field_type_func(event_payload_type); + if (!event_payload_type_copy) { + BT_LOGE_STR("Cannot copy event payload field type."); + goto ec_validation_error; + } + + /* + * Freeze this copy: if it's returned to the + * caller, it cannot be modified any way since + * it will be resolved. + */ + bt_ctf_field_type_common_freeze(event_payload_type_copy); + } + +skip_event_payload_type_copy: + /* Put original references and move copies */ + BT_CTF_OBJECT_MOVE_REF(event_context_type, event_context_type_copy); + BT_CTF_OBJECT_MOVE_REF(event_payload_type, event_payload_type_copy); + + /* Validate event class field types */ + valid_ret = validate_event_class_types(environment, + packet_header_type, packet_context_type, + event_header_type, stream_event_ctx_type, + event_context_type, event_payload_type); + if (valid_ret == 0) { + /* Event class is valid */ + output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT; + } + + goto ec_validation_done; + +ec_validation_error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type_copy); + BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type_copy); + ret = -1; + goto error; + } + +ec_validation_done: + /* + * Validation is complete. Move the field types that were used + * to validate (and that were possibly altered by the validation + * process) to the output values. + */ + BT_CTF_OBJECT_MOVE_REF(output->packet_header_type, packet_header_type); + BT_CTF_OBJECT_MOVE_REF(output->packet_context_type, packet_context_type); + BT_CTF_OBJECT_MOVE_REF(output->event_header_type, event_header_type); + BT_CTF_OBJECT_MOVE_REF(output->stream_event_ctx_type, stream_event_ctx_type); + BT_CTF_OBJECT_MOVE_REF(output->event_context_type, event_context_type); + BT_CTF_OBJECT_MOVE_REF(output->event_payload_type, event_payload_type); + return ret; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_header_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type); + return ret; +} + +BT_HIDDEN +void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace, + struct bt_ctf_stream_class_common *stream_class, + struct bt_ctf_event_class_common *event_class, + struct bt_ctf_validation_output *output, + enum bt_ctf_validation_flag replace_flags) +{ + if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) { + bt_ctf_field_type_common_freeze(trace->packet_header_field_type); + BT_CTF_OBJECT_MOVE_REF(trace->packet_header_field_type, + output->packet_header_type); + } + + if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) { + bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type); + bt_ctf_field_type_common_freeze(stream_class->event_header_field_type); + bt_ctf_field_type_common_freeze(stream_class->event_context_field_type); + BT_CTF_OBJECT_MOVE_REF(stream_class->packet_context_field_type, + output->packet_context_type); + BT_CTF_OBJECT_MOVE_REF(stream_class->event_header_field_type, + output->event_header_type); + BT_CTF_OBJECT_MOVE_REF(stream_class->event_context_field_type, + output->stream_event_ctx_type); + } + + if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) { + bt_ctf_field_type_common_freeze(event_class->context_field_type); + bt_ctf_field_type_common_freeze(event_class->payload_field_type); + BT_CTF_OBJECT_MOVE_REF(event_class->context_field_type, output->event_context_type); + BT_CTF_OBJECT_MOVE_REF(event_class->payload_field_type, output->event_payload_type); + } +} + +BT_HIDDEN +void bt_ctf_validation_output_put_types( + struct bt_ctf_validation_output *output) +{ + BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_header_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_context_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_header_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(output->stream_event_ctx_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_context_type); + BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_payload_type); +} diff --git a/ctf-writer/values.c b/ctf-writer/values.c new file mode 100644 index 00000000..dd8ae949 --- /dev/null +++ b/ctf-writer/values.c @@ -0,0 +1,1344 @@ +/* + * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER-VALUES" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BT_CTF_VALUE_FROM_CONCRETE(_concrete) ((struct bt_ctf_value *) (_concrete)) +#define BT_CTF_VALUE_TO_BOOL(_base) ((struct bt_ctf_value_bool *) (_base)) +#define BT_CTF_VALUE_TO_INTEGER(_base) ((struct bt_ctf_value_integer *) (_base)) +#define BT_CTF_VALUE_TO_REAL(_base) ((struct bt_ctf_value_real *) (_base)) +#define BT_CTF_VALUE_TO_STRING(_base) ((struct bt_ctf_value_string *) (_base)) +#define BT_CTF_VALUE_TO_ARRAY(_base) ((struct bt_ctf_value_array *) (_base)) +#define BT_CTF_VALUE_TO_MAP(_base) ((struct bt_ctf_value_map *) (_base)) + +#define BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(_value, _type) \ + BT_CTF_ASSERT_PRE(((struct bt_ctf_value *) (_value))->type == (_type), \ + "Value has the wrong type ID: expected-type=%d", (_type)) + +#define BT_CTF_ASSERT_PRE_VALUE_HOT(_value, _name) \ + BT_CTF_ASSERT_PRE_HOT(((struct bt_ctf_value *) (_value)), (_name), "") + +#define BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count) \ + BT_CTF_ASSERT_PRE((_index) < (_count), \ + "Index is out of bound: " \ + "index=%" PRIu64 ", count=%u", (_index), (_count)); + +struct bt_ctf_value { + struct bt_ctf_object base; + enum bt_ctf_value_type type; + bt_bool frozen; +}; + +static +void bt_ctf_value_null_instance_release_func(struct bt_ctf_object *obj) +{ + BT_LOGW("Releasing the null value singleton: addr=%p", obj); +} + +static +struct bt_ctf_value bt_ctf_value_null_instance = { + .base = { + .is_shared = true, + .ref_count = 1, + .release_func = bt_ctf_value_null_instance_release_func, + .spec_release_func = NULL, + .parent_is_owner_listener_func = NULL, + .parent = NULL, + }, + .type = BT_CTF_VALUE_TYPE_NULL, + .frozen = BT_TRUE, +}; + +struct bt_ctf_value *const bt_ctf_value_null = &bt_ctf_value_null_instance; +struct bt_ctf_private_value *const bt_ctf_private_value_null = + (void *) &bt_ctf_value_null_instance; + +struct bt_ctf_value_bool { + struct bt_ctf_value base; + bt_bool value; +}; + +struct bt_ctf_value_integer { + struct bt_ctf_value base; + int64_t value; +}; + +struct bt_ctf_value_real { + struct bt_ctf_value base; + double value; +}; + +struct bt_ctf_value_string { + struct bt_ctf_value base; + GString *gstr; +}; + +struct bt_ctf_value_array { + struct bt_ctf_value base; + GPtrArray *garray; +}; + +struct bt_ctf_value_map { + struct bt_ctf_value base; + GHashTable *ght; +}; + +static +void bt_ctf_value_destroy(struct bt_ctf_object *obj); + +static +void bt_ctf_value_string_destroy(struct bt_ctf_value *object) +{ + g_string_free(BT_CTF_VALUE_TO_STRING(object)->gstr, TRUE); + BT_CTF_VALUE_TO_STRING(object)->gstr = NULL; +} + +static +void bt_ctf_value_array_destroy(struct bt_ctf_value *object) +{ + /* + * Pointer array's registered value destructor will take care + * of putting each contained object. + */ + g_ptr_array_free(BT_CTF_VALUE_TO_ARRAY(object)->garray, TRUE); + BT_CTF_VALUE_TO_ARRAY(object)->garray = NULL; +} + +static +void bt_ctf_value_map_destroy(struct bt_ctf_value *object) +{ + /* + * Hash table's registered value destructor will take care of + * putting each contained object. Keys are GQuarks and cannot + * be destroyed anyway. + */ + g_hash_table_destroy(BT_CTF_VALUE_TO_MAP(object)->ght); + BT_CTF_VALUE_TO_MAP(object)->ght = NULL; +} + +static +void (* const destroy_funcs[])(struct bt_ctf_value *) = { + [BT_CTF_VALUE_TYPE_NULL] = NULL, + [BT_CTF_VALUE_TYPE_BOOL] = NULL, + [BT_CTF_VALUE_TYPE_INTEGER] = NULL, + [BT_CTF_VALUE_TYPE_REAL] = NULL, + [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_string_destroy, + [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_destroy, + [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_destroy, +}; + +static +struct bt_ctf_private_value *bt_ctf_value_null_copy(const struct bt_ctf_value *null_obj) +{ + return (void *) bt_ctf_value_null; +} + +static +struct bt_ctf_private_value *bt_ctf_value_bool_copy(const struct bt_ctf_value *bool_obj) +{ + return bt_ctf_private_value_bool_create_init( + BT_CTF_VALUE_TO_BOOL(bool_obj)->value); +} + +static +struct bt_ctf_private_value *bt_ctf_value_integer_copy( + const struct bt_ctf_value *integer_obj) +{ + return bt_ctf_private_value_integer_create_init( + BT_CTF_VALUE_TO_INTEGER(integer_obj)->value); +} + +static +struct bt_ctf_private_value *bt_ctf_value_real_copy(const struct bt_ctf_value *real_obj) +{ + return bt_ctf_private_value_real_create_init( + BT_CTF_VALUE_TO_REAL(real_obj)->value); +} + +static +struct bt_ctf_private_value *bt_ctf_value_string_copy(const struct bt_ctf_value *string_obj) +{ + return bt_ctf_private_value_string_create_init( + BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str); +} + +static +struct bt_ctf_private_value *bt_ctf_value_array_copy(const struct bt_ctf_value *array_obj) +{ + int i; + int ret; + struct bt_ctf_private_value *copy_obj; + struct bt_ctf_value_array *typed_array_obj; + + BT_LOGD("Copying array value: addr=%p", array_obj); + typed_array_obj = BT_CTF_VALUE_TO_ARRAY(array_obj); + copy_obj = bt_ctf_private_value_array_create(); + if (!copy_obj) { + BT_LOGE_STR("Cannot create empty array value."); + goto end; + } + + for (i = 0; i < typed_array_obj->garray->len; ++i) { + struct bt_ctf_private_value *element_obj_copy = NULL; + struct bt_ctf_value *element_obj = + bt_ctf_value_array_borrow_element_by_index( + array_obj, i); + + BT_ASSERT(element_obj); + BT_LOGD("Copying array value's element: element-addr=%p, " + "index=%d", element_obj, i); + ret = bt_ctf_value_copy(&element_obj_copy, element_obj); + if (ret) { + BT_LOGE("Cannot copy array value's element: " + "array-addr=%p, index=%d", + array_obj, i); + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); + goto end; + } + + BT_ASSERT(element_obj_copy); + ret = bt_ctf_private_value_array_append_element(copy_obj, + (void *) element_obj_copy); + BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy); + if (ret) { + BT_LOGE("Cannot append to array value: addr=%p", + array_obj); + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); + goto end; + } + } + + BT_LOGD("Copied array value: original-addr=%p, copy-addr=%p", + array_obj, copy_obj); + +end: + return copy_obj; +} + +static +struct bt_ctf_private_value *bt_ctf_value_map_copy(const struct bt_ctf_value *map_obj) +{ + int ret; + GHashTableIter iter; + gpointer key, element_obj; + struct bt_ctf_private_value *copy_obj; + struct bt_ctf_private_value *element_obj_copy = NULL; + struct bt_ctf_value_map *typed_map_obj; + + BT_LOGD("Copying map value: addr=%p", map_obj); + typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj); + copy_obj = bt_ctf_private_value_map_create(); + if (!copy_obj) { + goto end; + } + + g_hash_table_iter_init(&iter, typed_map_obj->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj)) { + const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key)); + + BT_ASSERT(key_str); + BT_LOGD("Copying map value's element: element-addr=%p, " + "key=\"%s\"", element_obj, key_str); + ret = bt_ctf_value_copy(&element_obj_copy, element_obj); + if (ret) { + BT_LOGE("Cannot copy map value's element: " + "map-addr=%p, key=\"%s\"", + map_obj, key_str); + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); + goto end; + } + + BT_ASSERT(element_obj_copy); + ret = bt_ctf_private_value_map_insert_entry(copy_obj, key_str, + (void *) element_obj_copy); + BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy); + if (ret) { + BT_LOGE("Cannot insert into map value: addr=%p, key=\"%s\"", + map_obj, key_str); + BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); + goto end; + } + } + + BT_LOGD("Copied map value: addr=%p", map_obj); + +end: + return copy_obj; +} + +static +struct bt_ctf_private_value *(* const copy_funcs[])(const struct bt_ctf_value *) = { + [BT_CTF_VALUE_TYPE_NULL] = bt_ctf_value_null_copy, + [BT_CTF_VALUE_TYPE_BOOL] = bt_ctf_value_bool_copy, + [BT_CTF_VALUE_TYPE_INTEGER] = bt_ctf_value_integer_copy, + [BT_CTF_VALUE_TYPE_REAL] = bt_ctf_value_real_copy, + [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_string_copy, + [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_copy, + [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_copy, +}; + +static +bt_bool bt_ctf_value_null_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + /* + * Always BT_TRUE since bt_ctf_value_compare() already checks if both + * object_a and object_b have the same type, and in the case of + * null value objects, they're always the same if it is so. + */ + return BT_TRUE; +} + +static +bt_bool bt_ctf_value_bool_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + if (BT_CTF_VALUE_TO_BOOL(object_a)->value != + BT_CTF_VALUE_TO_BOOL(object_b)->value) { + BT_LOGV("Boolean value objects are different: " + "bool-a-val=%d, bool-b-val=%d", + BT_CTF_VALUE_TO_BOOL(object_a)->value, + BT_CTF_VALUE_TO_BOOL(object_b)->value); + return BT_FALSE; + } + + return BT_TRUE; +} + +static +bt_bool bt_ctf_value_integer_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + if (BT_CTF_VALUE_TO_INTEGER(object_a)->value != + BT_CTF_VALUE_TO_INTEGER(object_b)->value) { + BT_LOGV("Integer value objects are different: " + "int-a-val=%" PRId64 ", int-b-val=%" PRId64, + BT_CTF_VALUE_TO_INTEGER(object_a)->value, + BT_CTF_VALUE_TO_INTEGER(object_b)->value); + return BT_FALSE; + } + + return BT_TRUE; +} + +static +bt_bool bt_ctf_value_real_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + if (BT_CTF_VALUE_TO_REAL(object_a)->value != + BT_CTF_VALUE_TO_REAL(object_b)->value) { + BT_LOGV("Real number value objects are different: " + "real-a-val=%f, real-b-val=%f", + BT_CTF_VALUE_TO_REAL(object_a)->value, + BT_CTF_VALUE_TO_REAL(object_b)->value); + return BT_FALSE; + } + + return BT_TRUE; +} + +static +bt_bool bt_ctf_value_string_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + if (strcmp(BT_CTF_VALUE_TO_STRING(object_a)->gstr->str, + BT_CTF_VALUE_TO_STRING(object_b)->gstr->str) != 0) { + BT_LOGV("String value objects are different: " + "string-a-val=\"%s\", string-b-val=\"%s\"", + BT_CTF_VALUE_TO_STRING(object_a)->gstr->str, + BT_CTF_VALUE_TO_STRING(object_b)->gstr->str); + return BT_FALSE; + } + + return BT_TRUE; +} + +static +bt_bool bt_ctf_value_array_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + int i; + bt_bool ret = BT_TRUE; + const struct bt_ctf_value_array *array_obj_a = + BT_CTF_VALUE_TO_ARRAY(object_a); + + if (bt_ctf_value_array_get_size(object_a) != + bt_ctf_value_array_get_size(object_b)) { + BT_LOGV("Array values are different: size mismatch " + "value-a-addr=%p, value-b-addr=%p, " + "value-a-size=%" PRId64 ", value-b-size=%" PRId64, + object_a, object_b, + bt_ctf_value_array_get_size(object_a), + bt_ctf_value_array_get_size(object_b)); + ret = BT_FALSE; + goto end; + } + + for (i = 0; i < array_obj_a->garray->len; ++i) { + struct bt_ctf_value *element_obj_a; + struct bt_ctf_value *element_obj_b; + + element_obj_a = bt_ctf_value_array_borrow_element_by_index( + object_a, i); + element_obj_b = bt_ctf_value_array_borrow_element_by_index( + object_b, i); + + if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) { + BT_LOGV("Array values's elements are different: " + "value-a-addr=%p, value-b-addr=%p, index=%d", + element_obj_a, element_obj_b, i); + ret = BT_FALSE; + goto end; + } + } + +end: + return ret; +} + +static +bt_bool bt_ctf_value_map_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + bt_bool ret = BT_TRUE; + GHashTableIter iter; + gpointer key, element_obj_a; + const struct bt_ctf_value_map *map_obj_a = BT_CTF_VALUE_TO_MAP(object_a); + + if (bt_ctf_value_map_get_size(object_a) != + bt_ctf_value_map_get_size(object_b)) { + BT_LOGV("Map values are different: size mismatch " + "value-a-addr=%p, value-b-addr=%p, " + "value-a-size=%" PRId64 ", value-b-size=%" PRId64, + object_a, object_b, + bt_ctf_value_map_get_size(object_a), + bt_ctf_value_map_get_size(object_b)); + ret = BT_FALSE; + goto end; + } + + g_hash_table_iter_init(&iter, map_obj_a->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) { + struct bt_ctf_value *element_obj_b; + const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key)); + + element_obj_b = bt_ctf_value_map_borrow_entry_value(object_b, + key_str); + + if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) { + BT_LOGV("Map values's elements are different: " + "value-a-addr=%p, value-b-addr=%p, key=\"%s\"", + element_obj_a, element_obj_b, key_str); + ret = BT_FALSE; + goto end; + } + } + +end: + return ret; +} + +static +bt_bool (* const compare_funcs[])(const struct bt_ctf_value *, + const struct bt_ctf_value *) = { + [BT_CTF_VALUE_TYPE_NULL] = bt_ctf_value_null_compare, + [BT_CTF_VALUE_TYPE_BOOL] = bt_ctf_value_bool_compare, + [BT_CTF_VALUE_TYPE_INTEGER] = bt_ctf_value_integer_compare, + [BT_CTF_VALUE_TYPE_REAL] = bt_ctf_value_real_compare, + [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_string_compare, + [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_compare, + [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_compare, +}; + +static +void bt_ctf_value_null_freeze(struct bt_ctf_value *object) +{ +} + +static +void bt_ctf_value_generic_freeze(struct bt_ctf_value *object) +{ + object->frozen = BT_TRUE; +} + +static +void bt_ctf_value_array_freeze(struct bt_ctf_value *object) +{ + int i; + struct bt_ctf_value_array *typed_array_obj = + BT_CTF_VALUE_TO_ARRAY(object); + + for (i = 0; i < typed_array_obj->garray->len; ++i) { + bt_ctf_value_freeze(g_ptr_array_index(typed_array_obj->garray, i)); + } + + bt_ctf_value_generic_freeze(object); +} + +static +void bt_ctf_value_map_freeze(struct bt_ctf_value *object) +{ + GHashTableIter iter; + gpointer key, element_obj; + const struct bt_ctf_value_map *map_obj = BT_CTF_VALUE_TO_MAP(object); + + g_hash_table_iter_init(&iter, map_obj->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj)) { + bt_ctf_value_freeze(element_obj); + } + + bt_ctf_value_generic_freeze(object); +} + +static +void (* const freeze_funcs[])(struct bt_ctf_value *) = { + [BT_CTF_VALUE_TYPE_NULL] = bt_ctf_value_null_freeze, + [BT_CTF_VALUE_TYPE_BOOL] = bt_ctf_value_generic_freeze, + [BT_CTF_VALUE_TYPE_INTEGER] = bt_ctf_value_generic_freeze, + [BT_CTF_VALUE_TYPE_REAL] = bt_ctf_value_generic_freeze, + [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_generic_freeze, + [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_freeze, + [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_freeze, +}; + +static +void bt_ctf_value_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_value *value; + + value = container_of(obj, struct bt_ctf_value, base); + BT_LOGD("Destroying value: addr=%p", value); + + if (bt_ctf_value_is_null(value)) { + BT_LOGD_STR("Not destroying the null value singleton."); + return; + } + + if (destroy_funcs[value->type]) { + destroy_funcs[value->type](value); + } + + g_free(value); +} + +BT_HIDDEN +enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object) +{ + enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK; + + BT_ASSERT(object); + + if (object->frozen) { + goto end; + } + + BT_LOGD("Freezing value: addr=%p", object); + freeze_funcs[object->type](object); + +end: + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object) +{ + BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object"); + return object->type; +} + +static +struct bt_ctf_value bt_ctf_value_create_base(enum bt_ctf_value_type type) +{ + struct bt_ctf_value value; + + value.type = type; + value.frozen = BT_FALSE; + bt_ctf_object_init_shared(&value.base, bt_ctf_value_destroy); + return value; +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val) +{ + struct bt_ctf_value_bool *bool_obj; + + BT_LOGD("Creating boolean value object: val=%d", val); + bool_obj = g_new0(struct bt_ctf_value_bool, 1); + if (!bool_obj) { + BT_LOGE_STR("Failed to allocate one boolean value object."); + goto end; + } + + bool_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_BOOL); + bool_obj->value = val; + BT_LOGD("Created boolean value object: addr=%p", bool_obj); + +end: + return (void *) BT_CTF_VALUE_FROM_CONCRETE(bool_obj); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void) +{ + return bt_ctf_private_value_bool_create_init(BT_FALSE); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(int64_t val) +{ + struct bt_ctf_value_integer *integer_obj; + + BT_LOGD("Creating integer value object: val=%" PRId64, val); + integer_obj = g_new0(struct bt_ctf_value_integer, 1); + if (!integer_obj) { + BT_LOGE_STR("Failed to allocate one integer value object."); + goto end; + } + + integer_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_INTEGER); + integer_obj->value = val; + BT_LOGD("Created integer value object: addr=%p", + integer_obj); + +end: + return (void *) BT_CTF_VALUE_FROM_CONCRETE(integer_obj); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void) +{ + return bt_ctf_private_value_integer_create_init(0); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val) +{ + struct bt_ctf_value_real *real_obj; + + BT_LOGD("Creating real number value object: val=%f", val); + real_obj = g_new0(struct bt_ctf_value_real, 1); + if (!real_obj) { + BT_LOGE_STR("Failed to allocate one real number value object."); + goto end; + } + + real_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_REAL); + real_obj->value = val; + BT_LOGD("Created real number value object: addr=%p", + real_obj); + +end: + return (void *) BT_CTF_VALUE_FROM_CONCRETE(real_obj); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_real_create(void) +{ + return bt_ctf_private_value_real_create_init(0.); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(const char *val) +{ + struct bt_ctf_value_string *string_obj = NULL; + + if (!val) { + BT_LOGW_STR("Invalid parameter: value is NULL."); + goto end; + } + + BT_LOGD("Creating string value object: val-len=%zu", strlen(val)); + string_obj = g_new0(struct bt_ctf_value_string, 1); + if (!string_obj) { + BT_LOGE_STR("Failed to allocate one string object."); + goto end; + } + + string_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_STRING); + string_obj->gstr = g_string_new(val); + if (!string_obj->gstr) { + BT_LOGE_STR("Failed to allocate a GString."); + g_free(string_obj); + string_obj = NULL; + goto end; + } + + BT_LOGD("Created string value object: addr=%p", + string_obj); + +end: + return (void *) BT_CTF_VALUE_FROM_CONCRETE(string_obj); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_string_create(void) +{ + return bt_ctf_private_value_string_create_init(""); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_array_create(void) +{ + struct bt_ctf_value_array *array_obj; + + BT_LOGD_STR("Creating empty array value object."); + array_obj = g_new0(struct bt_ctf_value_array, 1); + if (!array_obj) { + BT_LOGE_STR("Failed to allocate one array object."); + goto end; + } + + array_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_ARRAY); + array_obj->garray = bt_g_ptr_array_new_full(0, + (GDestroyNotify) bt_ctf_object_put_ref); + if (!array_obj->garray) { + BT_LOGE_STR("Failed to allocate a GPtrArray."); + g_free(array_obj); + array_obj = NULL; + goto end; + } + + BT_LOGD("Created array value object: addr=%p", + array_obj); + +end: + return (void *) BT_CTF_VALUE_FROM_CONCRETE(array_obj); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_map_create(void) +{ + struct bt_ctf_value_map *map_obj; + + BT_LOGD_STR("Creating empty map value object."); + map_obj = g_new0(struct bt_ctf_value_map, 1); + if (!map_obj) { + BT_LOGE_STR("Failed to allocate one map object."); + goto end; + } + + map_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_MAP); + map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) bt_ctf_object_put_ref); + if (!map_obj->ght) { + BT_LOGE_STR("Failed to allocate a GHashTable."); + g_free(map_obj); + map_obj = NULL; + goto end; + } + + BT_LOGD("Created map value object: addr=%p", + map_obj); + +end: + return (void *) BT_CTF_VALUE_FROM_CONCRETE(map_obj); +} + +BT_HIDDEN +bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj) +{ + BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL); + return BT_CTF_VALUE_TO_BOOL(bool_obj)->value; +} + +BT_HIDDEN +void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj, bt_bool val) +{ + BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL); + BT_CTF_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object"); + BT_CTF_VALUE_TO_BOOL(bool_obj)->value = val; + BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d", + bool_obj, val); +} + +BT_HIDDEN +int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj) +{ + BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER); + return BT_CTF_VALUE_TO_INTEGER(integer_obj)->value; +} + +BT_HIDDEN +void bt_ctf_private_value_integer_set(struct bt_ctf_private_value *integer_obj, + int64_t val) +{ + BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER); + BT_CTF_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object"); + BT_CTF_VALUE_TO_INTEGER(integer_obj)->value = val; + BT_LOGV("Set integer value's raw value: value-addr=%p, value=%" PRId64, + integer_obj, val); +} + +BT_HIDDEN +double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj) +{ + BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL); + return BT_CTF_VALUE_TO_REAL(real_obj)->value; +} + +BT_HIDDEN +void bt_ctf_private_value_real_set(struct bt_ctf_private_value *real_obj, double val) +{ + BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL); + BT_CTF_ASSERT_PRE_VALUE_HOT(real_obj, "Value object"); + BT_CTF_VALUE_TO_REAL(real_obj)->value = val; + BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f", + real_obj, val); +} + +BT_HIDDEN +const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj) +{ + BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING); + return BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_string_set( + struct bt_ctf_private_value *string_obj, const char *val) +{ + BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING); + BT_CTF_ASSERT_PRE_VALUE_HOT(string_obj, "Value object"); + g_string_assign(BT_CTF_VALUE_TO_STRING(string_obj)->gstr, val); + BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p", + string_obj, val); + return BT_CTF_VALUE_STATUS_OK; +} + +BT_HIDDEN +uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj) +{ + BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); + return (uint64_t) BT_CTF_VALUE_TO_ARRAY(array_obj)->garray->len; +} + +BT_HIDDEN +struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index( + const struct bt_ctf_value *array_obj, + uint64_t index) +{ + struct bt_ctf_value_array *typed_array_obj = + BT_CTF_VALUE_TO_ARRAY(array_obj); + + BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); + BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index, + typed_array_obj->garray->len); + return g_ptr_array_index(typed_array_obj->garray, index); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index( + const struct bt_ctf_private_value *array_obj, + uint64_t index) +{ + return (void *) bt_ctf_value_array_borrow_element_by_index( + (void *) array_obj, index); +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_append_element( + struct bt_ctf_private_value *array_obj, + struct bt_ctf_value *element_obj) +{ + struct bt_ctf_value_array *typed_array_obj = + BT_CTF_VALUE_TO_ARRAY(array_obj); + + BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object"); + BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); + BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object"); + g_ptr_array_add(typed_array_obj->garray, element_obj); + bt_ctf_object_get_ref(element_obj); + BT_LOGV("Appended element to array value: array-value-addr=%p, " + "element-value-addr=%p, new-size=%u", + array_obj, element_obj, typed_array_obj->garray->len); + return BT_CTF_VALUE_STATUS_OK; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element( + struct bt_ctf_private_value *array_obj, bt_bool val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *bool_obj = NULL; + + bool_obj = bt_ctf_private_value_bool_create_init(val); + ret = bt_ctf_private_value_array_append_element(array_obj, + (void *) bool_obj); + bt_ctf_object_put_ref(bool_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element( + struct bt_ctf_private_value *array_obj, int64_t val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *integer_obj = NULL; + + integer_obj = bt_ctf_private_value_integer_create_init(val); + ret = bt_ctf_private_value_array_append_element(array_obj, + (void *) integer_obj); + bt_ctf_object_put_ref(integer_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element( + struct bt_ctf_private_value *array_obj, double val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *real_obj = NULL; + + real_obj = bt_ctf_private_value_real_create_init(val); + ret = bt_ctf_private_value_array_append_element(array_obj, + (void *) real_obj); + bt_ctf_object_put_ref(real_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element( + struct bt_ctf_private_value *array_obj, const char *val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *string_obj = NULL; + + string_obj = bt_ctf_private_value_string_create_init(val); + ret = bt_ctf_private_value_array_append_element(array_obj, + (void *) string_obj); + bt_ctf_object_put_ref(string_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element( + struct bt_ctf_private_value *array_obj) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *empty_array_obj = NULL; + + empty_array_obj = bt_ctf_private_value_array_create(); + ret = bt_ctf_private_value_array_append_element(array_obj, + (void *) empty_array_obj); + bt_ctf_object_put_ref(empty_array_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element( + struct bt_ctf_private_value *array_obj) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *map_obj = NULL; + + map_obj = bt_ctf_private_value_map_create(); + ret = bt_ctf_private_value_array_append_element(array_obj, + (void *) map_obj); + bt_ctf_object_put_ref(map_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index( + struct bt_ctf_private_value *array_obj, uint64_t index, + struct bt_ctf_value *element_obj) +{ + struct bt_ctf_value_array *typed_array_obj = + BT_CTF_VALUE_TO_ARRAY(array_obj); + + BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object"); + BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); + BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object"); + BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index, + typed_array_obj->garray->len); + bt_ctf_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index)); + g_ptr_array_index(typed_array_obj->garray, index) = element_obj; + bt_ctf_object_get_ref(element_obj); + BT_LOGV("Set array value's element: array-value-addr=%p, " + "index=%" PRIu64 ", element-value-addr=%p", + array_obj, index, element_obj); + return BT_CTF_VALUE_STATUS_OK; +} + +BT_HIDDEN +uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj) +{ + BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); + return (uint64_t) g_hash_table_size(BT_CTF_VALUE_TO_MAP(map_obj)->ght); +} + +BT_HIDDEN +struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(const struct bt_ctf_value *map_obj, + const char *key) +{ + BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object"); + BT_CTF_ASSERT_PRE_NON_NULL(key, "Key"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); + return g_hash_table_lookup(BT_CTF_VALUE_TO_MAP(map_obj)->ght, + GUINT_TO_POINTER(g_quark_from_string(key))); +} + +BT_HIDDEN +struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value( + const struct bt_ctf_private_value *map_obj, const char *key) +{ + return (void *) bt_ctf_value_map_borrow_entry_value((void *) map_obj, key); +} + +BT_HIDDEN +bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj, const char *key) +{ + BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object"); + BT_CTF_ASSERT_PRE_NON_NULL(key, "Key"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); + return bt_g_hash_table_contains(BT_CTF_VALUE_TO_MAP(map_obj)->ght, + GUINT_TO_POINTER(g_quark_from_string(key))); +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry( + struct bt_ctf_private_value *map_obj, + const char *key, struct bt_ctf_value *element_obj) +{ + BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Map value object"); + BT_CTF_ASSERT_PRE_NON_NULL(key, "Key"); + BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); + BT_CTF_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object"); + g_hash_table_insert(BT_CTF_VALUE_TO_MAP(map_obj)->ght, + GUINT_TO_POINTER(g_quark_from_string(key)), element_obj); + bt_ctf_object_get_ref(element_obj); + BT_LOGV("Inserted value into map value: map-value-addr=%p, " + "key=\"%s\", element-value-addr=%p", + map_obj, key, element_obj); + return BT_CTF_VALUE_STATUS_OK; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry( + struct bt_ctf_private_value *map_obj, const char *key, bt_bool val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *bool_obj = NULL; + + bool_obj = bt_ctf_private_value_bool_create_init(val); + ret = bt_ctf_private_value_map_insert_entry(map_obj, key, + (void *) bool_obj); + bt_ctf_object_put_ref(bool_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry( + struct bt_ctf_private_value *map_obj, const char *key, int64_t val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *integer_obj = NULL; + + integer_obj = bt_ctf_private_value_integer_create_init(val); + ret = bt_ctf_private_value_map_insert_entry(map_obj, key, + (void *) integer_obj); + bt_ctf_object_put_ref(integer_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry( + struct bt_ctf_private_value *map_obj, const char *key, double val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *real_obj = NULL; + + real_obj = bt_ctf_private_value_real_create_init(val); + ret = bt_ctf_private_value_map_insert_entry(map_obj, key, + (void *) real_obj); + bt_ctf_object_put_ref(real_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry( + struct bt_ctf_private_value *map_obj, const char *key, + const char *val) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *string_obj = NULL; + + string_obj = bt_ctf_private_value_string_create_init(val); + ret = bt_ctf_private_value_map_insert_entry(map_obj, key, + (void *) string_obj); + bt_ctf_object_put_ref(string_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry( + struct bt_ctf_private_value *map_obj, const char *key) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *array_obj = NULL; + + array_obj = bt_ctf_private_value_array_create(); + ret = bt_ctf_private_value_map_insert_entry(map_obj, key, + (void *) array_obj); + bt_ctf_object_put_ref(array_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry( + struct bt_ctf_private_value *map_obj, const char *key) +{ + enum bt_ctf_value_status ret; + struct bt_ctf_private_value *empty_map_obj = NULL; + + empty_map_obj = bt_ctf_private_value_map_create(); + ret = bt_ctf_private_value_map_insert_entry(map_obj, key, + (void *) empty_map_obj); + bt_ctf_object_put_ref(empty_map_obj); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(const struct bt_ctf_value *map_obj, + bt_ctf_value_map_foreach_entry_cb cb, void *data) +{ + enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK; + gpointer key, element_obj; + GHashTableIter iter; + struct bt_ctf_value_map *typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj); + + BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object"); + BT_CTF_ASSERT_PRE_NON_NULL(cb, "Callback"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); + g_hash_table_iter_init(&iter, typed_map_obj->ght); + + while (g_hash_table_iter_next(&iter, &key, &element_obj)) { + const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key)); + + if (!cb(key_str, element_obj, data)) { + BT_LOGV("User canceled the loop: key=\"%s\", " + "value-addr=%p, data=%p", + key_str, element_obj, data); + ret = BT_CTF_VALUE_STATUS_CANCELED; + break; + } + } + + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry( + const struct bt_ctf_private_value *map_obj, + bt_ctf_private_value_map_foreach_entry_cb cb, void *data) +{ + return bt_ctf_value_map_foreach_entry((void *) map_obj, + (bt_ctf_value_map_foreach_entry_cb) cb, data); +} + +struct extend_map_element_data { + struct bt_ctf_private_value *extended_obj; + enum bt_ctf_value_status status; +}; + +static +bt_bool extend_map_element(const char *key, + struct bt_ctf_value *extension_obj_elem, void *data) +{ + bt_bool ret = BT_TRUE; + struct extend_map_element_data *extend_data = data; + struct bt_ctf_private_value *extension_obj_elem_copy = NULL; + + /* Copy object which is to replace the current one */ + extend_data->status = bt_ctf_value_copy(&extension_obj_elem_copy, + extension_obj_elem); + if (extend_data->status) { + BT_LOGE("Cannot copy map element: addr=%p", + extension_obj_elem); + goto error; + } + + BT_ASSERT(extension_obj_elem_copy); + + /* Replace in extended object */ + extend_data->status = bt_ctf_private_value_map_insert_entry( + extend_data->extended_obj, key, + (void *) extension_obj_elem_copy); + if (extend_data->status) { + BT_LOGE("Cannot replace value in extended value: key=\"%s\", " + "extended-value-addr=%p, element-value-addr=%p", + key, extend_data->extended_obj, + extension_obj_elem_copy); + goto error; + } + + goto end; + +error: + BT_ASSERT(extend_data->status != BT_CTF_VALUE_STATUS_OK); + ret = BT_FALSE; + +end: + BT_CTF_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy); + return ret; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_value_map_extend( + struct bt_ctf_private_value **extended_map_obj, + const struct bt_ctf_value *base_map_obj, + const struct bt_ctf_value *extension_obj) +{ + struct extend_map_element_data extend_data = { + .extended_obj = NULL, + .status = BT_CTF_VALUE_STATUS_OK, + }; + + BT_CTF_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object"); + BT_CTF_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object"); + BT_CTF_ASSERT_PRE_NON_NULL(extended_map_obj, + "Extended value object (output)"); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_CTF_VALUE_TYPE_MAP); + BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_CTF_VALUE_TYPE_MAP); + BT_LOGD("Extending map value: base-value-addr=%p, extension-value-addr=%p", + base_map_obj, extension_obj); + *extended_map_obj = NULL; + + /* Create copy of base map object to start with */ + extend_data.status = bt_ctf_value_copy(extended_map_obj, base_map_obj); + if (extend_data.status) { + BT_LOGE("Cannot copy base value: base-value-addr=%p", + base_map_obj); + goto error; + } + + BT_ASSERT(extended_map_obj); + + /* + * For each key in the extension map object, replace this key + * in the copied map object. + */ + extend_data.extended_obj = *extended_map_obj; + + if (bt_ctf_value_map_foreach_entry(extension_obj, extend_map_element, + &extend_data)) { + BT_LOGE("Cannot iterate on the extension object's elements: " + "extension-value-addr=%p", extension_obj); + goto error; + } + + if (extend_data.status) { + BT_LOGE("Failed to successfully iterate on the extension object's elements: " + "extension-value-addr=%p", extension_obj); + goto error; + } + + BT_LOGD("Extended map value: extended-value-addr=%p", + *extended_map_obj); + goto end; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(*extended_map_obj); + *extended_map_obj = NULL; + +end: + return extend_data.status; +} + +BT_HIDDEN +enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy_obj, + const struct bt_ctf_value *object) +{ + enum bt_ctf_value_status status = BT_CTF_VALUE_STATUS_OK; + + BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object"); + BT_CTF_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)"); + BT_LOGD("Copying value object: addr=%p", object); + *copy_obj = copy_funcs[object->type](object); + if (*copy_obj) { + BT_LOGD("Copied value object: copy-value-addr=%p", + copy_obj); + } else { + status = BT_CTF_VALUE_STATUS_NOMEM; + *copy_obj = NULL; + BT_LOGE_STR("Failed to copy value object."); + } + + return status; +} + +BT_HIDDEN +bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a, + const struct bt_ctf_value *object_b) +{ + bt_bool ret = BT_FALSE; + + BT_CTF_ASSERT_PRE_NON_NULL(object_a, "Value object A"); + BT_CTF_ASSERT_PRE_NON_NULL(object_b, "Value object B"); + + if (object_a->type != object_b->type) { + BT_LOGV("Values are different: type mismatch: " + "value-a-addr=%p, value-b-addr=%p, " + "value-a-type=%d, value-b-type=%d", + object_a, object_b, object_a->type, object_b->type); + goto end; + } + + ret = compare_funcs[object_a->type](object_a, object_b); + +end: + return ret; +} diff --git a/ctf-writer/visitor.c b/ctf-writer/visitor.c new file mode 100644 index 00000000..707cc7a8 --- /dev/null +++ b/ctf-writer/visitor.c @@ -0,0 +1,96 @@ +/* + * visitor.c + * + * Babeltrace CTF writer - Visitor + * + * Copyright 2016 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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 + +BT_HIDDEN +int bt_ctf_visitor_helper(struct bt_ctf_visitor_object *root, + bt_ctf_child_count_accessor child_counter, + bt_ctf_child_accessor child_accessor, + bt_ctf_child_visitor child_visitor, + bt_ctf_visitor visitor, + void *data) +{ + int ret, child_count, i; + + ret = visitor(root, data); + if (ret) { + goto end; + } + + child_count = child_counter(root->object); + if (child_count < 0) { + ret = child_count; + goto end; + } + + for (i = 0; i < child_count; i++) { + void *child; + + child = child_accessor(root->object, i); + if (!child) { + ret = -1; + goto end; + } + ret = child_visitor(child, visitor, data); + BT_CTF_OBJECT_PUT_REF_AND_RESET(child); + if (ret) { + goto end; + } + } +end: + return ret; +} + +enum bt_ctf_visitor_object_type bt_ctf_visitor_object_get_type( + struct bt_ctf_visitor_object *object) +{ + enum bt_ctf_visitor_object_type ret = BT_CTF_VISITOR_OBJECT_TYPE_UNKNOWN; + + if (!object) { + goto end; + } + + ret = object->type; +end: + return ret; +} + +void *bt_ctf_visitor_object_get_object(struct bt_ctf_visitor_object *object) +{ + void *ret = NULL; + + if (!object) { + goto end; + } + + ret = object->object; +end: + return ret; +} diff --git a/ctf-writer/writer.c b/ctf-writer/writer.c new file mode 100644 index 00000000..949bbea2 --- /dev/null +++ b/ctf-writer/writer.c @@ -0,0 +1,455 @@ +/* + * writer.c + * + * Babeltrace CTF Writer + * + * Copyright 2013, 2014 Jérémie Galarneau + * + * Author: Jérémie Galarneau + * + * 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. + */ + +#define BT_LOG_TAG "CTF-WRITER" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_ctf_writer_destroy(struct bt_ctf_object *obj); + +static +int init_trace_packet_header(struct bt_ctf_trace *trace) +{ + int ret = 0; + struct bt_ctf_field_type *_uint32_t = + get_field_type(FIELD_TYPE_ALIAS_UINT32_T); + struct bt_ctf_field_type *_uint8_t = + get_field_type(FIELD_TYPE_ALIAS_UINT8_T); + struct bt_ctf_field_type *trace_packet_header_type = + bt_ctf_field_type_structure_create(); + struct bt_ctf_field_type *uuid_array_type = + bt_ctf_field_type_array_create(_uint8_t, 16); + + if (!trace_packet_header_type || !uuid_array_type) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, + _uint32_t, "magic"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, + uuid_array_type, "uuid"); + if (ret) { + goto end; + } + + ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, + _uint32_t, "stream_id"); + if (ret) { + goto end; + } + + ret = bt_ctf_trace_set_packet_header_field_type(trace, + trace_packet_header_type); + if (ret) { + goto end; + } +end: + bt_ctf_object_put_ref(uuid_array_type); + bt_ctf_object_put_ref(_uint32_t); + bt_ctf_object_put_ref(_uint8_t); + bt_ctf_object_put_ref(trace_packet_header_type); + return ret; +} + +struct bt_ctf_writer *bt_ctf_writer_create(const char *path) +{ + int ret; + struct bt_ctf_writer *writer = NULL; + unsigned char uuid[16]; + char *metadata_path = NULL; + + if (!path) { + goto error; + } + + writer = g_new0(struct bt_ctf_writer, 1); + if (!writer) { + goto error; + } + + metadata_path = g_build_filename(path, "metadata", NULL); + + bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy); + writer->path = g_string_new(path); + if (!writer->path) { + goto error_destroy; + } + + writer->trace = bt_ctf_trace_create(); + if (!writer->trace) { + goto error_destroy; + } + + ret = init_trace_packet_header(writer->trace); + if (ret) { + goto error_destroy; + } + + /* Generate a UUID for this writer's trace */ + ret = bt_uuid_generate(uuid); + if (ret) { + BT_LOGE_STR("Cannot generate UUID for CTF writer's trace."); + goto error_destroy; + } + + ret = bt_ctf_trace_set_uuid(writer->trace, uuid); + if (ret) { + goto error_destroy; + } + + bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base); + bt_ctf_object_put_ref(writer->trace); + + /* Default to little-endian */ + ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE); + BT_ASSERT(ret == 0); + + /* Create trace directory if necessary and open a metadata file */ + if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) { + perror("g_mkdir_with_parents"); + goto error_destroy; + } + + writer->metadata_fd = open(metadata_path, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (writer->metadata_fd < 0) { + perror("open"); + goto error_destroy; + } + + g_free(metadata_path); + return writer; + +error_destroy: + BT_CTF_OBJECT_PUT_REF_AND_RESET(writer); +error: + g_free(metadata_path); + return writer; +} + +void bt_ctf_writer_destroy(struct bt_ctf_object *obj) +{ + struct bt_ctf_writer *writer; + + writer = container_of(obj, struct bt_ctf_writer, base); + bt_ctf_writer_flush_metadata(writer); + if (writer->path) { + g_string_free(writer->path, TRUE); + } + + if (writer->metadata_fd > 0) { + if (close(writer->metadata_fd)) { + perror("close"); + } + } + + bt_ctf_object_try_spec_release(&writer->trace->common.base); + g_free(writer); +} + +struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer) +{ + struct bt_ctf_trace *trace = NULL; + + if (!writer) { + goto end; + } + + trace = writer->trace; + bt_ctf_object_get_ref(trace); +end: + return trace; +} + +struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, + struct bt_ctf_stream_class *stream_class) +{ + struct bt_ctf_stream *stream = NULL; + int stream_class_count; + bt_bool stream_class_found = BT_FALSE; + int i; + + if (!writer || !stream_class) { + goto error; + } + + /* Make sure the stream class is part of the writer's trace */ + stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace); + if (stream_class_count < 0) { + goto error; + } + + for (i = 0; i < stream_class_count; i++) { + struct bt_ctf_stream_class *existing_stream_class = + bt_ctf_trace_get_stream_class_by_index( + writer->trace, i); + + if (existing_stream_class == stream_class) { + stream_class_found = BT_TRUE; + } + + BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class); + + if (stream_class_found) { + break; + } + } + + if (!stream_class_found) { + int ret = bt_ctf_trace_add_stream_class(writer->trace, + stream_class); + + if (ret) { + goto error; + } + } + + stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL); + if (!stream) { + goto error; + } + + return stream; + +error: + BT_CTF_OBJECT_PUT_REF_AND_RESET(stream); + return stream; +} + +int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer, + const char *name, + const char *value) +{ + int ret = -1; + + if (!writer || !name || !value) { + goto end; + } + + ret = bt_ctf_trace_set_environment_field_string(writer->trace, + name, value); +end: + return ret; +} + +int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer, + const char *name, int64_t value) +{ + int ret = -1; + + if (!writer || !name) { + goto end; + } + + ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name, + value); +end: + return ret; +} + +int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer, + struct bt_ctf_clock *clock) +{ + int ret = -1; + + if (!writer || !clock) { + goto end; + } + + ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class); +end: + return ret; +} + +char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer) +{ + char *metadata_string = NULL; + + if (!writer) { + goto end; + } + + metadata_string = bt_ctf_trace_get_metadata_string( + writer->trace); +end: + return metadata_string; +} + +void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer) +{ + int ret; + char *metadata_string = NULL; + + if (!writer) { + goto end; + } + + metadata_string = bt_ctf_trace_get_metadata_string( + writer->trace); + if (!metadata_string) { + goto end; + } + + if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) { + perror("lseek"); + goto end; + } + + if (ftruncate(writer->metadata_fd, 0)) { + perror("ftruncate"); + goto end; + } + + ret = write(writer->metadata_fd, metadata_string, + strlen(metadata_string)); + if (ret < 0) { + perror("write"); + goto end; + } +end: + g_free(metadata_string); +} + +int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, + enum bt_ctf_byte_order byte_order) +{ + int ret = 0; + + if (!writer || writer->frozen) { + ret = -1; + goto end; + } + + if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { + if (BYTE_ORDER == LITTLE_ENDIAN) { + byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN; + } else { + byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN; + } + } + + ret = bt_ctf_trace_set_native_byte_order(writer->trace, + byte_order); +end: + return ret; +} + +BT_HIDDEN +void bt_ctf_writer_freeze(struct bt_ctf_writer *writer) +{ + writer->frozen = 1; +} + +static +const unsigned int field_type_aliases_alignments[] = { + [FIELD_TYPE_ALIAS_UINT5_T] = 1, + [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8, + [FIELD_TYPE_ALIAS_UINT27_T] = 1, + [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8, +}; + +static +const unsigned int field_type_aliases_sizes[] = { + [FIELD_TYPE_ALIAS_UINT5_T] = 5, + [FIELD_TYPE_ALIAS_UINT8_T] = 8, + [FIELD_TYPE_ALIAS_UINT16_T] = 16, + [FIELD_TYPE_ALIAS_UINT27_T] = 27, + [FIELD_TYPE_ALIAS_UINT32_T] = 32, + [FIELD_TYPE_ALIAS_UINT64_T] = 64, +}; + +BT_HIDDEN +struct bt_ctf_field_type *get_field_type(enum field_type_alias alias) +{ + int ret; + unsigned int alignment, size; + struct bt_ctf_field_type *field_type = NULL; + + if (alias >= NR_FIELD_TYPE_ALIAS) { + goto end; + } + + alignment = field_type_aliases_alignments[alias]; + size = field_type_aliases_sizes[alias]; + field_type = bt_ctf_field_type_integer_create(size); + ret = bt_ctf_field_type_set_alignment(field_type, alignment); + if (ret) { + BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type); + } +end: + return field_type; +} + +BT_HIDDEN +const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order) +{ + const char *string; + + switch (byte_order) { + case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: + string = "le"; + break; + case BT_CTF_BYTE_ORDER_BIG_ENDIAN: + string = "be"; + break; + case BT_CTF_BYTE_ORDER_NATIVE: + string = "native"; + break; + default: + abort(); + } + + return string; +} diff --git a/extras/gen-babeltrace-h.py b/extras/gen-babeltrace-h.py index f03110fc..7c64a676 100644 --- a/extras/gen-babeltrace-h.py +++ b/extras/gen-babeltrace-h.py @@ -45,6 +45,9 @@ def _c_includes_from_sections(sections): src = '' for section in sections: + if 'ctf' in section.title.lower(): + continue + src += '/* {} */\n'.format(section.title) for filename in sorted(section.filenames): diff --git a/include/Makefile.am b/include/Makefile.am index e069b2cc..a340b805 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -235,6 +235,7 @@ noinst_HEADERS = \ babeltrace2/plugin/python-plugin-provider-internal.h \ babeltrace2/assert-internal.h \ babeltrace2/value-internal.h \ + babeltrace2/ctf-writer/assert-pre-internal.h \ babeltrace2/ctf-writer/attributes-internal.h \ babeltrace2/ctf-writer/clock-class-internal.h \ babeltrace2/ctf-writer/clock-internal.h \ diff --git a/include/babeltrace2/babeltrace.h b/include/babeltrace2/babeltrace.h index 45509a8a..20d50f59 100644 --- a/include/babeltrace2/babeltrace.h +++ b/include/babeltrace2/babeltrace.h @@ -34,37 +34,6 @@ #include #include -/* Legacy API (for CTF writer) */ -#include - -/* CTF writer API */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Legacy API (for CTF writer) */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - /* Trace IR API */ #include #include diff --git a/include/babeltrace2/ctf-writer/assert-pre-internal.h b/include/babeltrace2/ctf-writer/assert-pre-internal.h new file mode 100644 index 00000000..3ac3af1c --- /dev/null +++ b/include/babeltrace2/ctf-writer/assert-pre-internal.h @@ -0,0 +1,129 @@ +#ifndef BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H +#define BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H + +/* + * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2018 Philippe Proulx + * + * 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. + */ + +/* + * The macros in this header use macros defined in + * . We don't want this header to + * automatically include because you + * need to manually define BT_LOG_TAG before including + * and it is unexpected that you + * also need to define it before including this header. + * + * This is a reminder that in order to use + * , you also need to use logging + * explicitly. + */ + +#ifndef BABELTRACE_LOGGING_INTERNAL_H +# error Include before this header. +#endif + +#include +#include +#include + +#ifdef BT_DEV_MODE +/* + * Asserts that the library precondition _cond is satisfied. + * + * If _cond is false, log a fatal statement using _fmt and the optional + * arguments using BT_LOGF(), and abort. + * + * To assert that a postcondition is satisfied or that some internal + * object/context/value is in the expected state, use BT_ASSERT(). + */ +# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...) \ + do { \ + if (!(_cond)) { \ + BT_LOGF_STR("Library precondition not satisfied; error is:"); \ + BT_LOGF((_fmt), ##__VA_ARGS__); \ + BT_LOGF_STR("Aborting..."); \ + abort(); \ + } \ + } while (0) + +/* + * Marks a function as being only used within a BT_CTF_ASSERT_PRE() context. + */ +# define BT_CTF_ASSERT_PRE_FUNC + +/* + * Prints the details of an unsatisfied precondition without immediately + * aborting. You should use this within a function which checks + * preconditions, but which is called from a BT_CTF_ASSERT_PRE() context, so + * that the function can still return its result for BT_CTF_ASSERT_PRE() to + * evaluate it. + * + * Example: + * + * BT_CTF_ASSERT_PRE_FUNC + * static inline bool check_complex_precond(...) + * { + * ... + * + * if (...) { + * BT_CTF_ASSERT_PRE_MSG("Invalid object: ...", ...); + * return false; + * } + * + * ... + * } + * + * ... + * + * BT_CTF_ASSERT_PRE(check_complex_precond(...), + * "Precondition is not satisfied: ...", ...); + */ +# define BT_CTF_ASSERT_PRE_MSG BT_LOGF +#else +# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...) ((void) sizeof((void) (_cond), 0)) +# define BT_CTF_ASSERT_PRE_FUNC BT_UNUSED +# define BT_CTF_ASSERT_PRE_MSG(_fmt, ...) +#endif /* BT_DEV_MODE */ + +/* + * Developer mode: asserts that a given variable is not NULL. + */ +#define BT_CTF_ASSERT_PRE_NON_NULL(_obj, _obj_name) \ + BT_CTF_ASSERT_PRE((_obj) != NULL, "%s is NULL: ", _obj_name) + +/* + * Developer mode: asserts that a given object is NOT frozen. This macro + * checks the `frozen` field of _obj. + */ +#define BT_CTF_ASSERT_PRE_HOT(_obj, _obj_name, _fmt, ...) \ + BT_CTF_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name, \ + ##__VA_ARGS__) + +/* + * Developer mode: asserts that a given index is less than a given size. + */ +#define BT_CTF_ASSERT_PRE_VALID_INDEX(_index, _length) \ + BT_CTF_ASSERT_PRE((_index) < (_length), \ + "Index is out of bounds: index=%" PRIu64 ", " \ + "count=%" PRIu64, (uint64_t) (_index), (uint64_t) (_length)) + +#endif /* BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H */ diff --git a/include/babeltrace2/ctf-writer/event-class-internal.h b/include/babeltrace2/ctf-writer/event-class-internal.h index 34ce8ce4..c67184ae 100644 --- a/include/babeltrace2/ctf-writer/event-class-internal.h +++ b/include/babeltrace2/ctf-writer/event-class-internal.h @@ -92,7 +92,7 @@ static inline const char *bt_ctf_event_class_common_get_name( struct bt_ctf_event_class_common *event_class) { - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); BT_ASSERT(event_class->name); return event_class->name->str; } @@ -101,7 +101,7 @@ static inline int64_t bt_ctf_event_class_common_get_id( struct bt_ctf_event_class_common *event_class) { - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); return event_class->id; } @@ -151,7 +151,7 @@ static inline int bt_ctf_event_class_common_get_log_level( struct bt_ctf_event_class_common *event_class) { - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); return event_class->log_level; } @@ -221,7 +221,7 @@ const char *bt_ctf_event_class_common_get_emf_uri( { const char *emf_uri = NULL; - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); if (event_class->emf_uri->len > 0) { emf_uri = event_class->emf_uri->str; @@ -282,7 +282,7 @@ struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_context_field_ { struct bt_ctf_field_type_common *context_ft = NULL; - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); if (!event_class->context_field_type) { BT_LOGV("Event class has no context field type: " @@ -350,7 +350,7 @@ static inline struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_payload_field_type( struct bt_ctf_event_class_common *event_class) { - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); + BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class"); return event_class->payload_field_type; } diff --git a/include/babeltrace2/ctf-writer/event-internal.h b/include/babeltrace2/ctf-writer/event-internal.h index d1d3dc9d..97039878 100644 --- a/include/babeltrace2/ctf-writer/event-internal.h +++ b/include/babeltrace2/ctf-writer/event-internal.h @@ -29,7 +29,7 @@ */ #include -#include +#include #include #include #include @@ -74,8 +74,8 @@ void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event, # define bt_ctf_event_common_set_is_frozen(_event, _is_frozen) #endif -#define BT_ASSERT_PRE_EVENT_COMMON_HOT(_event, _name) \ - BT_ASSERT_PRE_HOT((_event), (_name), ": event-addr=%p", (_event)) +#define BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(_event, _name) \ + BT_CTF_ASSERT_PRE_HOT((_event), (_name), ": event-addr=%p", (_event)) static inline struct bt_ctf_event_class_common *bt_ctf_event_common_borrow_class( @@ -111,7 +111,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_payload( { struct bt_ctf_field_common *payload = NULL; - BT_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); if (!event->payload_field) { BT_LOGV("Event has no current payload field: addr=%p, " @@ -133,7 +133,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_header( { struct bt_ctf_field_common *header = NULL; - BT_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); if (!event->header_field) { BT_LOGV("Event has no current header field: addr=%p, " @@ -155,7 +155,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_context( { struct bt_ctf_field_common *context = NULL; - BT_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); if (!event->context_field) { BT_LOGV("Event has no current context field: addr=%p, " @@ -177,7 +177,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_stream_event_context( { struct bt_ctf_field_common *stream_event_context = NULL; - BT_ASSERT_PRE_NON_NULL(event, "Event"); + BT_CTF_ASSERT_PRE_NON_NULL(event, "Event"); if (!event->stream_event_context_field) { BT_LOGV("Event has no current stream event context field: addr=%p, " diff --git a/include/babeltrace2/ctf-writer/field-types-internal.h b/include/babeltrace2/ctf-writer/field-types-internal.h index 9f514772..757170fa 100644 --- a/include/babeltrace2/ctf-writer/field-types-internal.h +++ b/include/babeltrace2/ctf-writer/field-types-internal.h @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include @@ -39,13 +39,13 @@ #include #include -#define BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(_ft, _type_id, _name) \ - BT_ASSERT_PRE(((struct bt_ctf_field_type_common *) (_ft))->id == (_type_id), \ +#define BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(_ft, _type_id, _name) \ + BT_CTF_ASSERT_PRE(((struct bt_ctf_field_type_common *) (_ft))->id == (_type_id), \ _name " has the wrong type ID: expected-type-id=%s, " \ "ft-addr=%p", bt_ctf_field_type_id_string(_type_id), (_ft)) -#define BT_ASSERT_PRE_CTF_FT_HOT(_ft, _name) \ - BT_ASSERT_PRE_HOT((_ft), (_name), ": ft-addr=%p", (_ft)) +#define BT_CTF_ASSERT_PRE_CTF_FT_HOT(_ft, _name) \ + BT_CTF_ASSERT_PRE_HOT((_ft), (_name), ": ft-addr=%p", (_ft)) #define BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(_ft, _index) \ (&g_array_index(((struct bt_ctf_field_type_common_structure *) (_ft))->fields, \ diff --git a/include/babeltrace2/ctf-writer/fields-internal.h b/include/babeltrace2/ctf-writer/fields-internal.h index 0586fdd7..e9bd3962 100644 --- a/include/babeltrace2/ctf-writer/fields-internal.h +++ b/include/babeltrace2/ctf-writer/fields-internal.h @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include @@ -46,18 +46,18 @@ #include #include -#define BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(_field, _type_id, _name) \ - BT_ASSERT_PRE((_field)->type->id == ((int) (_type_id)), \ +#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(_field, _type_id, _name) \ + BT_CTF_ASSERT_PRE((_field)->type->id == ((int) (_type_id)), \ _name " has the wrong type ID: expected-type-id=%s, " \ "field-addr=%p", \ bt_ctf_field_type_id_string((int) (_type_id)), (_field)) -#define BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(_field, _name) \ - BT_ASSERT_PRE(bt_ctf_field_common_is_set_recursive(_field), \ +#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(_field, _name) \ + BT_CTF_ASSERT_PRE(bt_ctf_field_common_is_set_recursive(_field), \ _name " is not set: field-addr=%p", (_field)) -#define BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(_field, _name) \ - BT_ASSERT_PRE_HOT((_field), (_name), ": field-addr=%p", (_field)) +#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(_field, _name) \ + BT_CTF_ASSERT_PRE_HOT((_field), (_name), ": field-addr=%p", (_field)) struct bt_ctf_field_common; @@ -297,7 +297,7 @@ int _bt_ctf_field_common_validate_recursive(struct bt_ctf_field_common *field) int ret = 0; if (!field) { - BT_ASSERT_PRE_MSG("%s", "Invalid field: field is NULL."); + BT_CTF_ASSERT_PRE_MSG("%s", "Invalid field: field is NULL."); ret = -1; goto end; } @@ -363,7 +363,7 @@ struct bt_ctf_field_type_common *bt_ctf_field_common_borrow_type( { struct bt_ctf_field_type_common *ret = NULL; - BT_ASSERT_PRE_NON_NULL(field, "Field"); + BT_CTF_ASSERT_PRE_NON_NULL(field, "Field"); ret = field->type; return ret; } @@ -373,8 +373,8 @@ int64_t bt_ctf_field_common_sequence_get_length(struct bt_ctf_field_common *fiel { struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "Sequence field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE, "Field"); return (int64_t) sequence->length; } @@ -386,11 +386,11 @@ int bt_ctf_field_common_sequence_set_length(struct bt_ctf_field_common *field, int ret = 0; struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "Sequence field"); - BT_ASSERT_PRE(((int64_t) length) >= 0, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field"); + BT_CTF_ASSERT_PRE(((int64_t) length) >= 0, "Invalid sequence length (too large): length=%" PRId64, length); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Sequence field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Sequence field"); if (unlikely(length > sequence->elements->len)) { /* Make more room */ @@ -432,9 +432,9 @@ struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_name( size_t index; GHashTable *field_name_to_index; - BT_ASSERT_PRE_NON_NULL(field, "Structure field"); - BT_ASSERT_PRE_NON_NULL(name, "Field name"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field"); + BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_STRUCT, "Field"); structure_ft = BT_CTF_FROM_COMMON(field->type); field_name_to_index = structure_ft->field_name_to_index; @@ -461,10 +461,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_index( { struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "Structure field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_STRUCT, "Field"); - BT_ASSERT_PRE(index < structure->fields->len, + BT_CTF_ASSERT_PRE(index < structure->fields->len, "Index is out of bound: struct-field-addr=%p, " "index=%" PRIu64 ", count=%u", field, index, structure->fields->len); @@ -477,10 +477,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_array_borrow_field( { struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "Array field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_ARRAY, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Array field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_ARRAY, "Field"); - BT_ASSERT_PRE(index < array->elements->len, + BT_CTF_ASSERT_PRE(index < array->elements->len, "Index is out of bound: array-field-addr=%p, " "index=%" PRIu64 ", count=%u", field, index, array->elements->len); @@ -493,10 +493,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_sequence_borrow_field( { struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "Sequence field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE, "Field"); - BT_ASSERT_PRE(index < sequence->length, + BT_CTF_ASSERT_PRE(index < sequence->length, "Index is out of bound: seq-field-addr=%p, " "index=%" PRIu64 ", count=%u", field, index, sequence->elements->len); @@ -511,8 +511,8 @@ int bt_ctf_field_common_variant_set_tag(struct bt_ctf_field_common *variant_fiel int64_t choice_index; struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field); - BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, + BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, BT_CTF_FIELD_TYPE_ID_VARIANT, "Field"); /* Find matching index in variant field's type */ @@ -538,10 +538,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_variant_borrow_current_field( { struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field); - BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, + BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, BT_CTF_FIELD_TYPE_ID_VARIANT, "Field"); - BT_ASSERT_PRE(variant->current_field, + BT_CTF_ASSERT_PRE(variant->current_field, "Variant field has no current field: field-addr=%p", variant_field); return variant->current_field; } @@ -552,10 +552,10 @@ int bt_ctf_field_common_variant_get_tag_signed(struct bt_ctf_field_common *varia { struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field); - BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, + BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, BT_CTF_FIELD_TYPE_ID_VARIANT, "Field"); - BT_ASSERT_PRE(variant->current_field, + BT_CTF_ASSERT_PRE(variant->current_field, "Variant field has no current field: field-addr=%p", variant_field); *tag = variant->tag_value.i; return 0; @@ -567,10 +567,10 @@ int bt_ctf_field_common_variant_get_tag_unsigned(struct bt_ctf_field_common *var { struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field); - BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, + BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field, BT_CTF_FIELD_TYPE_ID_VARIANT, "Field"); - BT_ASSERT_PRE(variant->current_field, + BT_CTF_ASSERT_PRE(variant->current_field, "Variant field has no current field: field-addr=%p", variant_field); *tag = variant->tag_value.u; return 0; @@ -583,10 +583,10 @@ int bt_ctf_field_common_floating_point_get_value(struct bt_ctf_field_common *fie struct bt_ctf_field_common_floating_point *floating_point = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "Floating point number field"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_FLOAT, "Field"); *value = floating_point->payload; return 0; @@ -599,9 +599,9 @@ int bt_ctf_field_common_floating_point_set_value(struct bt_ctf_field_common *fie struct bt_ctf_field_common_floating_point *floating_point = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "Floating point number field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Floating point number field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Floating point number field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_FLOAT, "Field"); floating_point->payload = value; bt_ctf_field_common_set(field, true); @@ -613,9 +613,9 @@ const char *bt_ctf_field_common_string_get_value(struct bt_ctf_field_common *fie { struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "String field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "String field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_STRING, "Field"); return (const char *) string->buf->data; } @@ -625,9 +625,9 @@ int bt_ctf_field_common_string_clear(struct bt_ctf_field_common *field) { struct bt_ctf_field_common_string *string_field = BT_CTF_FROM_COMMON(field); - BT_ASSERT_PRE_NON_NULL(field, "String field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "String field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_STRING, "Field"); string_field->size = 0; bt_ctf_field_common_set(field, true); @@ -642,14 +642,14 @@ int bt_ctf_field_common_string_append_len(struct bt_ctf_field_common *field, char *data; size_t new_size; - BT_ASSERT_PRE_NON_NULL(field, "String field"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "String field"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_STRING, "Field"); /* Make sure no null bytes are appended */ - BT_ASSERT_PRE(memchr(value, '\0', length) == NULL, + BT_CTF_ASSERT_PRE(memchr(value, '\0', length) == NULL, "String value to append contains a null character: " "partial-value=\"%.32s\", length=%u", value, length); @@ -671,7 +671,7 @@ static inline int bt_ctf_field_common_string_append(struct bt_ctf_field_common *field, const char *value) { - BT_ASSERT_PRE_NON_NULL(value, "Value"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value"); return bt_ctf_field_common_string_append_len(field, value, strlen(value)); } @@ -680,10 +680,10 @@ static inline int bt_ctf_field_common_string_set_value(struct bt_ctf_field_common *field, const char *value) { - BT_ASSERT_PRE_NON_NULL(field, "String field"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, + BT_CTF_ASSERT_PRE_NON_NULL(field, "String field"); + BT_CTF_ASSERT_PRE_NON_NULL(value, "Value"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field"); + BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_STRING, "Field"); bt_ctf_field_common_string_clear(field); return bt_ctf_field_common_string_append_len(field, @@ -784,7 +784,7 @@ void bt_ctf_field_common_string_finalize(struct bt_ctf_field_common *field) } } -BT_ASSERT_PRE_FUNC +BT_CTF_ASSERT_PRE_FUNC static inline bool value_is_in_range_signed(unsigned int size, int64_t value) { bool ret = true; @@ -802,7 +802,7 @@ static inline bool value_is_in_range_signed(unsigned int size, int64_t value) return ret; } -BT_ASSERT_PRE_FUNC +BT_CTF_ASSERT_PRE_FUNC static inline bool value_is_in_range_unsigned(unsigned int size, uint64_t value) { bool ret = true; diff --git a/include/babeltrace2/ctf-writer/stream-class-internal.h b/include/babeltrace2/ctf-writer/stream-class-internal.h index 20982535..0b7fd47d 100644 --- a/include/babeltrace2/ctf-writer/stream-class-internal.h +++ b/include/babeltrace2/ctf-writer/stream-class-internal.h @@ -101,7 +101,7 @@ static inline const char *bt_ctf_stream_class_common_get_name( struct bt_ctf_stream_class_common *stream_class) { - BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); return stream_class->name->len > 0 ? stream_class->name->str : NULL; } @@ -111,7 +111,7 @@ int64_t bt_ctf_stream_class_common_get_id( { int64_t ret; - BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); if (!stream_class->id_set) { BT_LOGV("Stream class's ID is not set: addr=%p, name=\"%s\"", @@ -289,8 +289,8 @@ static inline struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_by_index( struct bt_ctf_stream_class_common *stream_class, uint64_t index) { - BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); - BT_ASSERT_PRE(index < stream_class->event_classes->len, + BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_CTF_ASSERT_PRE(index < stream_class->event_classes->len, "Index is out of bounds: index=%" PRIu64 ", " "count=%u", index, stream_class->event_classes->len); @@ -303,8 +303,8 @@ struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_ { int64_t id_key = (int64_t) id; - BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); - BT_ASSERT_PRE(id_key >= 0, + BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_CTF_ASSERT_PRE(id_key >= 0, "Invalid event class ID: %" PRIu64, id); return g_hash_table_lookup(stream_class->event_classes_ht, &id_key); @@ -315,7 +315,7 @@ struct bt_ctf_field_type_common * bt_ctf_stream_class_common_borrow_packet_context_field_type( struct bt_ctf_stream_class_common *stream_class) { - BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); return stream_class->packet_context_field_type; } @@ -378,7 +378,7 @@ bt_ctf_stream_class_common_borrow_event_header_field_type( { struct bt_ctf_field_type_common *ret = NULL; - BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); if (!stream_class->event_header_field_type) { BT_LOGV("Stream class has no event header field type: " @@ -454,7 +454,7 @@ bt_ctf_stream_class_common_borrow_event_context_field_type( { struct bt_ctf_field_type_common *ret = NULL; - BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); + BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); if (!stream_class->event_context_field_type) { goto end; diff --git a/include/babeltrace2/ctf-writer/stream-internal.h b/include/babeltrace2/ctf-writer/stream-internal.h index 456a6f4d..c7eb9fae 100644 --- a/include/babeltrace2/ctf-writer/stream-internal.h +++ b/include/babeltrace2/ctf-writer/stream-internal.h @@ -29,7 +29,7 @@ */ #include -#include +#include #include #include #include @@ -67,7 +67,7 @@ struct bt_ctf_stream_class_common *bt_ctf_stream_common_borrow_class( static inline const char *bt_ctf_stream_common_get_name(struct bt_ctf_stream_common *stream) { - BT_ASSERT_PRE_NON_NULL(stream, "Stream"); + BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream"); return stream->name ? stream->name->str : NULL; } @@ -76,7 +76,7 @@ int64_t bt_ctf_stream_common_get_id(struct bt_ctf_stream_common *stream) { int64_t ret; - BT_ASSERT_PRE_NON_NULL(stream, "Stream"); + BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream"); ret = stream->id; if (ret < 0) { BT_LOGV("Stream's ID is not set: addr=%p, name=\"%s\"", diff --git a/include/babeltrace2/ctf-writer/trace-internal.h b/include/babeltrace2/ctf-writer/trace-internal.h index ff313cf4..4d3e4d1a 100644 --- a/include/babeltrace2/ctf-writer/trace-internal.h +++ b/include/babeltrace2/ctf-writer/trace-internal.h @@ -28,7 +28,7 @@ * http://www.efficios.com/ctf */ -#include +#include #include #include #include @@ -79,7 +79,7 @@ void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace); static inline const char *bt_ctf_trace_common_get_name(struct bt_ctf_trace_common *trace) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return trace->name ? trace->name->str : NULL; } @@ -89,7 +89,7 @@ int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char * static inline const unsigned char *bt_ctf_trace_common_get_uuid(struct bt_ctf_trace_common *trace) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return trace->uuid_set ? trace->uuid : NULL; } @@ -114,7 +114,7 @@ int64_t bt_ctf_trace_common_get_environment_field_count( { int64_t ret; - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); ret = bt_ctf_attributes_get_count(trace->environment); BT_ASSERT(ret >= 0); return ret; @@ -125,7 +125,7 @@ const char * bt_ctf_trace_common_get_environment_field_name_by_index( struct bt_ctf_trace_common *trace, uint64_t index) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return bt_ctf_attributes_get_field_name(trace->environment, index); } @@ -134,7 +134,7 @@ struct bt_ctf_private_value * bt_ctf_trace_common_borrow_environment_field_value_by_index( struct bt_ctf_trace_common *trace, uint64_t index) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return bt_ctf_attributes_borrow_field_value(trace->environment, index); } @@ -143,8 +143,8 @@ struct bt_ctf_private_value * bt_ctf_trace_common_borrow_environment_field_value_by_name( struct bt_ctf_trace_common *trace, const char *name) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(name, "Name"); return bt_ctf_attributes_borrow_field_value_by_name(trace->environment, name); } @@ -156,7 +156,7 @@ int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace, static inline int64_t bt_ctf_trace_common_get_clock_class_count(struct bt_ctf_trace_common *trace) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return trace->clock_classes->len; } @@ -164,8 +164,8 @@ static inline struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_index( struct bt_ctf_trace_common *trace, uint64_t index) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE(index < trace->clock_classes->len, + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE(index < trace->clock_classes->len, "Index is out of bounds: index=%" PRIu64 ", " "count=%u", index, trace->clock_classes->len); @@ -175,7 +175,7 @@ struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_index( static inline int64_t bt_ctf_trace_common_get_stream_count(struct bt_ctf_trace_common *trace) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return (int64_t) trace->streams->len; } @@ -184,8 +184,8 @@ struct bt_ctf_stream_common *bt_ctf_trace_common_borrow_stream_by_index( struct bt_ctf_trace_common *trace, uint64_t index) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE(index < trace->streams->len, + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE(index < trace->streams->len, "Index is out of bounds: index=%" PRIu64 ", " "count=%u", index, trace->streams->len); @@ -195,7 +195,7 @@ struct bt_ctf_stream_common *bt_ctf_trace_common_borrow_stream_by_index( static inline int64_t bt_ctf_trace_common_get_stream_class_count(struct bt_ctf_trace_common *trace) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return (int64_t) trace->stream_classes->len; } @@ -203,8 +203,8 @@ static inline struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_index( struct bt_ctf_trace_common *trace, uint64_t index) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE(index < trace->stream_classes->len, + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE(index < trace->stream_classes->len, "Index is out of bounds: index=%" PRIu64 ", " "count=%u", index, trace->stream_classes->len); @@ -219,8 +219,8 @@ struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_id struct bt_ctf_stream_class_common *stream_class = NULL; int64_t id = (int64_t) id_param; - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE(id >= 0, + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE(id >= 0, "Invalid stream class ID: %" PRIu64, id_param); for (i = 0; i < trace->stream_classes->len; i++) { @@ -247,8 +247,8 @@ struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_name( size_t i; struct bt_ctf_clock_class *clock_class = NULL; - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(name, "Name"); for (i = 0; i < trace->clock_classes->len; i++) { struct bt_ctf_clock_class *cur_clk = @@ -273,7 +273,7 @@ static inline enum bt_ctf_byte_order bt_ctf_trace_common_get_native_byte_order( struct bt_ctf_trace_common *trace) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return trace->native_byte_order; } @@ -285,7 +285,7 @@ static inline struct bt_ctf_field_type_common *bt_ctf_trace_common_borrow_packet_header_field_type( struct bt_ctf_trace_common *trace) { - BT_ASSERT_PRE_NON_NULL(trace, "Trace"); + BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace"); return trace->packet_header_field_type; } diff --git a/lib/Makefile.am b/lib/Makefile.am index fe6b88b0..39b956a9 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ -SUBDIRS = trace-ir ctf-writer prio_heap plugin graph . +SUBDIRS = trace-ir prio_heap plugin graph -lib_LTLIBRARIES = libbabeltrace2.la libbabeltrace2-ctf.la +lib_LTLIBRARIES = libbabeltrace2.la libbabeltrace2_la_SOURCES = \ babeltrace2.c \ @@ -17,32 +17,10 @@ libbabeltrace2_la_LIBADD = \ graph/libgraph.la \ plugin/libplugin.la \ trace-ir/libtrace-ir.la \ - ctf-writer/libctf-writer.la \ $(top_builddir)/logging/libbabeltrace2-logging.la \ $(top_builddir)/common/libbabeltrace2-common.la \ - $(top_builddir)/ctfser/libbabeltrace2-ctfser.la \ $(top_builddir)/compat/libcompat.la if ENABLE_BUILT_IN_PYTHON_PLUGIN_SUPPORT libbabeltrace2_la_LIBADD += $(top_builddir)/python-plugin-provider/libbabeltrace2-python-plugin-provider.la endif - -# FIXME: Should we drop this? We changed the basename of the library, -# libbabeltrace2 is not a drop-in replacement for libbabeltrace anymore. -# -# Build a libbabeltrace2-ctf library for backwards compatibility. -# CTF writer used to be in libbabeltrace2-ctf in Babeltrace 1, so this -# file must still exist. As of Babeltrace 2, CTF writer is implemented -# in libbabeltrace2. -libbabeltrace2_ctf_la_SOURCES = $(libbabeltrace2_la_SOURCES) -libbabeltrace2_ctf_la_LDFLAGS = $(LT_NO_UNDEFINED) \ - -version-info $(BABELTRACE_LIBRARY_VERSION) - -libbabeltrace2_ctf_la_LIBADD = \ - graph/libgraph.la \ - trace-ir/libtrace-ir.la \ - ctf-writer/libctf-writer.la \ - $(top_builddir)/logging/libbabeltrace2-logging.la \ - $(top_builddir)/common/libbabeltrace2-common.la \ - $(top_builddir)/ctfser/libbabeltrace2-ctfser.la \ - $(top_builddir)/compat/libcompat.la diff --git a/lib/ctf-writer/Makefile.am b/lib/ctf-writer/Makefile.am deleted file mode 100644 index bee4b394..00000000 --- a/lib/ctf-writer/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -noinst_LTLIBRARIES = libctf-writer.la - -libctf_writer_la_SOURCES = \ - attributes.c \ - clock.c \ - clock-class.c \ - event.c \ - event-class.c \ - field-path.c \ - fields.c \ - field-types.c \ - field-wrapper.c \ - functor.c \ - object.c \ - object-pool.c \ - resolve.c \ - stream.c \ - stream-class.c \ - trace.c \ - utils.c \ - validation.c \ - values.c \ - visitor.c \ - writer.c - -libctf_writer_la_LIBADD = $(UUID_LIBS) diff --git a/lib/ctf-writer/attributes.c b/lib/ctf-writer/attributes.c deleted file mode 100644 index a594015f..00000000 --- a/lib/ctf-writer/attributes.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * attributes.c - * - * Babeltrace CTF writer - Attributes - * - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-ATTRS" -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define BT_CTF_ATTR_NAME_INDEX 0 -#define BT_CTF_ATTR_VALUE_INDEX 1 - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_attributes_create(void) -{ - struct bt_ctf_private_value *attr_obj; - - /* - * Attributes: array value object of array value objects, each one - * containing two entries: a string value object (attributes - * field name), and a value object (attributes field value). - * - * Example (JSON representation): - * - * [ - * ["hostname", "eeppdesk"], - * ["sysname", "Linux"], - * ["tracer_major", 2], - * ["tracer_minor", 5] - * ] - */ - BT_LOGD_STR("Creating attributes object."); - attr_obj = bt_ctf_private_value_array_create(); - if (!attr_obj) { - BT_LOGE_STR("Failed to create array value."); - } else { - BT_LOGD("Created attributes object: addr=%p", - attr_obj); - } - - return attr_obj; -} - -BT_HIDDEN -void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj) -{ - BT_LOGD("Destroying attributes object: addr=%p", attr_obj); - bt_ctf_object_put_ref(attr_obj); -} - -BT_HIDDEN -int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj) -{ - return bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)); -} - -BT_HIDDEN -const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj, - uint64_t index) -{ - const char *ret = NULL; - struct bt_ctf_private_value *attr_field_obj = NULL; - struct bt_ctf_private_value *attr_field_name_obj = NULL; - - if (!attr_obj) { - BT_LOGW_STR("Invalid parameter: attributes object is NULL."); - goto end; - } - - if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) { - BT_LOGW("Invalid parameter: index is out of bounds: " - "index=%" PRIu64 ", count=%" PRId64, - index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))); - goto end; - } - - attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index( - attr_obj, index); - if (!attr_field_obj) { - BT_LOGE("Cannot get attributes object's array value's element by index: " - "value-addr=%p, index=%" PRIu64, attr_obj, index); - goto end; - } - - attr_field_name_obj = - bt_ctf_private_value_array_borrow_element_by_index( - attr_field_obj, BT_CTF_ATTR_NAME_INDEX); - if (!attr_field_name_obj) { - BT_LOGE("Cannot get attribute array value's element by index: " - "value-addr=%p, index=%" PRIu64, attr_field_obj, - (uint64_t) BT_CTF_ATTR_NAME_INDEX); - goto end; - } - - ret = bt_ctf_value_string_get( - bt_ctf_private_value_as_value(attr_field_name_obj)); - -end: - return ret; -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj, - uint64_t index) -{ - struct bt_ctf_private_value *value_obj = NULL; - struct bt_ctf_private_value *attr_field_obj = NULL; - - if (!attr_obj) { - BT_LOGW_STR("Invalid parameter: attributes object is NULL."); - goto end; - } - - if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) { - BT_LOGW("Invalid parameter: index is out of bounds: " - "index=%" PRIu64 ", count=%" PRId64, - index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))); - goto end; - } - - attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index( - attr_obj, index); - if (!attr_field_obj) { - BT_LOGE("Cannot get attributes object's array value's element by index: " - "value-addr=%p, index=%" PRIu64, attr_obj, index); - goto end; - } - - value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj, - BT_CTF_ATTR_VALUE_INDEX); - if (!value_obj) { - BT_LOGE("Cannot get attribute array value's element by index: " - "value-addr=%p, index=%" PRIu64, attr_field_obj, - (uint64_t) BT_CTF_ATTR_VALUE_INDEX); - } - -end: - return value_obj; -} - -static -struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_by_name( - struct bt_ctf_private_value *attr_obj, const char *name) -{ - uint64_t i; - int64_t attr_size; - struct bt_ctf_private_value *value_obj = NULL; - struct bt_ctf_private_value *attr_field_name_obj = NULL; - - attr_size = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)); - if (attr_size < 0) { - BT_LOGE("Cannot get array value's size: value-addr=%p", - attr_obj); - goto error; - } - - for (i = 0; i < attr_size; ++i) { - const char *field_name; - - value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_obj, i); - if (!value_obj) { - BT_LOGE("Cannot get attributes object's array value's element by index: " - "value-addr=%p, index=%" PRIu64, attr_obj, i); - goto error; - } - - attr_field_name_obj = bt_ctf_private_value_array_borrow_element_by_index(value_obj, - BT_CTF_ATTR_NAME_INDEX); - if (!attr_field_name_obj) { - BT_LOGE("Cannot get attribute array value's element by index: " - "value-addr=%p, index=%" PRIu64, - value_obj, (int64_t) BT_CTF_ATTR_NAME_INDEX); - goto error; - } - - field_name = bt_ctf_value_string_get( - bt_ctf_private_value_as_value(attr_field_name_obj)); - - if (!strcmp(field_name, name)) { - break; - } - - value_obj = NULL; - } - - return value_obj; - -error: - value_obj = NULL; - return value_obj; -} - -BT_HIDDEN -int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj, - const char *name, struct bt_ctf_private_value *value_obj) -{ - int ret = 0; - struct bt_ctf_private_value *attr_field_obj = NULL; - - if (!attr_obj || !name || !value_obj) { - BT_LOGW("Invalid parameter: attributes object, name, or value object is NULL: " - "attr-value-addr=%p, name-addr=%p, value-addr=%p", - attr_obj, name, value_obj); - ret = -1; - goto end; - } - - attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name); - if (attr_field_obj) { - ret = bt_ctf_private_value_array_set_element_by_index( - attr_field_obj, BT_CTF_ATTR_VALUE_INDEX, - bt_ctf_private_value_as_value(value_obj)); - attr_field_obj = NULL; - goto end; - } - - attr_field_obj = bt_ctf_private_value_array_create(); - if (!attr_field_obj) { - BT_LOGE_STR("Failed to create empty array value."); - ret = -1; - goto end; - } - - ret = bt_ctf_private_value_array_append_string_element(attr_field_obj, name); - ret |= bt_ctf_private_value_array_append_element(attr_field_obj, - bt_ctf_private_value_as_value(value_obj)); - if (ret) { - BT_LOGE("Cannot append elements to array value: addr=%p", - attr_field_obj); - goto end; - } - - ret = bt_ctf_private_value_array_append_element(attr_obj, - bt_ctf_private_value_as_value(attr_field_obj)); - if (ret) { - BT_LOGE("Cannot append element to array value: " - "array-value-addr=%p, element-value-addr=%p", - attr_obj, attr_field_obj); - } - -end: - bt_ctf_object_put_ref(attr_field_obj); - return ret; -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name( - struct bt_ctf_private_value *attr_obj, const char *name) -{ - struct bt_ctf_private_value *value_obj = NULL; - struct bt_ctf_private_value *attr_field_obj = NULL; - - if (!attr_obj || !name) { - BT_LOGW("Invalid parameter: attributes object or name is NULL: " - "value-addr=%p, name-addr=%p", attr_obj, name); - goto end; - } - - attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name); - if (!attr_field_obj) { - BT_LOGD("Cannot find attributes object's field by name: " - "value-addr=%p, name=\"%s\"", attr_obj, name); - goto end; - } - - value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj, - BT_CTF_ATTR_VALUE_INDEX); - if (!value_obj) { - BT_LOGE("Cannot get attribute array value's element by index: " - "value-addr=%p, index=%" PRIu64, attr_field_obj, - (uint64_t) BT_CTF_ATTR_VALUE_INDEX); - } - -end: - return value_obj; -} - -BT_HIDDEN -int bt_ctf_attributes_freeze(struct bt_ctf_private_value *attr_obj) -{ - uint64_t i; - int64_t count; - int ret = 0; - - if (!attr_obj) { - BT_LOGW_STR("Invalid parameter: attributes object is NULL."); - ret = -1; - goto end; - } - - BT_LOGD("Freezing attributes object: value-addr=%p", attr_obj); - count = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)); - BT_ASSERT(count >= 0); - - /* - * We do not freeze the array value object itself here, since - * internal stuff could need to modify/add attributes. Each - * attribute is frozen one by one. - */ - for (i = 0; i < count; ++i) { - struct bt_ctf_private_value *obj = NULL; - - obj = bt_ctf_attributes_borrow_field_value(attr_obj, i); - if (!obj) { - BT_LOGE("Cannot get attributes object's field value by index: " - "value-addr=%p, index=%" PRIu64, - attr_obj, i); - ret = -1; - goto end; - } - - bt_ctf_value_freeze(bt_ctf_private_value_as_value(obj)); - } - -end: - return ret; -} diff --git a/lib/ctf-writer/clock-class.c b/lib/ctf-writer/clock-class.c deleted file mode 100644 index 9e3807c0..00000000 --- a/lib/ctf-writer/clock-class.c +++ /dev/null @@ -1,704 +0,0 @@ -/* - * clock-class.c - * - * Babeltrace CTF writer - Clock class - * - * Copyright 2013, 2014 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-CLOCK-CLASS" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static -void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj); - -BT_HIDDEN -bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class) -{ - return clock_class && clock_class->name; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class, - const char *name) -{ - int ret = 0; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - ret = -1; - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - if (!bt_ctf_identifier_is_valid(name)) { - BT_LOGW("Clock class's name is not a valid CTF identifier: " - "addr=%p, name=\"%s\"", - clock_class, name); - ret = -1; - goto end; - } - - if (clock_class->name) { - g_string_assign(clock_class->name, name); - } else { - clock_class->name = g_string_new(name); - if (!clock_class->name) { - BT_LOGE_STR("Failed to allocate a GString."); - ret = -1; - goto end; - } - } - - BT_LOGV("Set clock class's name: addr=%p, name=\"%s\"", - clock_class, name); - -end: - return ret; -} - -static -bool validate_freq(struct bt_ctf_clock_class *clock_class, - const char *name, uint64_t freq) -{ - bool is_valid = true; - - if (freq == -1ULL || freq == 0) { - BT_LOGW("Invalid parameter: frequency is invalid: " - "addr=%p, name=\"%s\", freq=%" PRIu64, - clock_class, name, freq); - is_valid = false; - goto end; - } - -end: - return is_valid; -} - -BT_HIDDEN -struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name, - uint64_t freq) -{ - int ret; - struct bt_ctf_clock_class *clock_class = NULL; - - BT_LOGD("Creating default clock class object: name=\"%s\"", - name); - - if (!validate_freq(NULL, name, freq)) { - /* validate_freq() logs errors */ - goto error; - } - - clock_class = g_new0(struct bt_ctf_clock_class, 1); - if (!clock_class) { - BT_LOGE_STR("Failed to allocate one clock class."); - goto error; - } - - clock_class->precision = 1; - clock_class->frequency = freq; - bt_ctf_object_init_shared(&clock_class->base, bt_ctf_clock_class_destroy); - - if (name) { - ret = bt_ctf_clock_class_set_name(clock_class, name); - if (ret) { - /* bt_ctf_clock_class_set_name() logs errors */ - goto error; - } - } - - BT_LOGD("Created clock class object: addr=%p, name=\"%s\"", - clock_class, name); - return clock_class; -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(clock_class); - return clock_class; -} - -BT_HIDDEN -const char *bt_ctf_clock_class_get_name(struct bt_ctf_clock_class *clock_class) -{ - const char *ret = NULL; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - goto end; - } - - if (clock_class->name) { - ret = clock_class->name->str; - } - -end: - return ret; -} - -BT_HIDDEN -const char *bt_ctf_clock_class_get_description( - struct bt_ctf_clock_class *clock_class) -{ - const char *ret = NULL; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - goto end; - } - - if (clock_class->description) { - ret = clock_class->description->str; - } -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class, - const char *desc) -{ - int ret = 0; - - if (!clock_class || !desc) { - BT_LOGW("Invalid parameter: clock class or description is NULL: " - "clock-class-addr=%p, name=\"%s\", desc-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), - desc); - ret = -1; - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - clock_class->description = g_string_new(desc); - ret = clock_class->description ? 0 : -1; - BT_LOGV("Set clock class's description: addr=%p, " - "name=\"%s\", desc=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class), desc); -end: - return ret; -} - -BT_HIDDEN -uint64_t bt_ctf_clock_class_get_frequency( - struct bt_ctf_clock_class *clock_class) -{ - uint64_t ret = -1ULL; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - goto end; - } - - ret = clock_class->frequency; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class, - uint64_t freq) -{ - int ret = 0; - - if (!clock_class) { - BT_LOGW("Invalid parameter: clock class is NULL or frequency is invalid: " - "addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - if (!validate_freq(clock_class, bt_ctf_clock_class_get_name(clock_class), - freq)) { - /* validate_freq() logs errors */ - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - clock_class->frequency = freq; - BT_LOGV("Set clock class's frequency: addr=%p, name=\"%s\", freq=%" PRIu64, - clock_class, bt_ctf_clock_class_get_name(clock_class), freq); -end: - return ret; -} - -BT_HIDDEN -uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_clock_class *clock_class) -{ - uint64_t ret = -1ULL; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - goto end; - } - - ret = clock_class->precision; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class, - uint64_t precision) -{ - int ret = 0; - - if (!clock_class || precision == -1ULL) { - BT_LOGW("Invalid parameter: clock class is NULL or precision is invalid: " - "addr=%p, name=\"%s\", precision=%" PRIu64, - clock_class, bt_ctf_clock_class_get_name(clock_class), - precision); - ret = -1; - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - clock_class->precision = precision; - BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64, - clock_class, bt_ctf_clock_class_get_name(clock_class), - precision); -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class, - int64_t *offset_s) -{ - int ret = 0; - - if (!clock_class || !offset_s) { - BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " - "clock-class-addr=%p, name=\"%s\", offset-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), - offset_s); - ret = -1; - goto end; - } - - *offset_s = clock_class->offset_s; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class, - int64_t offset_s) -{ - int ret = 0; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - ret = -1; - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - clock_class->offset_s = offset_s; - BT_LOGV("Set clock class's offset (seconds): " - "addr=%p, name=\"%s\", offset-s=%" PRId64, - clock_class, bt_ctf_clock_class_get_name(clock_class), - offset_s); -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_clock_class *clock_class, - int64_t *offset) -{ - int ret = 0; - - if (!clock_class || !offset) { - BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " - "clock-class-addr=%p, name=\"%s\", offset-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), - offset); - ret = -1; - goto end; - } - - *offset = clock_class->offset; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class, - int64_t offset) -{ - int ret = 0; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - ret = -1; - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - clock_class->offset = offset; - BT_LOGV("Set clock class's offset (cycles): addr=%p, name=\"%s\", offset-cycles=%" PRId64, - clock_class, bt_ctf_clock_class_get_name(clock_class), offset); -end: - return ret; -} - -BT_HIDDEN -bt_bool bt_ctf_clock_class_is_absolute(struct bt_ctf_clock_class *clock_class) -{ - int ret = -1; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - goto end; - } - - ret = clock_class->absolute; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_clock_class *clock_class, - bt_bool is_absolute) -{ - int ret = 0; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - ret = -1; - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - clock_class->absolute = !!is_absolute; - BT_LOGV("Set clock class's absolute flag: addr=%p, name=\"%s\", is-absolute=%d", - clock_class, bt_ctf_clock_class_get_name(clock_class), - is_absolute); -end: - return ret; -} - -BT_HIDDEN -const unsigned char *bt_ctf_clock_class_get_uuid( - struct bt_ctf_clock_class *clock_class) -{ - const unsigned char *ret; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - ret = NULL; - goto end; - } - - if (!clock_class->uuid_set) { - BT_LOGV("Clock class's UUID is not set: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = NULL; - goto end; - } - - ret = clock_class->uuid; -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class, - const unsigned char *uuid) -{ - int ret = 0; - - if (!clock_class || !uuid) { - BT_LOGW("Invalid parameter: clock class or UUID is NULL: " - "clock-class-addr=%p, name=\"%s\", uuid-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), - uuid); - ret = -1; - goto end; - } - - if (clock_class->frozen) { - BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - memcpy(clock_class->uuid, uuid, BABELTRACE_UUID_LEN); - clock_class->uuid_set = 1; - BT_LOGV("Set clock class's UUID: addr=%p, name=\"%s\", " - "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", - clock_class, bt_ctf_clock_class_get_name(clock_class), - (unsigned int) uuid[0], - (unsigned int) uuid[1], - (unsigned int) uuid[2], - (unsigned int) uuid[3], - (unsigned int) uuid[4], - (unsigned int) uuid[5], - (unsigned int) uuid[6], - (unsigned int) uuid[7], - (unsigned int) uuid[8], - (unsigned int) uuid[9], - (unsigned int) uuid[10], - (unsigned int) uuid[11], - (unsigned int) uuid[12], - (unsigned int) uuid[13], - (unsigned int) uuid[14], - (unsigned int) uuid[15]); -end: - return ret; -} - -BT_HIDDEN -void bt_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class) -{ - if (!clock_class || clock_class->frozen) { - return; - } - - BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - clock_class->frozen = 1; -} - -static -void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_clock_class *clock_class; - - clock_class = container_of(obj, struct bt_ctf_clock_class, base); - BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"", - obj, bt_ctf_clock_class_get_name(clock_class)); - - if (clock_class->name) { - g_string_free(clock_class->name, TRUE); - } - - if (clock_class->description) { - g_string_free(clock_class->description, TRUE); - } - - g_free(clock_class); -} - -BT_HIDDEN -int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a, - struct bt_ctf_clock_class *clock_class_b) -{ - int ret = 1; - BT_ASSERT(clock_class_a); - BT_ASSERT(clock_class_b); - - /* Name */ - if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) { - BT_LOGV("Clock classes differ: different names: " - "cc-a-name=\"%s\", cc-b-name=\"%s\"", - clock_class_a->name->str, - clock_class_b->name->str); - goto end; - } - - /* Description */ - if (clock_class_a->description) { - if (!clock_class_b->description) { - BT_LOGV_STR("Clock classes differ: clock class A has a " - "description, but clock class B does not."); - goto end; - } - - if (strcmp(clock_class_a->name->str, clock_class_b->name->str) - != 0) { - BT_LOGV("Clock classes differ: different descriptions: " - "cc-a-descr=\"%s\", cc-b-descr=\"%s\"", - clock_class_a->description->str, - clock_class_b->description->str); - goto end; - } - } else { - if (clock_class_b->description) { - BT_LOGV_STR("Clock classes differ: clock class A has " - "no description, but clock class B has one."); - goto end; - } - } - - /* Frequency */ - if (clock_class_a->frequency != clock_class_b->frequency) { - BT_LOGV("Clock classes differ: different frequencies: " - "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, - clock_class_a->frequency, - clock_class_b->frequency); - goto end; - } - - /* Precision */ - if (clock_class_a->precision != clock_class_b->precision) { - BT_LOGV("Clock classes differ: different precisions: " - "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, - clock_class_a->precision, - clock_class_b->precision); - goto end; - } - - /* Offset (seconds) */ - if (clock_class_a->offset_s != clock_class_b->offset_s) { - BT_LOGV("Clock classes differ: different offsets (seconds): " - "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, - clock_class_a->offset_s, - clock_class_b->offset_s); - goto end; - } - - /* Offset (cycles) */ - if (clock_class_a->offset != clock_class_b->offset) { - BT_LOGV("Clock classes differ: different offsets (cycles): " - "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, - clock_class_a->offset, - clock_class_b->offset); - goto end; - } - - /* UUIDs */ - if (clock_class_a->uuid_set) { - if (!clock_class_b->uuid_set) { - BT_LOGV_STR("Clock classes differ: clock class A has a " - "UUID, but clock class B does not."); - goto end; - } - - if (memcmp(clock_class_a->uuid, clock_class_b->uuid, - BABELTRACE_UUID_LEN) != 0) { - BT_LOGV("Clock classes differ: different UUIDs: " - "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", " - "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", - (unsigned int) clock_class_a->uuid[0], - (unsigned int) clock_class_a->uuid[1], - (unsigned int) clock_class_a->uuid[2], - (unsigned int) clock_class_a->uuid[3], - (unsigned int) clock_class_a->uuid[4], - (unsigned int) clock_class_a->uuid[5], - (unsigned int) clock_class_a->uuid[6], - (unsigned int) clock_class_a->uuid[7], - (unsigned int) clock_class_a->uuid[8], - (unsigned int) clock_class_a->uuid[9], - (unsigned int) clock_class_a->uuid[10], - (unsigned int) clock_class_a->uuid[11], - (unsigned int) clock_class_a->uuid[12], - (unsigned int) clock_class_a->uuid[13], - (unsigned int) clock_class_a->uuid[14], - (unsigned int) clock_class_a->uuid[15], - (unsigned int) clock_class_b->uuid[0], - (unsigned int) clock_class_b->uuid[1], - (unsigned int) clock_class_b->uuid[2], - (unsigned int) clock_class_b->uuid[3], - (unsigned int) clock_class_b->uuid[4], - (unsigned int) clock_class_b->uuid[5], - (unsigned int) clock_class_b->uuid[6], - (unsigned int) clock_class_b->uuid[7], - (unsigned int) clock_class_b->uuid[8], - (unsigned int) clock_class_b->uuid[9], - (unsigned int) clock_class_b->uuid[10], - (unsigned int) clock_class_b->uuid[11], - (unsigned int) clock_class_b->uuid[12], - (unsigned int) clock_class_b->uuid[13], - (unsigned int) clock_class_b->uuid[14], - (unsigned int) clock_class_b->uuid[15]); - goto end; - } - } else { - if (clock_class_b->uuid_set) { - BT_LOGV_STR("Clock classes differ: clock class A has " - "no UUID, but clock class B has one."); - goto end; - } - } - - /* Absolute */ - if (!!clock_class_a->absolute != !!clock_class_b->absolute) { - BT_LOGV("Clock classes differ: one is absolute, the other " - "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d", - !!clock_class_a->absolute, - !!clock_class_b->absolute); - goto end; - } - - /* Equal */ - ret = 0; - -end: - return ret; -} diff --git a/lib/ctf-writer/clock.c b/lib/ctf-writer/clock.c deleted file mode 100644 index f270ce3d..00000000 --- a/lib/ctf-writer/clock.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * clock.c - * - * Babeltrace CTF writer - Clock - * - * Copyright 2013, 2014 Jérémie Galarneau - * Copyright 2017 Philippe Proulx - * - * Author: Jérémie Galarneau - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-CLOCK" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static -void bt_ctf_clock_destroy(struct bt_ctf_object *obj); - -struct bt_ctf_clock *bt_ctf_clock_create(const char *name) -{ - int ret; - struct bt_ctf_clock *clock = NULL; - unsigned char cc_uuid[BABELTRACE_UUID_LEN]; - - BT_ASSERT_PRE_NON_NULL(name, "Name"); - clock = g_new0(struct bt_ctf_clock, 1); - if (!clock) { - goto error; - } - - bt_ctf_object_init_shared(&clock->base, bt_ctf_clock_destroy); - clock->value = 0; - - /* Pre-2.0.0 backward compatibility: default frequency is 1 GHz */ - clock->clock_class = (void *) bt_ctf_clock_class_create(name, 1000000000); - if (!clock->clock_class) { - goto error; - } - - /* Automatically set clock class's UUID. */ - ret = bt_uuid_generate(cc_uuid); - if (ret) { - goto error; - } - - ret = bt_ctf_clock_class_set_uuid(clock->clock_class, cc_uuid); - BT_ASSERT(ret == 0); - return clock; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(clock); - return clock; -} - -const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_get_name(clock->clock_class); -} - -const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_get_description(clock->clock_class); -} - -int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_set_description(clock->clock_class, - desc); -} - -uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_get_frequency(clock->clock_class); -} - -int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_set_frequency(clock->clock_class, - freq); -} - -uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_get_precision(clock->clock_class); -} - -int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_set_precision(clock->clock_class, - precision); -} - -int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, int64_t *offset_s) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_get_offset_s(clock->clock_class, - offset_s); -} - -int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, int64_t offset_s) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_set_offset_s(clock->clock_class, - offset_s); -} - -int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, int64_t *offset) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_get_offset_cycles(clock->clock_class, - offset); -} - -int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, int64_t offset) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_set_offset_cycles(clock->clock_class, - offset); -} - -int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_is_absolute(clock->clock_class); -} - -int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_set_is_absolute(clock->clock_class, - is_absolute); -} - -const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_get_uuid(clock->clock_class); -} - -int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, const unsigned char *uuid) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - return bt_ctf_clock_class_set_uuid(clock->clock_class, uuid); -} - -int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, int64_t time) -{ - int64_t value; - struct bt_ctf_clock_class *cc; - - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - cc = clock->clock_class; - - /* Common case where cycles are actually nanoseconds */ - if (cc->frequency == 1000000000) { - value = time; - } else { - value = (uint64_t) (((double) time * - (double) cc->frequency) / 1e9); - } - - BT_ASSERT_PRE(clock->value <= value, - "CTF writer clock value must be updated monotonically: " - "prev-value=%" PRId64 ", new-value=%" PRId64, - clock->value, value); - clock->value = value; - return 0; -} - -BT_HIDDEN -int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value) -{ - BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - *value = clock->value; - return 0; -} - -static -void bt_ctf_clock_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_clock *clock; - - clock = container_of(obj, struct bt_ctf_clock, base); - bt_ctf_object_put_ref(clock->clock_class); - g_free(clock); -} - -BT_HIDDEN -void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class, - struct metadata_context *context) -{ - unsigned char *uuid; - - BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, " - "name=\"%s\", metadata-context-addr=%p", clock_class, - bt_ctf_clock_class_get_name(clock_class), - context); - - if (!clock_class || !context) { - BT_LOGW("Invalid parameter: clock class or metadata context is NULL: " - "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p", - clock_class, - bt_ctf_clock_class_get_name(clock_class), - context); - return; - } - - uuid = clock_class->uuid; - g_string_append(context->string, "clock {\n"); - g_string_append_printf(context->string, "\tname = %s;\n", - clock_class->name->str); - - if (clock_class->uuid_set) { - g_string_append_printf(context->string, - "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - } - - if (clock_class->description) { - g_string_append_printf(context->string, "\tdescription = \"%s\";\n", - clock_class->description->str); - } - - g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n", - clock_class->frequency); - g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n", - clock_class->precision); - g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n", - clock_class->offset_s); - g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n", - clock_class->offset); - g_string_append_printf(context->string, "\tabsolute = %s;\n", - clock_class->absolute ? "true" : "false"); - g_string_append(context->string, "};\n\n"); -} diff --git a/lib/ctf-writer/event-class.c b/lib/ctf-writer/event-class.c deleted file mode 100644 index f918b86d..00000000 --- a/lib/ctf-writer/event-class.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright 2013, 2014 Jérémie Galarneau - * Copyright 2017-2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-EVENT-CLASS" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -BT_HIDDEN -void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj) -{ - struct bt_ctf_event_class_common *event_class; - - event_class = container_of(obj, struct bt_ctf_event_class_common, base); - BT_LOGD("Finalizing common event class: addr=%p, name=\"%s\", id=%" PRId64, - event_class, bt_ctf_event_class_common_get_name(event_class), - bt_ctf_event_class_common_get_id(event_class)); - - if (event_class->name) { - g_string_free(event_class->name, TRUE); - } - - if (event_class->emf_uri) { - g_string_free(event_class->emf_uri, TRUE); - } - - BT_LOGD_STR("Putting context field type."); - bt_ctf_object_put_ref(event_class->context_field_type); - BT_LOGD_STR("Putting payload field type."); - bt_ctf_object_put_ref(event_class->payload_field_type); -} - -BT_HIDDEN -int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class, - const char *name, bt_ctf_object_release_func release_func, - bt_ctf_field_type_structure_create_func ft_struct_create_func) -{ - int ret = 0; - - BT_LOGD("Initializing common event class object: name=\"%s\"", - name); - bt_ctf_object_init_shared_with_parent(&event_class->base, release_func); - event_class->payload_field_type = ft_struct_create_func(); - if (!event_class->payload_field_type) { - BT_LOGE_STR("Cannot create event class's initial payload field type object."); - goto error; - } - - event_class->id = -1; - event_class->name = g_string_new(name); - if (!event_class->name) { - BT_LOGE_STR("Failed to allocate a GString."); - goto error; - } - - event_class->emf_uri = g_string_new(NULL); - if (!event_class->emf_uri) { - BT_LOGE_STR("Failed to allocate a GString."); - goto error; - } - - event_class->log_level = BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED; - BT_LOGD("Initialized common event class object: addr=%p, name=\"%s\"", - event_class, bt_ctf_event_class_common_get_name(event_class)); - return ret; - -error: - ret = -1; - return ret; -} - -BT_HIDDEN -void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *event_class) -{ - BT_ASSERT(event_class); - - if (event_class->frozen) { - return; - } - - BT_LOGD("Freezing event class: addr=%p, name=\"%s\", id=%" PRId64, - event_class, bt_ctf_event_class_common_get_name(event_class), - bt_ctf_event_class_common_get_id(event_class)); - event_class->frozen = 1; - BT_LOGD_STR("Freezing event class's context field type."); - bt_ctf_field_type_common_freeze(event_class->context_field_type); - BT_LOGD_STR("Freezing event class's payload field type."); - bt_ctf_field_type_common_freeze(event_class->payload_field_type); -} - -BT_HIDDEN -int bt_ctf_event_class_common_validate_single_clock_class( - struct bt_ctf_event_class_common *event_class, - struct bt_ctf_clock_class **expected_clock_class) -{ - int ret = 0; - - BT_ASSERT(event_class); - BT_ASSERT(expected_clock_class); - ret = bt_ctf_field_type_common_validate_single_clock_class( - event_class->context_field_type, - expected_clock_class); - if (ret) { - BT_LOGW("Event class's context field type " - "is not recursively mapped to the " - "expected clock class: " - "event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", " - "ft-addr=%p", - event_class, - bt_ctf_event_class_common_get_name(event_class), - event_class->id, - event_class->context_field_type); - goto end; - } - - ret = bt_ctf_field_type_common_validate_single_clock_class( - event_class->payload_field_type, - expected_clock_class); - if (ret) { - BT_LOGW("Event class's payload field type " - "is not recursively mapped to the " - "expected clock class: " - "event-class-addr=%p, " - "event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", " - "ft-addr=%p", - event_class, - bt_ctf_event_class_common_get_name(event_class), - event_class->id, - event_class->payload_field_type); - goto end; - } - -end: - return ret; -} - -static -void bt_ctf_event_class_destroy(struct bt_ctf_object *obj) -{ - bt_ctf_event_class_common_finalize(obj); - g_free(obj); -} - -struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name) -{ - struct bt_ctf_event_class *ctf_event_class = NULL; - int ret; - - if (!name) { - BT_LOGW_STR("Invalid parameter: name is NULL."); - goto error; - } - - BT_LOGD("Creating event class object: name=\"%s\"", - name); - ctf_event_class = g_new0(struct bt_ctf_event_class, 1); - if (!ctf_event_class) { - BT_LOGE_STR("Failed to allocate one event class."); - goto error; - } - - ret = bt_ctf_event_class_common_initialize(BT_CTF_TO_COMMON(ctf_event_class), - name, bt_ctf_event_class_destroy, - (bt_ctf_field_type_structure_create_func) - bt_ctf_field_type_structure_create); - if (ret) { - goto error; - } - - goto end; - -error: - bt_ctf_object_put_ref(ctf_event_class); - -end: - return ctf_event_class; -} - -const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class) -{ - return bt_ctf_event_class_common_get_name(BT_CTF_TO_COMMON(event_class)); -} - -int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class) -{ - return bt_ctf_event_class_common_get_id(BT_CTF_TO_COMMON(event_class)); -} - -int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class, - uint64_t id) -{ - return bt_ctf_event_class_common_set_id(BT_CTF_TO_COMMON(event_class), id); -} - -enum bt_ctf_event_class_log_level bt_ctf_event_class_get_log_level( - struct bt_ctf_event_class *event_class) -{ - return bt_ctf_event_class_common_get_log_level(BT_CTF_TO_COMMON(event_class)); -} - -int bt_ctf_event_class_set_log_level(struct bt_ctf_event_class *event_class, - enum bt_ctf_event_class_log_level log_level) -{ - return bt_ctf_event_class_common_set_log_level(BT_CTF_TO_COMMON(event_class), - log_level); -} - -const char *bt_ctf_event_class_get_emf_uri( - struct bt_ctf_event_class *event_class) -{ - return bt_ctf_event_class_common_get_emf_uri(BT_CTF_TO_COMMON(event_class)); -} - -int bt_ctf_event_class_set_emf_uri(struct bt_ctf_event_class *event_class, - const char *emf_uri) -{ - return bt_ctf_event_class_common_set_emf_uri(BT_CTF_TO_COMMON(event_class), - emf_uri); -} - -struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class( - struct bt_ctf_event_class *event_class) -{ - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); - return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_stream_class( - BT_CTF_TO_COMMON(event_class))); -} - -struct bt_ctf_field_type *bt_ctf_event_class_get_payload_field_type( - struct bt_ctf_event_class *event_class) -{ - return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_payload_field_type( - BT_CTF_TO_COMMON(event_class))); -} - -int bt_ctf_event_class_set_payload_field_type( - struct bt_ctf_event_class *event_class, - struct bt_ctf_field_type *field_type) -{ - return bt_ctf_event_class_common_set_payload_field_type( - BT_CTF_TO_COMMON(event_class), (void *) field_type); -} - -struct bt_ctf_field_type *bt_ctf_event_class_get_context_field_type( - struct bt_ctf_event_class *event_class) -{ - return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_context_field_type( - BT_CTF_TO_COMMON(event_class))); -} - -int bt_ctf_event_class_set_context_field_type( - struct bt_ctf_event_class *event_class, - struct bt_ctf_field_type *field_type) -{ - return bt_ctf_event_class_common_set_context_field_type( - BT_CTF_TO_COMMON(event_class), (void *) field_type); -} - -int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, - struct bt_ctf_field_type *type, - const char *name) -{ - int ret = 0; - - if (!event_class || !type) { - BT_LOGW("Invalid parameter: event class or field type is NULL: " - "event-class-addr=%p, field-type-addr=%p", - event_class, type); - ret = -1; - goto end; - } - - if (!bt_ctf_identifier_is_valid(name)) { - BT_LOGW("Invalid parameter: event class's payload field type's field name is not a valid CTF identifier: " - "addr=%p, name=\"%s\", id=%" PRId64 ", field-name=\"%s\"", - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class), - name); - ret = -1; - goto end; - } - - if (event_class->common.frozen) { - BT_LOGW("Invalid parameter: event class is frozen: " - "addr=%p, name=\"%s\", id=%" PRId64, - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class)); - ret = -1; - goto end; - } - - if (!event_class->common.payload_field_type) { - BT_LOGW("Event class has no payload field type: " - "addr=%p, name=\"%s\", id=%" PRId64, - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class)); - ret = -1; - goto end; - } - - BT_ASSERT(bt_ctf_field_type_common_get_type_id( - event_class->common.payload_field_type) == - BT_CTF_FIELD_TYPE_ID_STRUCT); - ret = bt_ctf_field_type_structure_add_field( - (void *) event_class->common.payload_field_type, - (void *) type, name); - BT_LOGV("Added field to event class's payload field type: " - "event-class-addr=%p, event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", field-name=\"%s\", ft-addr=%p", - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class), name, type); -end: - return ret; -} - -int64_t bt_ctf_event_class_get_payload_type_field_count( - struct bt_ctf_event_class *event_class) -{ - int64_t ret; - - if (!event_class) { - BT_LOGW_STR("Invalid parameter: event class is NULL."); - ret = (int64_t) -1; - goto end; - } - - if (!event_class->common.payload_field_type) { - BT_LOGV("Event class has no payload field type: " - "addr=%p, name=\"%s\", id=%" PRId64, - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class)); - ret = (int64_t) -1; - goto end; - } - - BT_ASSERT(bt_ctf_field_type_common_get_type_id( - event_class->common.payload_field_type) == - BT_CTF_FIELD_TYPE_ID_STRUCT); - ret = bt_ctf_field_type_common_structure_get_field_count( - event_class->common.payload_field_type); -end: - return ret; -} - -int bt_ctf_event_class_get_payload_type_field_by_index( - struct bt_ctf_event_class *event_class, - const char **field_name, struct bt_ctf_field_type **field_type, - uint64_t index) -{ - int ret; - - if (!event_class) { - BT_LOGW_STR("Invalid parameter: event class is NULL."); - ret = -1; - goto end; - } - - if (!event_class->common.payload_field_type) { - BT_LOGV("Event class has no payload field type: " - "addr=%p, name=\"%s\", id=%" PRId64 ", index=%" PRIu64, - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class), index); - ret = -1; - goto end; - } - - BT_ASSERT(bt_ctf_field_type_common_get_type_id( - event_class->common.payload_field_type) == - BT_CTF_FIELD_TYPE_ID_STRUCT); - ret = bt_ctf_field_type_structure_get_field_by_index( - (void *) event_class->common.payload_field_type, - field_name, (void *) field_type, index); - -end: - return ret; -} - -struct bt_ctf_field_type * -bt_ctf_event_class_get_payload_type_field_type_by_name( - struct bt_ctf_event_class *event_class, const char *name) -{ - GQuark name_quark; - struct bt_ctf_field_type *field_type = NULL; - - if (!event_class || !name) { - BT_LOGW("Invalid parameter: event class or name is NULL: " - "event-class-addr=%p, name-addr=%p", - event_class, name); - goto end; - } - - if (!event_class->common.payload_field_type) { - BT_LOGV("Event class has no payload field type: " - "addr=%p, name=\"%s\", id=%" PRId64, - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class)); - goto end; - } - - BT_ASSERT(bt_ctf_field_type_common_get_type_id( - event_class->common.payload_field_type) == - BT_CTF_FIELD_TYPE_ID_STRUCT); - name_quark = g_quark_try_string(name); - if (!name_quark) { - BT_LOGE("Cannot get GQuark: string=\"%s\"", name); - goto end; - } - - /* - * No need to increment field_type's reference count since getting it - * from the structure already does. - */ - field_type = (void *) - bt_ctf_field_type_structure_get_field_type_by_name( - (void *) event_class->common.payload_field_type, name); - -end: - return field_type; -} - -BT_HIDDEN -int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class, - struct metadata_context *context) -{ - int ret = 0; - struct bt_ctf_value *attr_value = NULL; - - BT_ASSERT(event_class); - BT_ASSERT(context); - BT_LOGD("Serializing event class's metadata: " - "event-class-addr=%p, event-class-name=\"%s\", " - "event-class-id=%" PRId64 ", metadata-context-addr=%p", - event_class, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class), context); - context->current_indentation_level = 1; - g_string_assign(context->field_name, ""); - g_string_append(context->string, "event {\n"); - - /* Serialize attributes */ - g_string_append_printf(context->string, "\tname = \"%s\";\n", - event_class->common.name->str); - BT_ASSERT(event_class->common.id >= 0); - g_string_append_printf(context->string, "\tid = %" PRId64 ";\n", - event_class->common.id); - g_string_append_printf(context->string, "\tstream_id = %" PRId64 ";\n", - bt_ctf_stream_class_common_get_id( - bt_ctf_event_class_common_borrow_stream_class( - BT_CTF_TO_COMMON(event_class)))); - - if (event_class->common.log_level != - BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) { - g_string_append_printf(context->string, "\tloglevel = %d;\n", - (int) event_class->common.log_level); - } - - if (event_class->common.emf_uri->len > 0) { - g_string_append_printf(context->string, "\tmodel.emf.uri = \"%s\";\n", - event_class->common.emf_uri->str); - } - - /* Serialize context field type */ - if (event_class->common.context_field_type) { - g_string_append(context->string, "\tcontext := "); - BT_LOGD_STR("Serializing event class's context field type metadata."); - ret = bt_ctf_field_type_serialize_recursive( - (void *) event_class->common.context_field_type, - context); - if (ret) { - BT_LOGW("Cannot serialize event class's context field type's metadata: " - "ret=%d", ret); - goto end; - } - g_string_append(context->string, ";\n"); - } - - /* Serialize payload field type */ - if (event_class->common.payload_field_type) { - g_string_append(context->string, "\tfields := "); - BT_LOGD_STR("Serializing event class's payload field type metadata."); - ret = bt_ctf_field_type_serialize_recursive( - (void *) event_class->common.payload_field_type, - context); - if (ret) { - BT_LOGW("Cannot serialize event class's payload field type's metadata: " - "ret=%d", ret); - goto end; - } - g_string_append(context->string, ";\n"); - } - - g_string_append(context->string, "};\n\n"); - -end: - context->current_indentation_level = 0; - BT_CTF_OBJECT_PUT_REF_AND_RESET(attr_value); - return ret; -} - -struct bt_ctf_field_type *bt_ctf_event_class_get_field_by_name( - struct bt_ctf_event_class *event_class, const char *name) -{ - GQuark name_quark; - struct bt_ctf_field_type *field_type = NULL; - - if (!event_class || !name) { - BT_LOGW("Invalid parameter: event class or name is NULL: " - "event-class-addr=%p, name-addr=%p", - event_class, name); - goto end; - } - - if (!event_class->common.payload_field_type) { - BT_LOGV("Event class has no payload field type: " - "addr=%p, name=\"%s\", id=%" PRId64, - event_class, - bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class)); - goto end; - } - - BT_ASSERT(event_class->common.payload_field_type->id == - BT_CTF_FIELD_TYPE_ID_STRUCT); - name_quark = g_quark_try_string(name); - if (!name_quark) { - BT_LOGE("Cannot get GQuark: string=\"%s\"", name); - goto end; - } - - /* - * No need to increment field_type's reference count since getting it - * from the structure already does. - */ - field_type = bt_ctf_object_get_ref( - bt_ctf_field_type_common_structure_borrow_field_type_by_name( - event_class->common.payload_field_type, name)); - -end: - return field_type; -} diff --git a/lib/ctf-writer/event.c b/lib/ctf-writer/event.c deleted file mode 100644 index 62df18b2..00000000 --- a/lib/ctf-writer/event.c +++ /dev/null @@ -1,900 +0,0 @@ -/* - * Copyright 2013, 2014 Jérémie Galarneau - * Copyright 2017-2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-EVENT" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static -int bt_ctf_event_common_validate_types_for_create( - struct bt_ctf_event_class_common *event_class, - struct bt_ctf_validation_output *validation_output, - bt_ctf_validation_flag_copy_field_type_func copy_field_type_func) -{ - int ret; - enum bt_ctf_validation_flag validation_flags = - BT_CTF_VALIDATION_FLAG_STREAM | - BT_CTF_VALIDATION_FLAG_EVENT; - struct bt_ctf_trace_common *trace = NULL; - struct bt_ctf_stream_class_common *stream_class = NULL; - struct bt_ctf_field_type_common *packet_header_type = NULL; - struct bt_ctf_field_type_common *packet_context_type = NULL; - struct bt_ctf_field_type_common *event_header_type = NULL; - struct bt_ctf_field_type_common *stream_event_ctx_type = NULL; - struct bt_ctf_field_type_common *event_context_type = NULL; - struct bt_ctf_field_type_common *event_payload_type = NULL; - int trace_valid = 0; - struct bt_ctf_private_value *environment = NULL; - - stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class); - BT_ASSERT(stream_class); - trace = bt_ctf_stream_class_common_borrow_trace(stream_class); - if (trace) { - BT_LOGD_STR("Event class is part of a trace."); - packet_header_type = - bt_ctf_trace_common_borrow_packet_header_field_type(trace); - trace_valid = trace->valid; - BT_ASSERT(trace_valid); - environment = trace->environment; - } - - packet_context_type = - bt_ctf_stream_class_common_borrow_packet_context_field_type( - stream_class); - event_header_type = - bt_ctf_stream_class_common_borrow_event_header_field_type( - stream_class); - stream_event_ctx_type = - bt_ctf_stream_class_common_borrow_event_context_field_type( - stream_class); - event_context_type = - bt_ctf_event_class_common_borrow_context_field_type(event_class); - event_payload_type = - bt_ctf_event_class_common_borrow_payload_field_type(event_class); - ret = bt_ctf_validate_class_types(environment, packet_header_type, - packet_context_type, event_header_type, stream_event_ctx_type, - event_context_type, event_payload_type, trace_valid, - stream_class->valid, event_class->valid, - validation_output, validation_flags, copy_field_type_func); - if (ret) { - /* - * This means something went wrong during the validation - * process, not that the objects are invalid. - */ - BT_LOGE("Failed to validate event and parents: ret=%d", ret); - goto error; - } - - if ((validation_output->valid_flags & validation_flags) != - validation_flags) { - /* Invalid trace/stream class/event class */ - BT_LOGW("Invalid trace, stream class, or event class: " - "valid-flags=0x%x", validation_output->valid_flags); - goto error; - } - - goto end; - -error: - bt_ctf_validation_output_put_types(validation_output); - ret = -1; - -end: - return ret; -} - -static -int bt_ctf_event_common_create_fields( - struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_validation_output *validation_output, - create_field_func create_field_func, - release_field_func release_field_func, - create_header_field_func create_header_field_func, - release_header_field_func release_header_field_func, - struct bt_ctf_field_wrapper **header_field, - struct bt_ctf_field_common **stream_event_context_field, - struct bt_ctf_field_common **context_field, - struct bt_ctf_field_common **payload_field) -{ - int ret = 0; - - if (validation_output->event_header_type) { - BT_LOGD("Creating initial event header field: ft-addr=%p", - validation_output->event_header_type); - *header_field = - create_header_field_func(stream_class, - validation_output->event_header_type); - if (!*header_field) { - BT_LOGE_STR("Cannot create initial event header field object."); - goto error; - } - } - - if (validation_output->stream_event_ctx_type) { - BT_LOGD("Creating initial stream event context field: ft-addr=%p", - validation_output->stream_event_ctx_type); - *stream_event_context_field = create_field_func( - validation_output->stream_event_ctx_type); - if (!*stream_event_context_field) { - BT_LOGE_STR("Cannot create initial stream event context field object."); - goto error; - } - } - - if (validation_output->event_context_type) { - BT_LOGD("Creating initial event context field: ft-addr=%p", - validation_output->event_context_type); - *context_field = create_field_func( - validation_output->event_context_type); - if (!*context_field) { - BT_LOGE_STR("Cannot create initial event context field object."); - goto error; - } - } - - if (validation_output->event_payload_type) { - BT_LOGD("Creating initial event payload field: ft-addr=%p", - validation_output->event_payload_type); - *payload_field = create_field_func( - validation_output->event_payload_type); - if (!*payload_field) { - BT_LOGE_STR("Cannot create initial event payload field object."); - goto error; - } - } - - goto end; - -error: - if (*header_field) { - release_header_field_func(*header_field, stream_class); - } - - if (*stream_event_context_field) { - release_field_func(*stream_event_context_field); - } - - if (*context_field) { - release_field_func(*context_field); - } - - if (*payload_field) { - release_field_func(*payload_field); - } - - ret = -1; - -end: - return ret; -} - -BT_HIDDEN -int _bt_ctf_event_common_validate(struct bt_ctf_event_common *event) -{ - int ret = 0; - struct bt_ctf_stream_class_common *stream_class; - - BT_ASSERT(event); - if (event->header_field) { - ret = bt_ctf_field_common_validate_recursive( - event->header_field->field); - if (ret) { - BT_ASSERT_PRE_MSG("Invalid event's header field: " - "event-addr=%p, field-addr=%p", - event, event->header_field->field); - goto end; - } - } - - stream_class = bt_ctf_event_class_common_borrow_stream_class(event->class); - - /* - * We should not have been able to create the event without associating - * the event class to a stream class. - */ - BT_ASSERT(stream_class); - - if (stream_class->event_context_field_type) { - ret = bt_ctf_field_common_validate_recursive( - event->stream_event_context_field); - if (ret) { - BT_ASSERT_PRE_MSG("Invalid event's stream event context field: " - "event-addr=%p, field-addr=%p", - event, event->stream_event_context_field); - goto end; - } - } - - if (event->class->context_field_type) { - ret = bt_ctf_field_common_validate_recursive(event->context_field); - if (ret) { - BT_ASSERT_PRE_MSG("Invalid event's payload field: " - "event-addr=%p, field-addr=%p", - event, event->context_field); - goto end; - } - } - - ret = bt_ctf_field_common_validate_recursive(event->payload_field); - if (ret) { - BT_ASSERT_PRE_MSG("Invalid event's payload field: " - "event-addr=%p, field-addr=%p", - event, event->payload_field); - goto end; - } - -end: - return ret; -} - -BT_HIDDEN -void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event, - bool is_frozen) -{ - BT_ASSERT(event); - BT_LOGD("Freezing event: addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64, - event, bt_ctf_event_class_common_get_name(event->class), - bt_ctf_event_class_common_get_id(event->class)); - - if (event->header_field) { - BT_LOGD_STR("Freezing event's header field."); - bt_ctf_field_common_set_is_frozen_recursive( - event->header_field->field, is_frozen); - } - - if (event->stream_event_context_field) { - BT_LOGD_STR("Freezing event's stream event context field."); - bt_ctf_field_common_set_is_frozen_recursive( - event->stream_event_context_field, is_frozen); - } - - if (event->context_field) { - BT_LOGD_STR("Freezing event's context field."); - bt_ctf_field_common_set_is_frozen_recursive(event->context_field, - is_frozen); - } - - if (event->payload_field) { - BT_LOGD_STR("Freezing event's payload field."); - bt_ctf_field_common_set_is_frozen_recursive(event->payload_field, - is_frozen); - } - - event->frozen = is_frozen; -} - -BT_HIDDEN -int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event, - struct bt_ctf_event_class_common *event_class, - struct bt_ctf_clock_class *init_expected_clock_class, - bool is_shared_with_parent, bt_ctf_object_release_func release_func, - bt_ctf_validation_flag_copy_field_type_func field_type_copy_func, - bool must_be_in_trace, - int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_field_type_common *packet_context_field_type, - struct bt_ctf_field_type_common *event_header_field_type), - create_field_func create_field_func, - release_field_func release_field_func, - create_header_field_func create_header_field_func, - release_header_field_func release_header_field_func) -{ - int ret; - struct bt_ctf_trace_common *trace = NULL; - struct bt_ctf_stream_class_common *stream_class = NULL; - struct bt_ctf_field_wrapper *event_header = NULL; - struct bt_ctf_field_common *stream_event_context = NULL; - struct bt_ctf_field_common *event_context = NULL; - struct bt_ctf_field_common *event_payload = NULL; - struct bt_ctf_validation_output validation_output = { 0 }; - struct bt_ctf_clock_class *expected_clock_class = - init_expected_clock_class ? bt_ctf_object_get_ref(init_expected_clock_class) : - NULL; - - BT_ASSERT_PRE_NON_NULL(event_class, "Event class"); - BT_LOGD("Initializing common event object: event-class-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64, - event_class, bt_ctf_event_class_common_get_name(event_class), - bt_ctf_event_class_common_get_id(event_class)); - - stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class); - BT_ASSERT_PRE(stream_class, - "Event class is not part of a stream class: event-class-addr=%p", - event_class); - - /* The event class was frozen when added to its stream class */ - BT_ASSERT(event_class->frozen); - trace = bt_ctf_stream_class_common_borrow_trace(stream_class); - - if (must_be_in_trace) { - BT_ASSERT_PRE(trace, - "Event class's stream class is not part of a trace: " - "ec-addr=%p, sc-addr=%p", event_class, stream_class); - } - - /* - * This must be called before anything that can fail because on - * failure, the caller releases the reference to `event` to - * destroy it. - */ - if (is_shared_with_parent) { - bt_ctf_object_init_shared_with_parent(&event->base, release_func); - } else { - bt_ctf_object_init_unique(&event->base); - } - - if (!stream_class->frozen) { - /* - * Because this function freezes the stream class, - * validate that this stream class contains at most a - * single clock class so that we set its expected clock - * class for future checks. - */ - ret = bt_ctf_stream_class_common_validate_single_clock_class( - stream_class, &expected_clock_class); - if (ret) { - BT_LOGW("Event class's stream class or one of its event " - "classes contains a field type which is not " - "recursively mapped to the expected " - "clock class: " - "stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", " - "stream-class-name=\"%s\", " - "expected-clock-class-addr=%p, " - "expected-clock-class-name=\"%s\"", - stream_class, - bt_ctf_stream_class_common_get_id(stream_class), - bt_ctf_stream_class_common_get_name(stream_class), - expected_clock_class, - expected_clock_class ? - bt_ctf_clock_class_get_name(expected_clock_class) : - NULL); - goto error; - } - } - - /* Validate the trace, the stream class, and the event class */ - ret = bt_ctf_event_common_validate_types_for_create( - event_class, &validation_output, field_type_copy_func); - if (ret) { - /* bt_ctf_event_common_validate_types_for_create() logs errors */ - goto error; - } - - if (map_clock_classes_func) { - /* - * Safe to automatically map selected fields to the - * stream's clock's class here because the stream class - * is about to be frozen. - */ - if (map_clock_classes_func(stream_class, - validation_output.packet_context_type, - validation_output.event_header_type)) { - BT_LOGW_STR("Cannot automatically map selected stream class's " - "field types to stream class's clock's class."); - goto error; - } - } - - /* - * event does not share a common ancestor with the event class; it has - * to guarantee its existence by holding a reference. This reference - * shall be released once the event is associated to a stream since, - * from that point, the event and its class will share the same - * lifetime. - */ - event->class = bt_ctf_object_get_ref(event_class); - - ret = bt_ctf_event_common_create_fields(stream_class, - &validation_output, - create_field_func, release_field_func, - create_header_field_func, release_header_field_func, - &event_header, &stream_event_context, &event_context, - &event_payload); - if (ret) { - /* bt_ctf_event_common_create_fields() logs errors */ - goto error; - } - - /* - * At this point all the fields are created, potentially from - * validated copies of field types, so that the field types and - * fields can be replaced in the trace, stream class, - * event class, and created event. - */ - bt_ctf_validation_replace_types(trace, stream_class, event_class, - &validation_output, - BT_CTF_VALIDATION_FLAG_STREAM | BT_CTF_VALIDATION_FLAG_EVENT); - event->header_field = event_header; - event_header = NULL; - event->stream_event_context_field = stream_event_context; - stream_event_context = NULL; - event->context_field = event_context; - event_context = NULL; - event->payload_field = event_payload; - event_payload = NULL; - - /* - * Put what was not moved in bt_ctf_validation_replace_types(). - */ - bt_ctf_validation_output_put_types(&validation_output); - - /* - * Freeze the stream class since the event header must not be changed - * anymore. - */ - bt_ctf_stream_class_common_freeze(stream_class); - - /* - * It is safe to set the stream class's unique clock class - * now because the stream class is frozen. - */ - if (expected_clock_class) { - BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class); - } - - /* - * Mark stream class, and event class as valid since - * they're all frozen now. - */ - stream_class->valid = 1; - event_class->valid = 1; - - /* Put stuff we borrowed from the event class */ - BT_LOGD("Initialized event object: addr=%p, event-class-name=\"%s\", " - "event-class-id=%" PRId64, - event, bt_ctf_event_class_common_get_name(event->class), - bt_ctf_event_class_common_get_id(event->class)); - goto end; - -error: - bt_ctf_validation_output_put_types(&validation_output); - bt_ctf_object_put_ref(expected_clock_class); - - if (event_header) { - release_header_field_func(event_header, stream_class); - } - - if (stream_event_context) { - release_field_func(stream_event_context); - } - - if (event_context) { - release_field_func(event_context); - } - - if (event_payload) { - release_field_func(event_payload); - } - - ret = -1; - -end: - return ret; -} - -int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_field_type_common *packet_context_type, - struct bt_ctf_field_type_common *event_header_type) -{ - int ret = bt_ctf_stream_class_map_clock_class( - BT_CTF_FROM_COMMON(stream_class), - BT_CTF_FROM_COMMON(packet_context_type), - BT_CTF_FROM_COMMON(event_header_type)); - - if (ret) { - BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class."); - } - - return ret; -} - -static -void destroy_event_header_field(struct bt_ctf_field_wrapper *field_wrapper) -{ - BT_ASSERT(field_wrapper); - bt_ctf_object_put_ref(field_wrapper->field); - bt_ctf_field_wrapper_destroy(field_wrapper); -} - -static -struct bt_ctf_field_wrapper *create_event_header_field( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_wrapper *field_wrapper = NULL; - struct bt_ctf_field *field = bt_ctf_field_create((void *) ft); - - if (!field) { - goto error; - } - - field_wrapper = bt_ctf_field_wrapper_new(NULL); - if (!field_wrapper) { - goto error; - } - - field_wrapper->field = (void *) field; - field = NULL; - goto end; - -error: - bt_ctf_object_put_ref(field); - - if (field_wrapper) { - destroy_event_header_field(field_wrapper); - field_wrapper = NULL; - } - -end: - return field_wrapper; -} - -static -void release_event_header_field(struct bt_ctf_field_wrapper *field_wrapper, - struct bt_ctf_event_common *event_common) -{ - BT_ASSERT(field_wrapper); - BT_CTF_OBJECT_PUT_REF_AND_RESET(field_wrapper->field); - bt_ctf_field_wrapper_destroy(field_wrapper); -} - -static -void bt_ctf_event_destroy(struct bt_ctf_object *obj) -{ - bt_ctf_event_common_finalize(obj, (void *) bt_ctf_object_put_ref, - (void *) release_event_header_field); - g_free(obj); -} - -struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class) -{ - int ret; - struct bt_ctf_event *event = NULL; - struct bt_ctf_clock_class *expected_clock_class = NULL; - - event = g_new0(struct bt_ctf_event, 1); - if (!event) { - BT_LOGE_STR("Failed to allocate one CTF writer event."); - goto error; - } - - if (event_class) { - struct bt_ctf_stream_class *stream_class = - BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class( - BT_CTF_TO_COMMON(event_class))); - - if (stream_class && stream_class->clock) { - expected_clock_class = stream_class->clock->clock_class; - } - } - - ret = bt_ctf_event_common_initialize(BT_CTF_TO_COMMON(event), - BT_CTF_TO_COMMON(event_class), expected_clock_class, - true, bt_ctf_event_destroy, - (bt_ctf_validation_flag_copy_field_type_func) - bt_ctf_field_type_copy, - false, map_clock_classes_func, - (create_field_func) bt_ctf_field_create, - (release_field_func) bt_ctf_object_put_ref, - (create_header_field_func) create_event_header_field, - (release_header_field_func) destroy_event_header_field); - if (ret) { - /* bt_ctf_event_common_initialize() logs errors */ - goto error; - } - - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(event); - -end: - return event; -} - -struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event) -{ - BT_ASSERT_PRE_NON_NULL(event, "Event"); - return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))); -} - -BT_HIDDEN -struct bt_ctf_stream *bt_ctf_event_borrow_stream(struct bt_ctf_event *event) -{ - BT_ASSERT(event); - return (struct bt_ctf_stream *) - bt_ctf_object_borrow_parent(&BT_CTF_TO_COMMON(event)->base); -} - -struct bt_ctf_stream *bt_ctf_event_get_stream(struct bt_ctf_event *event) -{ - BT_ASSERT_PRE_NON_NULL(event, "Event"); - return bt_ctf_object_get_ref(bt_ctf_event_borrow_stream(event)); -} - -int bt_ctf_event_set_payload(struct bt_ctf_event *event, const char *name, - struct bt_ctf_field *field) -{ - BT_ASSERT_PRE_NON_NULL(event, "Event"); - BT_ASSERT_PRE_NON_NULL(field, "Payload field"); - BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); - return bt_ctf_field_structure_set_field_by_name( - (void *) event->common.payload_field, name, field); -} - -struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event, - const char *name) -{ - struct bt_ctf_field *field = NULL; - - BT_ASSERT_PRE_NON_NULL(event, "Event"); - - if (name) { - field = bt_ctf_field_structure_get_field_by_name( - BT_CTF_FROM_COMMON(event->common.payload_field), name); - } else { - field = BT_CTF_FROM_COMMON(event->common.payload_field); - bt_ctf_object_get_ref(field); - } - - return field; -} - -struct bt_ctf_field *bt_ctf_event_get_payload_field( - struct bt_ctf_event *event) -{ - return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_payload(BT_CTF_TO_COMMON(event))); -} - -struct bt_ctf_field *bt_ctf_event_get_header(struct bt_ctf_event *event) -{ - return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_header(BT_CTF_TO_COMMON(event))); -} - -struct bt_ctf_field *bt_ctf_event_get_context(struct bt_ctf_event *event) -{ - return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_context(BT_CTF_TO_COMMON(event))); -} - -struct bt_ctf_field *bt_ctf_event_get_stream_event_context( - struct bt_ctf_event *event) -{ - return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_stream_event_context( - BT_CTF_TO_COMMON(event))); -} - -BT_HIDDEN -int bt_ctf_event_serialize(struct bt_ctf_event *event, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - int ret = 0; - - BT_ASSERT(event); - BT_ASSERT(ctfser); - - BT_LOGV_STR("Serializing event's context field."); - if (event->common.context_field) { - ret = bt_ctf_field_serialize_recursive( - (void *) event->common.context_field, ctfser, - native_byte_order); - if (ret) { - BT_LOGW("Cannot serialize event's context field: " - "event-addr=%p, event-class-name=\"%s\", " - "event-class-id=%" PRId64, - event, - bt_ctf_event_class_common_get_name(event->common.class), - bt_ctf_event_class_common_get_id(event->common.class)); - goto end; - } - } - - BT_LOGV_STR("Serializing event's payload field."); - if (event->common.payload_field) { - ret = bt_ctf_field_serialize_recursive( - (void *) event->common.payload_field, ctfser, - native_byte_order); - if (ret) { - BT_LOGW("Cannot serialize event's payload field: " - "event-addr=%p, event-class-name=\"%s\", " - "event-class-id=%" PRId64, - event, - bt_ctf_event_class_common_get_name(event->common.class), - bt_ctf_event_class_common_get_id(event->common.class)); - goto end; - } - } - -end: - return ret; -} - -BT_HIDDEN -void _bt_ctf_event_freeze(struct bt_ctf_event *event) -{ - _bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true); -} - -int bt_ctf_event_set_header(struct bt_ctf_event *event, - struct bt_ctf_field *header) -{ - BT_ASSERT_PRE_NON_NULL(event, "Event"); - BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); - - /* - * Ensure the provided header's type matches the one registered to the - * stream class. - */ - if (header) { - BT_ASSERT_PRE(bt_ctf_field_type_common_compare( - ((struct bt_ctf_field_common *) header)->type, - bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type) == 0, - "Header field's type is different from the " - "expected field type: event-addr=%p, ft-addr=%p, " - "expected-ft-addr=%p", - event, ((struct bt_ctf_field_common *) header)->type, - bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type); - } else { - BT_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type, - "Setting no event header field, " - "but event header field type is not NULL: ", - "event-addr=%p, header-ft-addr=%p", - event, - bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type); - } - - bt_ctf_object_put_ref(event->common.header_field->field); - event->common.header_field->field = bt_ctf_object_get_ref(header); - BT_LOGV("Set event's header field: event-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "header-field-addr=%p", - event, bt_ctf_event_class_common_get_name(event->common.class), - bt_ctf_event_class_common_get_id(event->common.class), header); - return 0; -} - -int bt_ctf_event_common_set_payload(struct bt_ctf_event *event, - struct bt_ctf_field *payload) -{ - BT_ASSERT_PRE_NON_NULL(event, "Event"); - BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); - - if (payload) { - BT_ASSERT_PRE(bt_ctf_field_type_common_compare( - ((struct bt_ctf_field_common *) payload)->type, - event->common.class->payload_field_type) == 0, - "Payload field's type is different from the " - "expected field type: event-addr=%p, ft-addr=%p, " - "expected-ft-addr=%p", - event, - ((struct bt_ctf_field_common *) payload)->type, - event->common.class->payload_field_type); - } else { - BT_ASSERT_PRE(!event->common.class->payload_field_type, - "Setting no event payload field, " - "but event payload field type is not NULL: ", - "event-addr=%p, payload-ft-addr=%p", - event, event->common.class->payload_field_type); - } - - bt_ctf_object_put_ref(event->common.payload_field); - event->common.payload_field = bt_ctf_object_get_ref(payload); - BT_LOGV("Set event's payload field: event-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "payload-field-addr=%p", - event, bt_ctf_event_class_common_get_name(event->common.class), - bt_ctf_event_class_common_get_id(event->common.class), payload); - return 0; -} - -int bt_ctf_event_set_context(struct bt_ctf_event *event, - struct bt_ctf_field *context) -{ - BT_ASSERT_PRE_NON_NULL(event, "Event"); - BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); - - if (context) { - BT_ASSERT_PRE(bt_ctf_field_type_common_compare( - ((struct bt_ctf_field_common *) context)->type, - event->common.class->context_field_type) == 0, - "Context field's type is different from the " - "expected field type: event-addr=%p, ft-addr=%p, " - "expected-ft-addr=%p", - event, ((struct bt_ctf_field_common *) context)->type, - event->common.class->context_field_type); - } else { - BT_ASSERT_PRE(!event->common.class->context_field_type, - "Setting no event context field, " - "but event context field type is not NULL: ", - "event-addr=%p, context-ft-addr=%p", - event, event->common.class->context_field_type); - } - - bt_ctf_object_put_ref(event->common.context_field); - event->common.context_field = bt_ctf_object_get_ref(context); - BT_LOGV("Set event's context field: event-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "context-field-addr=%p", - event, bt_ctf_event_class_common_get_name(event->common.class), - bt_ctf_event_class_common_get_id(event->common.class), context); - return 0; -} - -int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event, - struct bt_ctf_field *stream_event_context) -{ - BT_ASSERT_PRE_NON_NULL(event, "Event"); - BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event"); - - if (stream_event_context) { - BT_ASSERT_PRE(bt_ctf_field_type_common_compare( - ((struct bt_ctf_field_common *) stream_event_context)->type, - bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type) == 0, - "Stream event context field's type is different from the " - "expected field type: event-addr=%p, ft-addr=%p, " - "expected-ft-addr=%p", - event, - ((struct bt_ctf_field_common *) stream_event_context)->type, - bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type); - } else { - BT_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type, - "Setting no stream event context field, " - "but stream event context field type is not NULL: ", - "event-addr=%p, context-ft-addr=%p", - event, - bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type); - } - - bt_ctf_object_put_ref(event->common.stream_event_context_field); - event->common.stream_event_context_field = bt_ctf_object_get_ref(stream_event_context); - BT_LOGV("Set event's stream event context field: event-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "stream-event-context-field-addr=%p", - event, bt_ctf_event_class_common_get_name(event->common.class), - bt_ctf_event_class_common_get_id(event->common.class), - stream_event_context); - return 0; -} diff --git a/lib/ctf-writer/field-path.c b/lib/ctf-writer/field-path.c deleted file mode 100644 index eb6c0353..00000000 --- a/lib/ctf-writer/field-path.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * field-path.c - * - * Babeltrace CTF writer - Field path - * - * Copyright 2013, 2014 Jérémie Galarneau - * Copyright 2016 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-FIELD-PATH" -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -static -void field_path_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_path *field_path = (struct bt_ctf_field_path *) obj; - - BT_LOGD("Destroying field path: addr=%p", obj); - - if (!field_path) { - return; - } - - if (field_path->indexes) { - g_array_free(field_path->indexes, TRUE); - } - g_free(field_path); -} - -BT_HIDDEN -struct bt_ctf_field_path *bt_ctf_field_path_create(void) -{ - struct bt_ctf_field_path *field_path = NULL; - - BT_LOGD_STR("Creating empty field path object."); - - field_path = g_new0(struct bt_ctf_field_path, 1); - if (!field_path) { - BT_LOGE_STR("Failed to allocate one field path."); - goto error; - } - - bt_ctf_object_init_shared(&field_path->base, field_path_destroy); - field_path->root = BT_CTF_SCOPE_UNKNOWN; - field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int)); - if (!field_path->indexes) { - BT_LOGE_STR("Failed to allocate a GArray."); - goto error; - } - - BT_LOGD("Created empty field path object: addr=%p", field_path); - return field_path; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path); - return NULL; -} - -BT_HIDDEN -void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path) -{ - if (field_path->indexes->len > 0) { - g_array_remove_range(field_path->indexes, 0, - field_path->indexes->len); - } -} - -BT_HIDDEN -struct bt_ctf_field_path *bt_ctf_field_path_copy( - struct bt_ctf_field_path *path) -{ - struct bt_ctf_field_path *new_path; - - BT_ASSERT(path); - BT_LOGD("Copying field path: addr=%p, index-count=%u", - path, path->indexes->len); - new_path = bt_ctf_field_path_create(); - if (!new_path) { - BT_LOGE_STR("Cannot create empty field path."); - goto end; - } - - new_path->root = path->root; - g_array_insert_vals(new_path->indexes, 0, - path->indexes->data, path->indexes->len); - BT_LOGD("Copied field path: original-addr=%p, copy-addr=%p", - path, new_path); -end: - return new_path; -} - -enum bt_ctf_scope bt_ctf_field_path_get_root_scope( - const struct bt_ctf_field_path *field_path) -{ - enum bt_ctf_scope scope = BT_CTF_SCOPE_UNKNOWN; - - if (!field_path) { - BT_LOGW_STR("Invalid parameter: field path is NULL."); - goto end; - } - - scope = field_path->root; - -end: - return scope; -} - -int64_t bt_ctf_field_path_get_index_count( - const struct bt_ctf_field_path *field_path) -{ - int64_t count = (int64_t) -1; - - if (!field_path) { - BT_LOGW_STR("Invalid parameter: field path is NULL."); - goto end; - } - - count = (int64_t) field_path->indexes->len; - -end: - return count; -} - -int bt_ctf_field_path_get_index(const struct bt_ctf_field_path *field_path, - uint64_t index) -{ - int ret = INT_MIN; - - if (!field_path) { - BT_LOGW_STR("Invalid parameter: field path is NULL."); - goto end; - } - - if (index >= field_path->indexes->len) { - BT_LOGW("Invalid parameter: index is out of bounds: " - "addr=%p, index=%" PRIu64 ", count=%u", - field_path, index, field_path->indexes->len); - goto end; - } - - ret = g_array_index(field_path->indexes, int, index); - -end: - return ret; -} diff --git a/lib/ctf-writer/field-types.c b/lib/ctf-writer/field-types.c deleted file mode 100644 index 64cdcd17..00000000 --- a/lib/ctf-writer/field-types.c +++ /dev/null @@ -1,5564 +0,0 @@ -/* - * Copyright 2013, 2014 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-FIELD-TYPES" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static -void destroy_enumeration_mapping(struct bt_ctf_enumeration_mapping *mapping) -{ - g_free(mapping); -} - -BT_HIDDEN -void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft, - bool init_bo, bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - BT_ASSERT(ft && (ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN) && - (ft->id < BT_CTF_FIELD_TYPE_ID_NR)); - - bt_ctf_object_init_shared(&ft->base, release_func); - ft->methods = methods; - - if (init_bo) { - int ret; - const enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_NATIVE; - - BT_LOGD("Setting initial field type's byte order: bo=%s", - bt_ctf_byte_order_string(bo)); - ret = bt_ctf_field_type_common_set_byte_order(ft, bo); - BT_ASSERT(ret == 0); - } - - ft->alignment = 1; -} - -BT_HIDDEN -void bt_ctf_field_type_common_integer_initialize( - struct bt_ctf_field_type_common *ft, - unsigned int size, bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT(size > 0); - BT_LOGD("Initializing common integer field type object: size=%u", - size); - ft->id = BT_CTF_FIELD_TYPE_ID_INTEGER; - int_ft->size = size; - int_ft->base = BT_CTF_INTEGER_BASE_DECIMAL; - int_ft->encoding = BT_CTF_STRING_ENCODING_NONE; - bt_ctf_field_type_common_initialize(ft, true, release_func, methods); - BT_LOGD("Initialized common integer field type object: addr=%p, size=%u", - ft, size); -} - -BT_HIDDEN -void bt_ctf_field_type_common_floating_point_initialize( - struct bt_ctf_field_type_common *ft, - bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); - - BT_LOGD_STR("Initializing common floating point number field type object."); - ft->id = BT_CTF_FIELD_TYPE_ID_FLOAT; - flt_ft->exp_dig = sizeof(float) * CHAR_BIT - FLT_MANT_DIG; - flt_ft->mant_dig = FLT_MANT_DIG; - bt_ctf_field_type_common_initialize(ft, true, release_func, methods); - BT_LOGD("Initialized common floating point number field type object: addr=%p, " - "exp-size=%u, mant-size=%u", ft, flt_ft->exp_dig, - flt_ft->mant_dig); -} - -BT_HIDDEN -void bt_ctf_field_type_common_enumeration_initialize( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *container_ft, - bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT(container_ft); - BT_LOGD("Initializing common enumeration field type object: int-ft-addr=%p", - container_ft); - ft->id = BT_CTF_FIELD_TYPE_ID_ENUM; - enum_ft->container_ft = bt_ctf_object_get_ref(container_ft); - enum_ft->entries = g_ptr_array_new_with_free_func( - (GDestroyNotify) destroy_enumeration_mapping); - bt_ctf_field_type_common_initialize(ft, false, release_func, methods); - BT_LOGD("Initialized common enumeration field type object: addr=%p, " - "int-ft-addr=%p, int-ft-size=%u", ft, container_ft, - bt_ctf_field_type_common_integer_get_size(container_ft)); -} - -BT_HIDDEN -void bt_ctf_field_type_common_string_initialize( - struct bt_ctf_field_type_common *ft, - bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft); - - BT_LOGD_STR("Initializing common string field type object."); - ft->id = BT_CTF_FIELD_TYPE_ID_STRING; - bt_ctf_field_type_common_initialize(ft, true, release_func, methods); - string_ft->encoding = BT_CTF_STRING_ENCODING_UTF8; - ft->alignment = CHAR_BIT; - BT_LOGD("Initialized common string field type object: addr=%p", ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_structure_initialize( - struct bt_ctf_field_type_common *ft, - bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - - BT_LOGD_STR("Initializing common structure field type object."); - ft->id = BT_CTF_FIELD_TYPE_ID_STRUCT; - struct_ft->fields = g_array_new(FALSE, TRUE, - sizeof(struct bt_ctf_field_type_common_structure_field)); - struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL); - bt_ctf_field_type_common_initialize(ft, true, release_func, methods); - BT_LOGD("Initialized common structure field type object: addr=%p", ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_array_initialize( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *element_ft, - unsigned int length, bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT(element_ft); - BT_LOGD("Initializing common array field type object: element-ft-addr=%p, " - "length=%u", element_ft, length); - ft->id = BT_CTF_FIELD_TYPE_ID_ARRAY; - array_ft->element_ft = bt_ctf_object_get_ref(element_ft); - array_ft->length = length; - bt_ctf_field_type_common_initialize(ft, false, release_func, methods); - BT_LOGD("Initialized common array field type object: addr=%p, " - "element-ft-addr=%p, length=%u", ft, element_ft, length); -} - -BT_HIDDEN -void bt_ctf_field_type_common_sequence_initialize( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *element_ft, - const char *length_field_name, - bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT(element_ft); - BT_ASSERT(length_field_name); - BT_ASSERT(bt_ctf_identifier_is_valid(length_field_name)); - BT_LOGD("Initializing common sequence field type object: element-ft-addr=%p, " - "length-field-name=\"%s\"", element_ft, length_field_name); - ft->id = BT_CTF_FIELD_TYPE_ID_SEQUENCE; - seq_ft->element_ft = bt_ctf_object_get_ref(element_ft); - seq_ft->length_field_name = g_string_new(length_field_name); - bt_ctf_field_type_common_initialize(ft, false, release_func, methods); - BT_LOGD("Initialized common sequence field type object: addr=%p, " - "element-ft-addr=%p, length-field-name=\"%s\"", - ft, element_ft, length_field_name); -} - -BT_HIDDEN -void bt_ctf_field_type_common_variant_initialize( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *tag_ft, - const char *tag_name, - bt_ctf_object_release_func release_func, - struct bt_ctf_field_type_common_methods *methods) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT(!tag_name || bt_ctf_identifier_is_valid(tag_name)); - BT_LOGD("Initializing common variant field type object: " - "tag-ft-addr=%p, tag-field-name=\"%s\"", - tag_ft, tag_name); - ft->id = BT_CTF_FIELD_TYPE_ID_VARIANT; - var_ft->tag_name = g_string_new(tag_name); - var_ft->choice_name_to_index = g_hash_table_new(NULL, NULL); - var_ft->choices = g_array_new(FALSE, TRUE, - sizeof(struct bt_ctf_field_type_common_variant_choice)); - - if (tag_ft) { - var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft); - } - - bt_ctf_field_type_common_initialize(ft, true, release_func, methods); - /* A variant's alignment is undefined */ - ft->alignment = 0; - BT_LOGD("Initialized common variant field type object: addr=%p, " - "tag-ft-addr=%p, tag-field-name=\"%s\"", - ft, tag_ft, tag_name); -} - -BT_HIDDEN -void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_integer *ft = (void *) obj; - - if (!ft) { - return; - } - - BT_LOGD("Destroying integer field type object: addr=%p", ft); - BT_LOGD_STR("Putting mapped clock class."); - bt_ctf_object_put_ref(ft->mapped_clock_class); - g_free(ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_floating_point *ft = (void *) obj; - - if (!ft) { - return; - } - - BT_LOGD("Destroying floating point number field type object: addr=%p", ft); - g_free(ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_enumeration *ft = (void *) obj; - - if (!ft) { - return; - } - - BT_LOGD("Destroying enumeration field type object: addr=%p", ft); - g_ptr_array_free(ft->entries, TRUE); - BT_LOGD_STR("Putting container field type."); - bt_ctf_object_put_ref(ft->container_ft); - g_free(ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_string *ft = (void *) obj; - - if (!ft) { - return; - } - - BT_LOGD("Destroying string field type object: addr=%p", ft); - g_free(ft); -} - -static -void bt_ctf_field_type_common_structure_field_finalize( - struct bt_ctf_field_type_common_structure_field *field) -{ - if (!field) { - return; - } - - BT_LOGD("Finalizing structure field type's field: " - "addr=%p, field-ft-addr=%p, field-name=\"%s\"", - field, field->type, g_quark_to_string(field->name)); - BT_LOGD_STR("Putting field type."); - bt_ctf_object_put_ref(field->type); -} - -BT_HIDDEN -void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_structure *ft = (void *) obj; - uint64_t i; - - if (!ft) { - return; - } - - BT_LOGD("Destroying structure field type object: addr=%p", ft); - - if (ft->fields) { - for (i = 0; i < ft->fields->len; i++) { - bt_ctf_field_type_common_structure_field_finalize( - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - ft, i)); - } - - g_array_free(ft->fields, TRUE); - } - - if (ft->field_name_to_index) { - g_hash_table_destroy(ft->field_name_to_index); - } - - g_free(ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_array *ft = (void *) obj; - - if (!ft) { - return; - } - - BT_LOGD("Destroying array field type object: addr=%p", ft); - BT_LOGD_STR("Putting element field type."); - bt_ctf_object_put_ref(ft->element_ft); - g_free(ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_sequence *ft = (void *) obj; - - if (!ft) { - return; - } - - BT_LOGD("Destroying sequence field type object: addr=%p", ft); - BT_LOGD_STR("Putting element field type."); - bt_ctf_object_put_ref(ft->element_ft); - g_string_free(ft->length_field_name, TRUE); - BT_LOGD_STR("Putting length field path."); - bt_ctf_object_put_ref(ft->length_field_path); - g_free(ft); -} - -static -void bt_ctf_field_type_common_variant_choice_finalize( - struct bt_ctf_field_type_common_variant_choice *choice) -{ - if (!choice) { - return; - } - - BT_LOGD("Finalizing variant field type's choice: " - "addr=%p, field-ft-addr=%p, field-name=\"%s\"", - choice, choice->type, g_quark_to_string(choice->name)); - BT_LOGD_STR("Putting field type."); - bt_ctf_object_put_ref(choice->type); - - if (choice->ranges) { - g_array_free(choice->ranges, TRUE); - } -} - -BT_HIDDEN -void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_common_variant *ft = (void *) obj; - uint64_t i; - - if (!ft) { - return; - } - - BT_LOGD("Destroying variant field type object: addr=%p", ft); - - if (ft->choices) { - for (i = 0; i < ft->choices->len; i++) { - bt_ctf_field_type_common_variant_choice_finalize( - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - ft, i)); - } - - g_array_free(ft->choices, TRUE); - } - - if (ft->choice_name_to_index) { - g_hash_table_destroy(ft->choice_name_to_index); - } - - if (ft->tag_name) { - g_string_free(ft->tag_name, TRUE); - } - - BT_LOGD_STR("Putting tag field type."); - bt_ctf_object_put_ref(ft->tag_ft); - BT_LOGD_STR("Putting tag field path."); - bt_ctf_object_put_ref(ft->tag_field_path); - g_free(ft); -} - -struct range_overlap_query { - union { - uint64_t _unsigned; - int64_t _signed; - } range_start; - - union { - uint64_t _unsigned; - int64_t _signed; - } range_end; - int overlaps; - GQuark mapping_name; -}; - -static -void check_ranges_overlap(gpointer element, gpointer query) -{ - struct bt_ctf_enumeration_mapping *mapping = element; - struct range_overlap_query *overlap_query = query; - - if (mapping->range_start._signed <= overlap_query->range_end._signed - && overlap_query->range_start._signed <= - mapping->range_end._signed) { - overlap_query->overlaps = 1; - overlap_query->mapping_name = mapping->string; - } - - overlap_query->overlaps |= - mapping->string == overlap_query->mapping_name; - - if (overlap_query->overlaps) { - BT_LOGV("Overlapping enumeration field type mappings: " - "mapping-name=\"%s\", " - "mapping-a-range-start=%" PRId64 ", " - "mapping-a-range-end=%" PRId64 ", " - "mapping-b-range-start=%" PRId64 ", " - "mapping-b-range-end=%" PRId64, - g_quark_to_string(mapping->string), - mapping->range_start._signed, - mapping->range_end._signed, - overlap_query->range_start._signed, - overlap_query->range_end._signed); - } -} - -static -void check_ranges_overlap_unsigned(gpointer element, gpointer query) -{ - struct bt_ctf_enumeration_mapping *mapping = element; - struct range_overlap_query *overlap_query = query; - - if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned - && overlap_query->range_start._unsigned <= - mapping->range_end._unsigned) { - overlap_query->overlaps = 1; - overlap_query->mapping_name = mapping->string; - } - - overlap_query->overlaps |= - mapping->string == overlap_query->mapping_name; - - if (overlap_query->overlaps) { - BT_LOGW("Overlapping enumeration field type mappings: " - "mapping-name=\"%s\", " - "mapping-a-range-start=%" PRIu64 ", " - "mapping-a-range-end=%" PRIu64 ", " - "mapping-b-range-start=%" PRIu64 ", " - "mapping-b-range-end=%" PRIu64, - g_quark_to_string(mapping->string), - mapping->range_start._unsigned, - mapping->range_end._unsigned, - overlap_query->range_start._unsigned, - overlap_query->range_end._unsigned); - } -} - -static -gint compare_enumeration_mappings_signed(struct bt_ctf_enumeration_mapping **a, - struct bt_ctf_enumeration_mapping **b) -{ - return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1; -} - -static -gint compare_enumeration_mappings_unsigned(struct bt_ctf_enumeration_mapping **a, - struct bt_ctf_enumeration_mapping **b) -{ - return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1; -} - -static -int add_structure_variant_member(GArray *members, - GHashTable *field_name_to_index, - struct bt_ctf_field_type_common *field_type, const char *field_name, - bool is_variant) -{ - int ret = 0; - GQuark name_quark = g_quark_from_string(field_name); - struct bt_ctf_field_type_common **member_ft; - GQuark *member_name; - - /* Make sure structure does not contain a field of the same name */ - if (g_hash_table_lookup_extended(field_name_to_index, - GUINT_TO_POINTER(name_quark), NULL, NULL)) { - BT_LOGW("Structure or variant field type already contains a field type with this name: " - "field-name=\"%s\"", field_name); - ret = -1; - goto end; - } - - g_array_set_size(members, members->len + 1); - - if (is_variant) { - struct bt_ctf_field_type_common_variant_choice *choice = - &g_array_index(members, - struct bt_ctf_field_type_common_variant_choice, - members->len - 1); - - member_ft = &choice->type; - member_name = &choice->name; - BT_ASSERT(!choice->ranges); - choice->ranges = g_array_new(FALSE, TRUE, - sizeof(struct bt_ctf_field_type_common_variant_choice_range)); - BT_ASSERT(choice->ranges); - } else { - struct bt_ctf_field_type_common_structure_field *field = - &g_array_index(members, - struct bt_ctf_field_type_common_structure_field, - members->len - 1); - - member_ft = &field->type; - member_name = &field->name; - } - - *member_name = name_quark; - *member_ft = bt_ctf_object_get_ref(field_type); - g_hash_table_insert(field_name_to_index, - GUINT_TO_POINTER(name_quark), - GUINT_TO_POINTER(members->len - 1)); - BT_LOGV("Added structure/variant field type member: member-ft-addr=%p, " - "member-name=\"%s\"", field_type, field_name); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft) -{ - int ret = 0; - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - if (int_ft->mapped_clock_class && int_ft->is_signed) { - BT_LOGW("Invalid integer field type: cannot be signed and have a mapped clock class: " - "ft-addr=%p, clock-class-addr=%p, clock-class-name=\"%s\"", - ft, int_ft->mapped_clock_class, - bt_ctf_clock_class_get_name(int_ft->mapped_clock_class)); - ret = -1; - goto end; - } - -end: - return ret; -} - -static -void bt_ctf_field_type_enum_iter_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_field_type_enumeration_mapping_iterator *iter = - container_of(obj, - struct bt_ctf_field_type_enumeration_mapping_iterator, - base); - - BT_LOGD("Destroying enumeration field type mapping iterator: addr=%p", - obj); - BT_LOGD_STR("Putting parent enumeration field type."); - bt_ctf_object_put_ref(iter->enumeration_ft); - g_free(iter); -} - -static -struct bt_ctf_field_type_enumeration_mapping_iterator * -bt_ctf_field_type_common_enumeration_find_mappings_type( - struct bt_ctf_field_type_common *ft, - enum bt_ctf_field_type_enumeration_mapping_iterator_type iterator_type) -{ - struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, - "Field type"); - iter = g_new0(struct bt_ctf_field_type_enumeration_mapping_iterator, 1); - if (!iter) { - BT_LOGE_STR("Failed to allocate one enumeration field type mapping."); - goto end; - } - - bt_ctf_object_init_shared(&iter->base, bt_ctf_field_type_enum_iter_destroy); - iter->enumeration_ft = bt_ctf_object_get_ref(ft); - iter->index = -1; - iter->type = iterator_type; - -end: - return iter; -} - -BT_HIDDEN -struct bt_ctf_field_type_enumeration_mapping_iterator * -bt_ctf_field_type_common_enumeration_find_mappings_by_name( - struct bt_ctf_field_type_common *ft, const char *name) -{ - struct bt_ctf_field_type_enumeration_mapping_iterator *iter; - - iter = bt_ctf_field_type_common_enumeration_find_mappings_type( - ft, CTF_ITERATOR_BY_NAME); - if (!iter) { - BT_LOGW("Cannot create enumeration field type mapping iterator: " - "ft-addr=%p, mapping-name=\"%s\"", ft, name); - goto error; - } - - iter->u.name_quark = g_quark_try_string(name); - if (!iter->u.name_quark) { - /* - * No results are possible, set the iterator's position at the - * end. - */ - iter->index = iter->enumeration_ft->entries->len; - } - - return iter; - -error: - bt_ctf_object_put_ref(iter); - return NULL; -} - -static -struct bt_ctf_enumeration_mapping *bt_ctf_field_type_common_enumeration_get_mapping_by_index( - struct bt_ctf_field_type_common *ft, uint64_t index) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - struct bt_ctf_enumeration_mapping *mapping = NULL; - - if (index >= enum_ft->entries->len) { - BT_LOGW("Invalid parameter: index is out of bounds: " - "addr=%p, index=%" PRIu64 ", count=%u", - ft, index, enum_ft->entries->len); - goto end; - } - - mapping = g_ptr_array_index(enum_ft->entries, index); - -end: - return mapping; -} - -BT_HIDDEN -int bt_ctf_field_type_enumeration_mapping_iterator_next( - struct bt_ctf_field_type_enumeration_mapping_iterator *iter) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = iter->enumeration_ft; - int i, ret = 0, len; - - BT_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator"); - len = enum_ft->entries->len; - for (i = iter->index + 1; i < len; i++) { - struct bt_ctf_enumeration_mapping *mapping = - bt_ctf_field_type_common_enumeration_get_mapping_by_index( - BT_CTF_TO_COMMON(enum_ft), i); - - switch (iter->type) { - case CTF_ITERATOR_BY_NAME: - if (mapping->string == iter->u.name_quark) { - iter->index = i; - goto end; - } - break; - case CTF_ITERATOR_BY_SIGNED_VALUE: - { - int64_t value = iter->u.signed_value; - - if (value >= mapping->range_start._signed && - value <= mapping->range_end._signed) { - iter->index = i; - goto end; - } - break; - } - case CTF_ITERATOR_BY_UNSIGNED_VALUE: - { - uint64_t value = iter->u.unsigned_value; - - if (value >= mapping->range_start._unsigned && - value <= mapping->range_end._unsigned) { - iter->index = i; - goto end; - } - break; - } - default: - BT_LOGF("Invalid enumeration field type mapping iterator type: " - "type=%d", iter->type); - abort(); - } - } - - ret = -1; - -end: - return ret; -} - -BT_HIDDEN -struct bt_ctf_field_type_enumeration_mapping_iterator * -bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value( - struct bt_ctf_field_type_common *ft, int64_t value) -{ - struct bt_ctf_field_type_enumeration_mapping_iterator *iter; - - iter = bt_ctf_field_type_common_enumeration_find_mappings_type( - ft, CTF_ITERATOR_BY_SIGNED_VALUE); - if (!iter) { - BT_LOGW("Cannot create enumeration field type mapping iterator: " - "ft-addr=%p, value=%" PRId64, ft, value); - goto error; - } - - if (bt_ctf_field_type_common_integer_is_signed( - BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 1) { - BT_LOGW("Invalid parameter: enumeration field type is unsigned: " - "enum-ft-addr=%p, int-ft-addr=%p", - ft, iter->enumeration_ft->container_ft); - goto error; - } - - iter->u.signed_value = value; - return iter; - -error: - bt_ctf_object_put_ref(iter); - return NULL; -} - -BT_HIDDEN -struct bt_ctf_field_type_enumeration_mapping_iterator * -bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value( - struct bt_ctf_field_type_common *ft, uint64_t value) -{ - struct bt_ctf_field_type_enumeration_mapping_iterator *iter; - - iter = bt_ctf_field_type_common_enumeration_find_mappings_type( - ft, CTF_ITERATOR_BY_UNSIGNED_VALUE); - if (!iter) { - BT_LOGW("Cannot create enumeration field type mapping iterator: " - "ft-addr=%p, value=%" PRIu64, ft, value); - goto error; - } - - if (bt_ctf_field_type_common_integer_is_signed( - BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 0) { - BT_LOGW("Invalid parameter: enumeration field type is signed: " - "enum-ft-addr=%p, int-ft-addr=%p", - ft, iter->enumeration_ft->container_ft); - goto error; - } - - iter->u.unsigned_value = value; - return iter; - -error: - bt_ctf_object_put_ref(iter); - return NULL; -} - -BT_HIDDEN -int bt_ctf_field_type_enumeration_mapping_iterator_signed_get( - struct bt_ctf_field_type_enumeration_mapping_iterator *iter, - const char **mapping_name, int64_t *range_begin, - int64_t *range_end) -{ - BT_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator"); - BT_ASSERT_PRE(iter->index != -1, - "Invalid enumeration field type mapping iterator access: " - "addr=%p, position=-1", iter); - return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index( - (void *) iter->enumeration_ft, iter->index, - mapping_name, range_begin, range_end); -} - -BT_HIDDEN -int bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get( - struct bt_ctf_field_type_enumeration_mapping_iterator *iter, - const char **mapping_name, uint64_t *range_begin, - uint64_t *range_end) -{ - BT_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator"); - BT_ASSERT_PRE(iter->index != -1, - "Invalid enumeration field type mapping iterator access: " - "addr=%p, position=-1", iter); - return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index( - (void *) iter->enumeration_ft, iter->index, - mapping_name, range_begin, range_end); -} - -/* - * Note: This algorithm is O(n^2) vs number of enumeration mappings. - * Only used when freezing an enumeration. - */ -static -void bt_ctf_field_type_common_enumeration_set_range_overlap( - struct bt_ctf_field_type_common_enumeration *ft) -{ - int64_t i, j, len; - int is_signed; - - BT_LOGV("Setting enumeration field type's overlap flag: addr=%p", - ft); - len = ft->entries->len; - is_signed = bt_ctf_field_type_common_integer_is_signed( - BT_CTF_TO_COMMON(ft->container_ft)); - - for (i = 0; i < len; i++) { - for (j = i + 1; j < len; j++) { - struct bt_ctf_enumeration_mapping *mapping[2]; - - mapping[0] = bt_ctf_field_type_common_enumeration_get_mapping_by_index( - BT_CTF_TO_COMMON(ft), i); - mapping[1] = bt_ctf_field_type_common_enumeration_get_mapping_by_index( - BT_CTF_TO_COMMON(ft), j); - if (is_signed) { - if (mapping[0]->range_start._signed - <= mapping[1]->range_end._signed - && mapping[0]->range_end._signed - >= mapping[1]->range_start._signed) { - ft->has_overlapping_ranges = BT_TRUE; - goto end; - } - } else { - if (mapping[0]->range_start._unsigned - <= mapping[1]->range_end._unsigned - && mapping[0]->range_end._unsigned - >= mapping[1]->range_start._unsigned) { - ft->has_overlapping_ranges = BT_TRUE; - goto end; - } - } - } - } - -end: - if (ft->has_overlapping_ranges) { - BT_LOGV_STR("Enumeration field type has overlapping ranges."); - } else { - BT_LOGV_STR("Enumeration field type has no overlapping ranges."); - } -} - -BT_HIDDEN -int bt_ctf_field_type_common_enumeration_validate_recursive( - struct bt_ctf_field_type_common *ft) -{ - int ret = 0; - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - - ret = bt_ctf_field_type_common_integer_validate( - BT_CTF_TO_COMMON(enum_ft->container_ft)); - if (ret) { - BT_LOGW("Invalid enumeration field type: container type is invalid: " - "enum-ft-addr=%p, int-ft-addr=%p", - ft, enum_ft->container_ft); - goto end; - } - - /* Ensure enum has entries */ - if (enum_ft->entries->len == 0) { - BT_LOGW("Invalid enumeration field type: no entries: " - "addr=%p", ft); - ret = -1; - goto end; - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_sequence_validate_recursive( - struct bt_ctf_field_type_common *ft) -{ - int ret = 0; - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - /* Length field name should be set at this point */ - if (seq_ft->length_field_name->len == 0) { - BT_LOGW("Invalid sequence field type: no length field name: " - "addr=%p", ft); - ret = -1; - goto end; - } - - ret = bt_ctf_field_type_common_validate(seq_ft->element_ft); - if (ret) { - BT_LOGW("Invalid sequence field type: invalid element field type: " - "seq-ft-addr=%p, element-ft-add=%p", - ft, seq_ft->element_ft); - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_array_validate_recursive( - struct bt_ctf_field_type_common *ft) -{ - int ret = 0; - struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); - - ret = bt_ctf_field_type_common_validate(array_ft->element_ft); - if (ret) { - BT_LOGW("Invalid array field type: invalid element field type: " - "array-ft-addr=%p, element-ft-add=%p", - ft, array_ft->element_ft); - } - - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_structure_validate_recursive( - struct bt_ctf_field_type_common *ft) -{ - int ret = 0; - struct bt_ctf_field_type_common *child_ft = NULL; - int64_t field_count = - bt_ctf_field_type_common_structure_get_field_count(ft); - int64_t i; - - BT_ASSERT(field_count >= 0); - - for (i = 0; i < field_count; ++i) { - const char *field_name; - - ret = bt_ctf_field_type_common_structure_borrow_field_by_index(ft, - &field_name, &child_ft, i); - BT_ASSERT(ret == 0); - ret = bt_ctf_field_type_common_validate(child_ft); - if (ret) { - BT_LOGW("Invalid structure field type: " - "a contained field type is invalid: " - "struct-ft-addr=%p, field-ft-addr=%p, " - "field-name=\"%s\", field-index=%" PRId64, - ft, child_ft, field_name, i); - goto end; - } - } - -end: - return ret; -} - -static -bt_bool bt_ctf_field_type_common_enumeration_has_overlapping_ranges( - struct bt_ctf_field_type_common_enumeration *enum_ft) -{ - if (!enum_ft->common.frozen) { - bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft); - } - - return enum_ft->has_overlapping_ranges; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_validate_recursive( - struct bt_ctf_field_type_common *ft) -{ - int ret = 0; - int64_t field_count; - struct bt_ctf_field_type_common *child_ft = NULL; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - int64_t i; - - if (var_ft->tag_name->len == 0) { - BT_LOGW("Invalid variant field type: no tag field name: " - "addr=%p", ft); - ret = -1; - goto end; - } - - if (!var_ft->tag_ft) { - BT_LOGW("Invalid variant field type: no tag field type: " - "addr=%p, tag-field-name=\"%s\"", var_ft, - var_ft->tag_name->str); - ret = -1; - goto end; - } - - if (bt_ctf_field_type_common_enumeration_has_overlapping_ranges(var_ft->tag_ft)) { - BT_LOGW("Invalid variant field type: enumeration tag field type has overlapping ranges: " - "variant-ft-addr=%p, tag-field-name=\"%s\", " - "enum-ft-addr=%p", ft, var_ft->tag_name->str, - var_ft->tag_ft); - ret = -1; - goto end; - } - - /* - * It is valid to have a variant field type which does not have - * the fields corresponding to each label in the associated - * enumeration. - * - * It is also valid to have variant field type fields which - * cannot be selected because the variant field type tag has no - * mapping named as such. This scenario, while not ideal, cannot - * cause any error. - * - * If a non-existing field happens to be selected by an - * enumeration while reading a variant field, an error will be - * generated at that point (while reading the stream). - */ - field_count = bt_ctf_field_type_common_variant_get_field_count(ft); - if (field_count < 0) { - BT_LOGW("Invalid variant field type: no fields: " - "addr=%p, tag-field-name=\"%s\"", - ft, var_ft->tag_name->str); - ret = -1; - goto end; - } - - for (i = 0; i < field_count; ++i) { - const char *field_name; - - ret = bt_ctf_field_type_common_variant_borrow_field_by_index(ft, - &field_name, &child_ft, i); - BT_ASSERT(ret == 0); - ret = bt_ctf_field_type_common_validate(child_ft); - if (ret) { - BT_LOGW("Invalid variant field type: " - "a contained field type is invalid: " - "variant-ft-addr=%p, tag-field-name=\"%s\", " - "field-ft-addr=%p, field-name=\"%s\", " - "field-index=%" PRId64, - ft, var_ft->tag_name->str, child_ft, - field_name, i); - goto end; - } - } - -end: - return ret; -} - -/* - * This function validates a given field type without considering - * where this field type is located. It only validates the properties - * of the given field type and the properties of its children if - * applicable. - */ -BT_HIDDEN -int bt_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft) -{ - int ret = 0; - - BT_ASSERT(ft); - - if (ft->valid) { - /* Already marked as valid */ - goto end; - } - - if (ft->methods->validate) { - ret = ft->methods->validate(ft); - } - - if (ret == 0 && ft->frozen) { - /* Field type is valid */ - BT_LOGV("Marking field type as valid: addr=%p", ft); - ft->valid = 1; - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, - "Field type"); - return (int) int_ft->size; -} - -BT_HIDDEN -bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, - "Field type"); - return int_ft->is_signed; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft, - bt_bool is_signed) -{ - int ret = 0; - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid parameter: field type is not an integer field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - int_ft->is_signed = !!is_signed; - BT_LOGV("Set integer field type's signedness: addr=%p, is-signed=%d", - ft, is_signed); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft, - unsigned int size) -{ - int ret = 0; - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid parameter: field type is not an integer field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (size == 0 || size > 64) { - BT_LOGW("Invalid parameter: size must be between 1 and 64: " - "addr=%p, size=%u", ft, size); - ret = -1; - goto end; - } - - int_ft->size = size; - BT_LOGV("Set integer field type's size: addr=%p, size=%u", - ft, size); - -end: - return ret; -} - -BT_HIDDEN -enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, - "Field type"); - return int_ft->base; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft, - enum bt_ctf_integer_base base) -{ - int ret = 0; - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid parameter: field type is not an integer field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - switch (base) { - case BT_CTF_INTEGER_BASE_UNSPECIFIED: - case BT_CTF_INTEGER_BASE_BINARY: - case BT_CTF_INTEGER_BASE_OCTAL: - case BT_CTF_INTEGER_BASE_DECIMAL: - case BT_CTF_INTEGER_BASE_HEXADECIMAL: - { - int_ft->base = base; - break; - } - default: - BT_LOGW("Invalid parameter: unknown integer field type base: " - "addr=%p, base=%d", ft, base); - ret = -1; - } - - BT_LOGV("Set integer field type's base: addr=%p, base=%s", - ft, bt_ctf_integer_base_string(base)); - -end: - return ret; -} - -BT_HIDDEN -enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, - "Field type"); - return int_ft->encoding; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft, - enum bt_ctf_string_encoding encoding) -{ - int ret = 0; - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid parameter: field type is not an integer field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (encoding != BT_CTF_STRING_ENCODING_UTF8 && - encoding != BT_CTF_STRING_ENCODING_ASCII && - encoding != BT_CTF_STRING_ENCODING_NONE) { - BT_LOGW("Invalid parameter: unknown string encoding: " - "addr=%p, encoding=%d", ft, encoding); - ret = -1; - goto end; - } - - int_ft->encoding = encoding; - BT_LOGV("Set integer field type's encoding: addr=%p, encoding=%s", - ft, bt_ctf_string_encoding_string(encoding)); - -end: - return ret; -} - -BT_HIDDEN -struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER, - "Field type"); - return int_ft->mapped_clock_class; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_clock_class *clock_class) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - int ret = 0; - - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid parameter: field type is not an integer field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - goto end; - } - - if (!bt_ctf_clock_class_is_valid(clock_class)) { - BT_LOGW("Invalid parameter: clock class is invalid: ft-addr=%p" - "clock-class-addr=%p, clock-class-name=\"%s\"", - ft, clock_class, - bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - bt_ctf_object_put_ref(int_ft->mapped_clock_class); - int_ft->mapped_clock_class = bt_ctf_object_get_ref(clock_class); - BT_LOGV("Set integer field type's mapped clock class: ft-addr=%p, " - "clock-class-addr=%p, clock-class-name=\"%s\"", - ft, clock_class, bt_ctf_clock_class_get_name(clock_class)); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_integer_set_mapped_clock_class( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_clock_class *clock_class) -{ - int ret = 0; - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen( - ft, clock_class); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index( - struct bt_ctf_field_type_common *ft, uint64_t index, - const char **mapping_name, int64_t *range_begin, - int64_t *range_end) -{ - int ret = 0; - struct bt_ctf_enumeration_mapping *mapping; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, - BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); - mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(ft, - index); - if (!mapping) { - /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() logs errors */ - ret = -1; - goto end; - } - - if (mapping_name) { - *mapping_name = g_quark_to_string(mapping->string); - BT_ASSERT(*mapping_name); - } - - if (range_begin) { - *range_begin = mapping->range_start._signed; - } - - if (range_end) { - *range_end = mapping->range_end._signed; - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index( - struct bt_ctf_field_type_common *ft, uint64_t index, - const char **mapping_name, uint64_t *range_begin, - uint64_t *range_end) -{ - int ret = 0; - struct bt_ctf_enumeration_mapping *mapping; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); - mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index( - ft, index); - if (!mapping) { - /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() reports any error */ - ret = -1; - goto end; - } - - if (mapping_name) { - *mapping_name = g_quark_to_string(mapping->string); - BT_ASSERT(*mapping_name); - } - - if (range_begin) { - *range_begin = mapping->range_start._unsigned; - } - - if (range_end) { - *range_end = mapping->range_end._unsigned; - } - -end: - return ret; -} - -BT_HIDDEN -struct bt_ctf_field_type_common * -bt_ctf_field_type_common_enumeration_borrow_container_field_type( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); - return BT_CTF_TO_COMMON(enum_ft->container_ft); -} - -BT_HIDDEN -int bt_ctf_field_type_common_enumeration_signed_add_mapping( - struct bt_ctf_field_type_common *ft, const char *string, - int64_t range_start, int64_t range_end) -{ - int ret = 0; - GQuark mapping_name; - struct bt_ctf_enumeration_mapping *mapping; - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - char *escaped_string; - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (!string) { - BT_LOGW_STR("Invalid parameter: string is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) { - BT_LOGW("Invalid parameter: field type is not an enumeration field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (range_end < range_start) { - BT_LOGW("Invalid parameter: range's end is lesser than range's start: " - "addr=%p, range-start=%" PRId64 ", range-end=%" PRId64, - ft, range_start, range_end); - ret = -1; - goto end; - } - - if (strlen(string) == 0) { - BT_LOGW("Invalid parameter: mapping name is an empty string: " - "enum-ft-addr=%p, mapping-name-addr=%p", ft, - string); - ret = -1; - goto end; - } - - escaped_string = g_strescape(string, NULL); - if (!escaped_string) { - BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, " - "mapping-name-addr=%p, mapping-name=\"%s\"", - ft, string, string); - ret = -1; - goto end; - } - - mapping = g_new(struct bt_ctf_enumeration_mapping, 1); - if (!mapping) { - BT_LOGE_STR("Failed to allocate one enumeration mapping."); - ret = -1; - goto error_free; - } - mapping_name = g_quark_from_string(escaped_string); - *mapping = (struct bt_ctf_enumeration_mapping) { - .range_start._signed = range_start, - .range_end._signed = range_end, - .string = mapping_name, - }; - g_ptr_array_add(enum_ft->entries, mapping); - g_ptr_array_sort(enum_ft->entries, - (GCompareFunc) compare_enumeration_mappings_signed); - BT_LOGV("Added mapping to signed enumeration field type: addr=%p, " - "name=\"%s\", range-start=%" PRId64 ", " - "range-end=%" PRId64, - ft, string, range_start, range_end); - -error_free: - free(escaped_string); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_enumeration_unsigned_add_mapping( - struct bt_ctf_field_type_common *ft, const char *string, - uint64_t range_start, uint64_t range_end) -{ - int ret = 0; - GQuark mapping_name; - struct bt_ctf_enumeration_mapping *mapping; - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - char *escaped_string; - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (!string) { - BT_LOGW_STR("Invalid parameter: string is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) { - BT_LOGW("Invalid parameter: field type is not an enumeration field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (range_end < range_start) { - BT_LOGW("Invalid parameter: range's end is lesser than range's start: " - "addr=%p, range-start=%" PRIu64 ", range-end=%" PRIu64, - ft, range_start, range_end); - ret = -1; - goto end; - } - - if (strlen(string) == 0) { - BT_LOGW("Invalid parameter: mapping name is an empty string: " - "enum-ft-addr=%p, mapping-name-addr=%p", ft, - string); - ret = -1; - goto end; - } - - escaped_string = g_strescape(string, NULL); - if (!escaped_string) { - BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, " - "mapping-name-addr=%p, mapping-name=\"%s\"", - ft, string, string); - ret = -1; - goto end; - } - - mapping = g_new(struct bt_ctf_enumeration_mapping, 1); - if (!mapping) { - BT_LOGE_STR("Failed to allocate one enumeration mapping."); - ret = -1; - goto error_free; - } - mapping_name = g_quark_from_string(escaped_string); - *mapping = (struct bt_ctf_enumeration_mapping) { - .range_start._unsigned = range_start, - .range_end._unsigned = range_end, - .string = mapping_name, - }; - g_ptr_array_add(enum_ft->entries, mapping); - g_ptr_array_sort(enum_ft->entries, - (GCompareFunc) compare_enumeration_mappings_unsigned); - BT_LOGV("Added mapping to unsigned enumeration field type: addr=%p, " - "name=\"%s\", range-start=%" PRIu64 ", " - "range-end=%" PRIu64, - ft, string, range_start, range_end); - -error_free: - free(escaped_string); - -end: - return ret; -} - -BT_HIDDEN -int64_t bt_ctf_field_type_common_enumeration_get_mapping_count( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type"); - return (int64_t) enum_ft->entries->len; -} - -BT_HIDDEN -int bt_ctf_field_type_common_floating_point_get_exponent_digits( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT, - "Field type"); - return (int) flt_ft->exp_dig; -} - -BT_HIDDEN -int bt_ctf_field_type_common_floating_point_set_exponent_digits( - struct bt_ctf_field_type_common *ft, - unsigned int exponent_digits) -{ - int ret = 0; - struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) { - BT_LOGW("Invalid parameter: field type is not a floating point number field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) && - (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) && - (exponent_digits != - sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) { - BT_LOGW("Invalid parameter: invalid exponent size: " - "addr=%p, exp-size=%u", ft, exponent_digits); - ret = -1; - goto end; - } - - flt_ft->exp_dig = exponent_digits; - BT_LOGV("Set floating point number field type's exponent size: addr=%p, " - "exp-size=%u", ft, exponent_digits); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_floating_point_get_mantissa_digits( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT, - "Field type"); - return (int) flt_ft->mant_dig; -} - -BT_HIDDEN -int bt_ctf_field_type_common_floating_point_set_mantissa_digits( - struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits) -{ - int ret = 0; - struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) { - BT_LOGW("Invalid parameter: field type is not a floating point number field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if ((mantissa_digits != FLT_MANT_DIG) && - (mantissa_digits != DBL_MANT_DIG) && - (mantissa_digits != LDBL_MANT_DIG)) { - BT_LOGW("Invalid parameter: invalid mantissa size: " - "addr=%p, mant-size=%u", ft, mantissa_digits); - ret = -1; - goto end; - } - - flt_ft->mant_dig = mantissa_digits; - BT_LOGV("Set floating point number field type's mantissa size: addr=%p, " - "mant-size=%u", ft, mantissa_digits); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_structure_replace_field( - struct bt_ctf_field_type_common *ft, - const char *field_name, - struct bt_ctf_field_type_common *field_type) -{ - int ret = 0; - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - GQuark name_quark; - uint64_t i; - - BT_ASSERT(ft); - BT_ASSERT(field_name); - BT_ASSERT(field_type); - BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_STRUCT); - name_quark = g_quark_from_string(field_name); - - for (i = 0; i < struct_ft->fields->len; i++) { - struct bt_ctf_field_type_common_structure_field *field = - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i); - - if (field->name == name_quark) { - bt_ctf_object_put_ref(field->type); - field->type = bt_ctf_object_get_ref(field_type); - } - } - - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *field_type, - const char *field_name) -{ - int ret = 0; - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - - /* - * TODO: check that `field_type` does not contain `type`, - * recursively. - */ - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (!field_name) { - BT_LOGW_STR("Invalid parameter: field name is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { - BT_LOGW("Invalid parameter: field type is not a structure field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (ft == field_type) { - BT_LOGW("Invalid parameter: structure field type and field type to add are the same: " - "addr=%p", ft); - ret = -1; - goto end; - } - - if (add_structure_variant_member(struct_ft->fields, - struct_ft->field_name_to_index, field_type, field_name, - false)) { - BT_LOGW("Cannot add field to structure field type: " - "struct-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"", - ft, field_type, field_name); - ret = -1; - goto end; - } - - BT_LOGV("Added structure field type field: struct-ft-addr=%p, " - "field-ft-addr=%p, field-name=\"%s\"", ft, - field_type, field_name); - -end: - return ret; -} - -BT_HIDDEN -int64_t bt_ctf_field_type_common_structure_get_field_count( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, - "Field type"); - return (int64_t) struct_ft->fields->len; -} - -BT_HIDDEN -int bt_ctf_field_type_common_structure_borrow_field_by_index( - struct bt_ctf_field_type_common *ft, - const char **field_name, - struct bt_ctf_field_type_common **field_type, uint64_t index) -{ - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - struct bt_ctf_field_type_common_structure_field *field; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, - "Field type"); - BT_ASSERT_PRE(index < struct_ft->fields->len, - "Index is out of bounds: index=%" PRIu64 ", " - "count=%u, ft-addr=%p", - index, struct_ft->fields->len, ft); - field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(struct_ft, index); - - if (field_type) { - *field_type = field->type; - } - - if (field_name) { - *field_name = g_quark_to_string(field->name); - BT_ASSERT(*field_name); - } - - return 0; -} - -BT_HIDDEN -struct bt_ctf_field_type_common * -bt_ctf_field_type_common_structure_borrow_field_type_by_name( - struct bt_ctf_field_type_common *ft, const char *name) -{ - size_t index; - GQuark name_quark; - struct bt_ctf_field_type_common_structure_field *field; - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - struct bt_ctf_field_type_common *field_type = NULL; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, - "Field type"); - name_quark = g_quark_try_string(name); - if (!name_quark) { - BT_LOGV("No such structure field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, name); - goto end; - } - - if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index, - GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) { - BT_LOGV("No such structure field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, name); - goto end; - } - - field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, index); - field_type = field->type; - -end: - return field_type; -} - -BT_HIDDEN -struct bt_ctf_field_type_common * -bt_ctf_field_type_common_variant_borrow_tag_field_type( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - struct bt_ctf_field_type_common *tag_ft = NULL; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - - if (!var_ft->tag_ft) { - BT_LOGV("Variant field type has no tag field type: " - "addr=%p", ft); - goto end; - } - - tag_ft = BT_CTF_TO_COMMON(var_ft->tag_ft); - -end: - return tag_ft; -} - -BT_HIDDEN -const char *bt_ctf_field_type_common_variant_get_tag_name( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - const char *tag_name = NULL; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - - if (var_ft->tag_name->len == 0) { - BT_LOGV("Variant field type has no tag field name: " - "addr=%p", ft); - goto end; - } - - tag_name = var_ft->tag_name->str; - -end: - return tag_name; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_set_tag_name( - struct bt_ctf_field_type_common *ft, const char *name) -{ - int ret = 0; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) { - BT_LOGW("Invalid parameter: field type is not a variant field type: " - "addr=%p, ft-id=%s", ft, bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (!bt_ctf_identifier_is_valid(name)) { - BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: " - "variant-ft-addr=%p, tag-field-name=\"%s\"", - ft, name); - ret = -1; - goto end; - } - - g_string_assign(var_ft->tag_name, name); - BT_LOGV("Set variant field type's tag field name: addr=%p, " - "tag-field-name=\"%s\"", ft, name); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *field_type, - const char *field_name) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - GQuark field_name_quark = g_quark_from_string(field_name); - - /* - * TODO: check that `field_type` does not contain `type`, - * recursively. - */ - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) { - BT_LOGW("Invalid parameter: field type is not a variant field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (ft == field_type) { - BT_LOGW("Invalid parameter: variant field type and field type to add are the same: " - "addr=%p", ft); - ret = -1; - goto end; - } - - /* The user has explicitly provided a tag; validate against it. */ - if (var_ft->tag_ft) { - int name_found = 0; - - /* Make sure this name is present in the enum tag */ - for (i = 0; i < var_ft->tag_ft->entries->len; i++) { - struct bt_ctf_enumeration_mapping *mapping = - g_ptr_array_index(var_ft->tag_ft->entries, i); - - if (mapping->string == field_name_quark) { - name_found = 1; - break; - } - } - - if (!name_found) { - /* Validation failed */ - BT_LOGW("Invalid parameter: field name does not name a tag field type's mapping: " - "variant-ft-addr=%p, tag-ft-addr=%p, " - "tag-field-name=\"%s\"" - "field-ft-addr=%p, field-name=\"%s\"", - ft, var_ft->tag_ft, var_ft->tag_name->str, - field_type, field_name); - ret = -1; - goto end; - } - } - - if (add_structure_variant_member(var_ft->choices, - var_ft->choice_name_to_index, field_type, - field_name, true)) { - BT_LOGW("Cannot add field to variant field type: " - "variant-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"", - ft, field_type, field_name); - ret = -1; - goto end; - } - - BT_LOGV("Added variant field type field: variant-ft-addr=%p, " - "field-ft-addr=%p, field-name=\"%s\"", ft, - field_type, field_name); - -end: - return ret; -} - -BT_HIDDEN -struct bt_ctf_field_type_common * -bt_ctf_field_type_common_variant_borrow_field_type_by_name( - struct bt_ctf_field_type_common *ft, - const char *field_name) -{ - size_t index; - GQuark name_quark; - struct bt_ctf_field_type_common_variant_choice *choice; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - struct bt_ctf_field_type_common *field_type = NULL; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_NON_NULL(field_name, "Name"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - name_quark = g_quark_try_string(field_name); - if (!name_quark) { - BT_LOGV("No such variant field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, field_name); - goto end; - } - - if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, - GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) { - BT_LOGV("No such variant field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, field_name); - goto end; - } - - choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index); - field_type = choice->type; - -end: - return field_type; -} - -BT_HIDDEN -int64_t bt_ctf_field_type_common_variant_get_field_count( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Variant field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - return (int64_t) var_ft->choices->len; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_borrow_field_by_index( - struct bt_ctf_field_type_common *ft, - const char **field_name, - struct bt_ctf_field_type_common **field_type, uint64_t index) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - struct bt_ctf_field_type_common_variant_choice *choice; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - BT_ASSERT_PRE(index < var_ft->choices->len, - "Index is out of bounds: index=%" PRIu64 ", " - "count=%u, ft-addr=%p", - index, var_ft->choices->len, ft); - choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index); - - if (field_type) { - *field_type = choice->type; - } - - if (field_name) { - *field_name = g_quark_to_string(choice->name); - BT_ASSERT(*field_name); - } - - return 0; -} - -BT_HIDDEN -int64_t bt_ctf_field_type_common_variant_find_choice_index( - struct bt_ctf_field_type_common *ft, uint64_t uval, - bool is_signed) -{ - int64_t ret; - uint64_t i; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT(ft); - BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_VARIANT); - - if (bt_ctf_field_type_common_variant_update_choices(ft)) { - ret = INT64_C(-1); - goto end; - } - - for (i = 0; i < var_ft->choices->len; i++) { - uint64_t range_i; - struct bt_ctf_field_type_common_variant_choice *choice = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - var_ft, i); - - for (range_i = 0; range_i < choice->ranges->len; range_i++) { - struct bt_ctf_field_type_common_variant_choice_range *range = - &g_array_index( - choice->ranges, - struct bt_ctf_field_type_common_variant_choice_range, - range_i); - - if (is_signed) { - int64_t tag_ival = (int64_t) uval; - - if (tag_ival >= range->lower.i && - tag_ival <= range->upper.i) { - goto found; - } - } else { - if (uval >= range->lower.u && - uval <= range->upper.u) { - goto found; - } - } - } - } - - /* Range not found */ - ret = INT64_C(-1); - goto end; - -found: - ret = (int64_t) i; - -end: - return ret; -} - -BT_HIDDEN -struct bt_ctf_field_type_common * -bt_ctf_field_type_common_array_borrow_element_field_type( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY, - "Field type"); - BT_ASSERT(array_ft && array_ft->element_ft); - return array_ft->element_ft; -} - -BT_HIDDEN -int bt_ctf_field_type_common_array_set_element_field_type( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *element_ft) -{ - int ret = 0; - struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: array field type is NULL."); - ret = -1; - goto end; - } - - if (!element_ft) { - BT_LOGW_STR("Invalid parameter: element field type is NULL."); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_ARRAY) { - BT_LOGW("Invalid parameter: field type is not an array field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (array_ft->element_ft) { - BT_CTF_OBJECT_PUT_REF_AND_RESET(array_ft->element_ft); - } - - array_ft->element_ft = bt_ctf_object_get_ref(element_ft); - BT_LOGV("Set array field type's element field type: array-ft-addr=%p, " - "element-ft-addr=%p", ft, element_ft); - -end: - return ret; -} - -BT_HIDDEN -int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY, - "Field type"); - return (int64_t) array_ft->length; -} - -BT_HIDDEN -struct bt_ctf_field_type_common *bt_ctf_field_type_common_sequence_borrow_element_field_type( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE, - "Field type"); - return seq_ft->element_ft; -} - -BT_HIDDEN -int bt_ctf_field_type_common_sequence_set_element_field_type( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *element_ft) -{ - int ret = 0; - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: sequence field type is NULL."); - ret = -1; - goto end; - } - - if (!element_ft) { - BT_LOGW_STR("Invalid parameter: element field type is NULL."); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) { - BT_LOGW("Invalid parameter: field type is not a sequence field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (seq_ft->element_ft) { - BT_CTF_OBJECT_PUT_REF_AND_RESET(seq_ft->element_ft); - } - - seq_ft->element_ft = element_ft; - bt_ctf_object_get_ref(seq_ft->element_ft); - BT_LOGV("Set sequence field type's element field type: sequence-ft-addr=%p, " - "element-ft-addr=%p", ft, element_ft); - -end: - return ret; -} - -BT_HIDDEN -const char *bt_ctf_field_type_common_sequence_get_length_field_name( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE, - "Field type"); - return seq_ft->length_field_name ? - seq_ft->length_field_name->str : NULL; -} - -BT_HIDDEN -enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRING, - "Field type"); - return string_ft->encoding; -} - -BT_HIDDEN -int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft, - enum bt_ctf_string_encoding encoding) -{ - int ret = 0; - struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_STRING) { - BT_LOGW("Invalid parameter: field type is not a string field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - if (encoding != BT_CTF_STRING_ENCODING_UTF8 && - encoding != BT_CTF_STRING_ENCODING_ASCII) { - BT_LOGW("Invalid parameter: unknown string encoding: " - "addr=%p, encoding=%d", ft, encoding); - ret = -1; - goto end; - } - - string_ft->encoding = encoding; - BT_LOGV("Set string field type's encoding: addr=%p, encoding=%s", - ft, bt_ctf_string_encoding_string(encoding)); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *ft) -{ - int ret; - enum bt_ctf_field_type_id type_id; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - - if (ft->frozen) { - ret = (int) ft->alignment; - goto end; - } - - type_id = bt_ctf_field_type_common_get_type_id(ft); - switch (type_id) { - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - { - struct bt_ctf_field_type_common *element_ft = - bt_ctf_field_type_common_sequence_borrow_element_field_type(ft); - - BT_ASSERT(element_ft); - ret = bt_ctf_field_type_common_get_alignment(element_ft); - break; - } - case BT_CTF_FIELD_TYPE_ID_ARRAY: - { - struct bt_ctf_field_type_common *element_ft = - bt_ctf_field_type_common_array_borrow_element_field_type(ft); - - BT_ASSERT(element_ft); - ret = bt_ctf_field_type_common_get_alignment(element_ft); - break; - } - case BT_CTF_FIELD_TYPE_ID_STRUCT: - { - int64_t i, element_count; - - element_count = bt_ctf_field_type_common_structure_get_field_count( - ft); - BT_ASSERT(element_count >= 0); - - for (i = 0; i < element_count; i++) { - struct bt_ctf_field_type_common *field = NULL; - int field_alignment; - - ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - ft, NULL, &field, i); - BT_ASSERT(ret == 0); - BT_ASSERT(field); - field_alignment = bt_ctf_field_type_common_get_alignment( - field); - if (field_alignment < 0) { - ret = field_alignment; - goto end; - } - - ft->alignment = MAX(field_alignment, ft->alignment); - } - ret = (int) ft->alignment; - break; - } - case BT_CTF_FIELD_TYPE_ID_UNKNOWN: - BT_LOGW("Invalid parameter: unknown field type ID: " - "addr=%p, ft-id=%d", ft, type_id); - ret = -1; - break; - default: - ret = (int) ft->alignment; - break; - } - -end: - return ret; -} - -static inline -int is_power_of_two(unsigned int value) -{ - return ((value & (value - 1)) == 0) && value > 0; -} - -BT_HIDDEN -int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft, - unsigned int alignment) -{ - int ret = 0; - enum bt_ctf_field_type_id type_id; - - /* Alignment must be a power of two */ - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (!is_power_of_two(alignment)) { - BT_LOGW("Invalid parameter: alignment is not a power of two: " - "addr=%p, align=%u", ft, alignment); - ret = -1; - goto end; - } - - type_id = bt_ctf_field_type_common_get_type_id(ft); - if (type_id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) { - BT_LOGW("Invalid parameter: unknown field type ID: " - "addr=%p, ft-id=%d", ft, type_id); - ret = -1; - goto end; - } - - if (ft->id == BT_CTF_FIELD_TYPE_ID_STRING && alignment != CHAR_BIT) { - BT_LOGW("Invalid parameter: alignment must be %u for a string field type: " - "addr=%p, align=%u", CHAR_BIT, ft, alignment); - ret = -1; - goto end; - } - - if (type_id == BT_CTF_FIELD_TYPE_ID_VARIANT || - type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE || - type_id == BT_CTF_FIELD_TYPE_ID_ARRAY) { - /* Setting an alignment on these types makes no sense */ - BT_LOGW("Invalid parameter: cannot set the alignment of this field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - ft->alignment = alignment; - ret = 0; - BT_LOGV("Set field type's alignment: addr=%p, align=%u", - ft, alignment); - -end: - return ret; -} - -BT_HIDDEN -enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order( - struct bt_ctf_field_type_common *ft) -{ - enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - - switch (ft->id) { - case BT_CTF_FIELD_TYPE_ID_INTEGER: - { - struct bt_ctf_field_type_common_integer *integer = - BT_CTF_FROM_COMMON(ft); - - ret = integer->user_byte_order; - break; - } - case BT_CTF_FIELD_TYPE_ID_ENUM: - { - struct bt_ctf_field_type_common_enumeration *enum_ft = - BT_CTF_FROM_COMMON(ft); - - ret = bt_ctf_field_type_common_get_byte_order( - BT_CTF_TO_COMMON(enum_ft->container_ft)); - break; - } - case BT_CTF_FIELD_TYPE_ID_FLOAT: - { - struct bt_ctf_field_type_common_floating_point *floating_point = - BT_CTF_FROM_COMMON(ft); - ret = floating_point->user_byte_order; - break; - } - default: - BT_LOGW("Invalid parameter: cannot get the byte order of this field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - goto end; - } - - BT_ASSERT(ret == BT_CTF_BYTE_ORDER_NATIVE || - ret == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN || - ret == BT_CTF_BYTE_ORDER_BIG_ENDIAN || - ret == BT_CTF_BYTE_ORDER_NETWORK); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft, - enum bt_ctf_byte_order byte_order) -{ - int ret = 0; - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->frozen) { - BT_LOGW("Invalid parameter: field type is frozen: addr=%p", - ft); - ret = -1; - goto end; - } - - if (byte_order != BT_CTF_BYTE_ORDER_NATIVE && - byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN && - byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN && - byte_order != BT_CTF_BYTE_ORDER_NETWORK) { - BT_LOGW("Invalid parameter: invalid byte order: " - "addr=%p, bo=%s", ft, - bt_ctf_byte_order_string(byte_order)); - ret = -1; - goto end; - } - - if (ft->methods->set_byte_order) { - ft->methods->set_byte_order(ft, byte_order); - } - - BT_LOGV("Set field type's byte order: addr=%p, bo=%s", - ft, bt_ctf_byte_order_string(byte_order)); - -end: - return ret; -} - -BT_HIDDEN -enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id( - struct bt_ctf_field_type_common *ft) -{ - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - return ft->id; -} - -BT_HIDDEN -void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft) -{ - if (!ft || ft->frozen) { - return; - } - - BT_ASSERT(ft->methods->freeze); - ft->methods->freeze(ft); -} - -BT_HIDDEN -struct bt_ctf_field_type_common * -bt_ctf_field_type_common_variant_borrow_field_type_signed( - struct bt_ctf_field_type_common_variant *var_ft, - int64_t tag_value) -{ - struct bt_ctf_field_type_common *field_type = NULL; - GQuark field_name_quark; - gpointer index; - struct bt_ctf_field_type_common_variant_choice *choice; - struct range_overlap_query query = { - .range_start._signed = tag_value, - .range_end._signed = tag_value, - .mapping_name = 0, - .overlaps = 0, - }; - - g_ptr_array_foreach(var_ft->tag_ft->entries, check_ranges_overlap, - &query); - if (!query.overlaps) { - goto end; - } - - field_name_quark = query.mapping_name; - if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, - GUINT_TO_POINTER(field_name_quark), NULL, &index)) { - goto end; - } - - choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, - (size_t) index); - field_type = choice->type; - -end: - return field_type; -} - -BT_HIDDEN -struct bt_ctf_field_type_common * -bt_ctf_field_type_common_variant_borrow_field_type_unsigned( - struct bt_ctf_field_type_common_variant *var_ft, - uint64_t tag_value) -{ - struct bt_ctf_field_type_common *field_type = NULL; - GQuark field_name_quark; - gpointer index; - struct bt_ctf_field_type_common_variant_choice *choice; - struct range_overlap_query query = { - .range_start._unsigned = tag_value, - .range_end._unsigned = tag_value, - .mapping_name = 0, - .overlaps = 0, - }; - - g_ptr_array_foreach(var_ft->tag_ft->entries, - check_ranges_overlap_unsigned, &query); - if (!query.overlaps) { - goto end; - } - - field_name_quark = query.mapping_name; - if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, - GUINT_TO_POINTER(field_name_quark), NULL, &index)) { - goto end; - } - - choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, - (size_t) index); - field_type = choice->type; - -end: - return field_type; -} - -BT_HIDDEN -struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common *ft_copy = NULL; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT(ft->methods->copy); - ft_copy = ft->methods->copy(ft); - if (!ft_copy) { - BT_LOGE_STR("Cannot copy field type."); - goto end; - } - - ft_copy->alignment = ft->alignment; - -end: - return ft_copy; -} - -BT_HIDDEN -int bt_ctf_field_type_common_structure_get_field_name_index( - struct bt_ctf_field_type_common *ft, const char *name) -{ - int ret; - size_t index; - GQuark name_quark; - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT, - "Field type"); - - name_quark = g_quark_try_string(name); - if (!name_quark) { - BT_LOGV("No such structure field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, name); - ret = -1; - goto end; - } - - if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index, - GUINT_TO_POINTER(name_quark), - NULL, (gpointer *) &index)) { - BT_LOGV("No such structure field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, name); - ret = -1; - goto end; - } - - ret = (int) index; - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_get_field_name_index( - struct bt_ctf_field_type_common *ft, const char *name) -{ - int ret; - size_t index; - GQuark name_quark; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - name_quark = g_quark_try_string(name); - if (!name_quark) { - BT_LOGV("No such variant field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, name); - ret = -1; - goto end; - } - - if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index, - GUINT_TO_POINTER(name_quark), - NULL, (gpointer *) &index)) { - BT_LOGV("No such variant field type field name: " - "ft-addr=%p, field-name=\"%s\"", - ft, name); - ret = -1; - goto end; - } - - ret = (int) index; - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_sequence_set_length_field_path( - struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path) -{ - int ret = 0; - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) { - BT_LOGW("Invalid parameter: field type is not a sequence field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - bt_ctf_object_get_ref(path); - BT_CTF_OBJECT_MOVE_REF(seq_ft->length_field_path, path); - BT_LOGV("Set sequence field type's length field path: ft-addr=%p, " - "field-path-addr=%p", ft, path); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_set_tag_field_path( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_path *path) -{ - int ret = 0; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - ret = -1; - goto end; - } - - if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) { - BT_LOGW("Invalid parameter: field type is not a variant field type: " - "addr=%p, ft-id=%s", ft, - bt_ctf_field_type_id_string(ft->id)); - ret = -1; - goto end; - } - - bt_ctf_object_get_ref(path); - BT_CTF_OBJECT_MOVE_REF(var_ft->tag_field_path, path); - BT_LOGV("Set variant field type's tag field path: ft-addr=%p, " - "field-path-addr=%p", ft, path); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_set_tag_field_type( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_field_type_common *tag_ft) -{ - int ret = 0; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - if (!ft) { - BT_LOGW_STR("Invalid parameter: variant field type is NULL."); - ret = -1; - goto end; - } - - if (!tag_ft) { - BT_LOGW_STR("Invalid parameter: tag field type is NULL."); - ret = -1; - goto end; - } - - if (tag_ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) { - BT_LOGW("Invalid parameter: tag field type is not an enumeration field type: " - "addr=%p, ft-id=%s", tag_ft, - bt_ctf_field_type_id_string(tag_ft->id)); - ret = -1; - goto end; - } - - bt_ctf_object_put_ref(var_ft->tag_ft); - var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft); - BT_LOGV("Set variant field type's tag field type: variant-ft-addr=%p, " - "tag-ft-addr=%p", ft, tag_ft); - -end: - return ret; -} - -BT_HIDDEN -void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft) -{ - ft->frozen = 1; -} - -BT_HIDDEN -void bt_ctf_field_type_common_enumeration_freeze_recursive( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - - BT_LOGD("Freezing enumeration field type object: addr=%p", ft); - bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft); - bt_ctf_field_type_common_generic_freeze(ft); - BT_LOGD("Freezing enumeration field type object's container field type: int-ft-addr=%p", - enum_ft->container_ft); - bt_ctf_field_type_common_freeze(BT_CTF_TO_COMMON(enum_ft->container_ft)); -} - -BT_HIDDEN -void bt_ctf_field_type_common_structure_freeze_recursive( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - uint64_t i; - - /* Cache the alignment */ - BT_LOGD("Freezing structure field type object: addr=%p", ft); - ft->alignment = bt_ctf_field_type_common_get_alignment(ft); - bt_ctf_field_type_common_generic_freeze(ft); - - for (i = 0; i < struct_ft->fields->len; i++) { - struct bt_ctf_field_type_common_structure_field *field = - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i); - - BT_LOGD("Freezing structure field type field: " - "ft-addr=%p, name=\"%s\"", - field->type, g_quark_to_string(field->name)); - bt_ctf_field_type_common_freeze(field->type); - } -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_update_choices(struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - uint64_t i; - int ret = 0; - bool is_signed; - - if (ft->frozen && var_ft->choices_up_to_date) { - goto end; - } - - BT_ASSERT(var_ft->tag_ft); - is_signed = !!var_ft->tag_ft->container_ft->is_signed; - - for (i = 0; i < var_ft->choices->len; i++) { - struct bt_ctf_field_type_common_variant_choice *choice = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i); - const char *choice_name = g_quark_to_string(choice->name); - struct bt_ctf_field_type_enumeration_mapping_iterator *iter = - bt_ctf_field_type_common_enumeration_find_mappings_by_name( - BT_CTF_TO_COMMON(var_ft->tag_ft), choice_name); - - if (!iter) { - ret = -1; - goto end; - } - - BT_ASSERT(choice->ranges); - g_array_set_size(choice->ranges, 0); - - while (bt_ctf_field_type_enumeration_mapping_iterator_next(iter) == 0) { - struct bt_ctf_field_type_common_variant_choice_range range; - - if (is_signed) { - ret = bt_ctf_field_type_enumeration_mapping_iterator_signed_get( - iter, NULL, - &range.lower.i, &range.upper.i); - } else { - ret = bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get( - iter, NULL, - &range.lower.u, &range.upper.u); - } - - BT_ASSERT(ret == 0); - g_array_append_val(choice->ranges, range); - } - - bt_ctf_object_put_ref(iter); - } - - var_ft->choices_up_to_date = true; - -end: - return ret; -} - -BT_HIDDEN -void bt_ctf_field_type_common_variant_freeze_recursive( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - uint64_t i; - - BT_LOGD("Freezing variant field type object: addr=%p", ft); - bt_ctf_field_type_common_generic_freeze(ft); - - for (i = 0; i < var_ft->choices->len; i++) { - struct bt_ctf_field_type_common_variant_choice *choice = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i); - - BT_LOGD("Freezing variant field type member: " - "ft-addr=%p, name=\"%s\"", - choice->type, g_quark_to_string(choice->name)); - bt_ctf_field_type_common_freeze(choice->type); - } -} - -BT_HIDDEN -void bt_ctf_field_type_common_array_freeze_recursive( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); - - /* Cache the alignment */ - BT_LOGD("Freezing array field type object: addr=%p", ft); - ft->alignment = bt_ctf_field_type_common_get_alignment(ft); - bt_ctf_field_type_common_generic_freeze(ft); - BT_LOGD("Freezing array field type object's element field type: element-ft-addr=%p", - array_ft->element_ft); - bt_ctf_field_type_common_freeze(array_ft->element_ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_sequence_freeze_recursive( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - /* Cache the alignment */ - BT_LOGD("Freezing sequence field type object: addr=%p", ft); - ft->alignment = bt_ctf_field_type_common_get_alignment(ft); - bt_ctf_field_type_common_generic_freeze(ft); - BT_LOGD("Freezing sequence field type object's element field type: element-ft-addr=%p", - seq_ft->element_ft); - bt_ctf_field_type_common_freeze(seq_ft->element_ft); -} - -BT_HIDDEN -void bt_ctf_field_type_common_integer_set_byte_order( - struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order) -{ - struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft); - - int_ft->user_byte_order = byte_order; -} - -BT_HIDDEN -void bt_ctf_field_type_common_enumeration_set_byte_order_recursive( - struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft); - - bt_ctf_field_type_common_set_byte_order(BT_CTF_TO_COMMON(enum_ft->container_ft), - byte_order); -} - -BT_HIDDEN -void bt_ctf_field_type_common_floating_point_set_byte_order( - struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order) -{ - struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); - - flt_ft->user_byte_order = byte_order; -} - -BT_HIDDEN -void bt_ctf_field_type_common_structure_set_byte_order_recursive( - struct bt_ctf_field_type_common *ft, - enum bt_ctf_byte_order byte_order) -{ - int i; - struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft); - - for (i = 0; i < struct_ft->fields->len; i++) { - struct bt_ctf_field_type_common_structure_field *field = - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - struct_ft, i); - struct bt_ctf_field_type_common *field_type = field->type; - - bt_ctf_field_type_common_set_byte_order(field_type, byte_order); - } -} - -BT_HIDDEN -void bt_ctf_field_type_common_variant_set_byte_order_recursive( - struct bt_ctf_field_type_common *ft, - enum bt_ctf_byte_order byte_order) -{ - int i; - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - for (i = 0; i < var_ft->choices->len; i++) { - struct bt_ctf_field_type_common_variant_choice *choice = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - var_ft, i); - struct bt_ctf_field_type_common *field_type = choice->type; - - bt_ctf_field_type_common_set_byte_order(field_type, byte_order); - } -} - -BT_HIDDEN -void bt_ctf_field_type_common_array_set_byte_order_recursive( - struct bt_ctf_field_type_common *ft, - enum bt_ctf_byte_order byte_order) -{ - struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft); - - bt_ctf_field_type_common_set_byte_order(array_ft->element_ft, byte_order); -} - -BT_HIDDEN -void bt_ctf_field_type_common_sequence_set_byte_order_recursive( - struct bt_ctf_field_type_common *ft, - enum bt_ctf_byte_order byte_order) -{ - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - bt_ctf_field_type_common_set_byte_order(seq_ft->element_ft, byte_order); -} - - -BT_HIDDEN -int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - struct bt_ctf_field_type_common_integer *int_ft_a = BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_integer *int_ft_b = BT_CTF_FROM_COMMON(ft_b); - - /* Length */ - if (int_ft_a->size != int_ft_b->size) { - BT_LOGV("Integer field types differ: different sizes: " - "ft-a-size=%u, ft-b-size=%u", - int_ft_a->size, int_ft_b->size); - goto end; - } - - /* Byte order */ - if (int_ft_a->user_byte_order != int_ft_b->user_byte_order) { - BT_LOGV("Integer field types differ: different byte orders: " - "ft-a-bo=%s, ft-b-bo=%s", - bt_ctf_byte_order_string(int_ft_a->user_byte_order), - bt_ctf_byte_order_string(int_ft_b->user_byte_order)); - goto end; - } - - /* Signedness */ - if (int_ft_a->is_signed != int_ft_b->is_signed) { - BT_LOGV("Integer field types differ: different signedness: " - "ft-a-is-signed=%d, ft-b-is-signed=%d", - int_ft_a->is_signed, - int_ft_b->is_signed); - goto end; - } - - /* Base */ - if (int_ft_a->base != int_ft_b->base) { - BT_LOGV("Integer field types differ: different bases: " - "ft-a-base=%s, ft-b-base=%s", - bt_ctf_integer_base_string(int_ft_a->base), - bt_ctf_integer_base_string(int_ft_b->base)); - goto end; - } - - /* Encoding */ - if (int_ft_a->encoding != int_ft_b->encoding) { - BT_LOGV("Integer field types differ: different encodings: " - "ft-a-encoding=%s, ft-b-encoding=%s", - bt_ctf_string_encoding_string(int_ft_a->encoding), - bt_ctf_string_encoding_string(int_ft_b->encoding)); - goto end; - } - - /* Mapped clock class */ - if (int_ft_a->mapped_clock_class) { - if (!int_ft_b->mapped_clock_class) { - BT_LOGV_STR("Integer field types differ: field type A " - "has a mapped clock class, but field type B " - "does not."); - goto end; - } - - if (bt_ctf_clock_class_compare(int_ft_a->mapped_clock_class, - int_ft_b->mapped_clock_class) != 0) { - BT_LOGV_STR("Integer field types differ: different " - "mapped clock classes."); - } - } else { - if (int_ft_b->mapped_clock_class) { - BT_LOGV_STR("Integer field types differ: field type A " - "has no description, but field type B has one."); - goto end; - } - } - - /* Equal */ - ret = 0; - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_floating_point_compare( - struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - struct bt_ctf_field_type_common_floating_point *flt_ft_a = - BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_floating_point *flt_ft_b = - BT_CTF_FROM_COMMON(ft_b); - - /* Byte order */ - if (flt_ft_a->user_byte_order != flt_ft_b->user_byte_order) { - BT_LOGV("Floating point number field types differ: different byte orders: " - "ft-a-bo=%s, ft-b-bo=%s", - bt_ctf_byte_order_string(flt_ft_a->user_byte_order), - bt_ctf_byte_order_string(flt_ft_b->user_byte_order)); - goto end; - } - - /* Exponent length */ - if (flt_ft_a->exp_dig != flt_ft_b->exp_dig) { - BT_LOGV("Floating point number field types differ: different exponent sizes: " - "ft-a-exp-size=%u, ft-b-exp-size=%u", - flt_ft_a->exp_dig, flt_ft_b->exp_dig); - goto end; - } - - /* Mantissa length */ - if (flt_ft_a->mant_dig != flt_ft_b->mant_dig) { - BT_LOGV("Floating point number field types differ: different mantissa sizes: " - "ft-a-mant-size=%u, ft-b-mant-size=%u", - flt_ft_a->mant_dig, flt_ft_b->mant_dig); - goto end; - } - - /* Equal */ - ret = 0; - -end: - return ret; -} - -static -int compare_enumeration_mappings(struct bt_ctf_enumeration_mapping *mapping_a, - struct bt_ctf_enumeration_mapping *mapping_b) -{ - int ret = 1; - - /* Label */ - if (mapping_a->string != mapping_b->string) { - BT_LOGV("Enumeration field type mappings differ: different names: " - "mapping-a-name=\"%s\", mapping-b-name=\"%s\"", - g_quark_to_string(mapping_a->string), - g_quark_to_string(mapping_b->string)); - goto end; - } - - /* Range start */ - if (mapping_a->range_start._unsigned != - mapping_b->range_start._unsigned) { - BT_LOGV("Enumeration field type mappings differ: different starts of range: " - "mapping-a-range-start-unsigned=%" PRIu64 ", " - "mapping-b-range-start-unsigned=%" PRIu64, - mapping_a->range_start._unsigned, - mapping_b->range_start._unsigned); - goto end; - } - - /* Range end */ - if (mapping_a->range_end._unsigned != - mapping_b->range_end._unsigned) { - BT_LOGV("Enumeration field type mappings differ: different ends of range: " - "mapping-a-range-end-unsigned=%" PRIu64 ", " - "mapping-b-range-end-unsigned=%" PRIu64, - mapping_a->range_end._unsigned, - mapping_b->range_end._unsigned); - goto end; - } - - /* Equal */ - ret = 0; - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_enumeration_compare_recursive( - struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - int i; - struct bt_ctf_field_type_common_enumeration *enum_ft_a = - BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_enumeration *enum_ft_b = - BT_CTF_FROM_COMMON(ft_b); - - /* Container field type */ - ret = bt_ctf_field_type_common_compare( - BT_CTF_TO_COMMON(enum_ft_a->container_ft), - BT_CTF_TO_COMMON(enum_ft_b->container_ft)); - if (ret) { - BT_LOGV("Enumeration field types differ: different container field types: " - "ft-a-container-ft-addr=%p, ft-b-container-ft-addr=%p", - enum_ft_a->container_ft, enum_ft_b->container_ft); - goto end; - } - - ret = 1; - - /* Entries */ - if (enum_ft_a->entries->len != enum_ft_b->entries->len) { - goto end; - } - - for (i = 0; i < enum_ft_a->entries->len; ++i) { - struct bt_ctf_enumeration_mapping *mapping_a = - g_ptr_array_index(enum_ft_a->entries, i); - struct bt_ctf_enumeration_mapping *mapping_b = - g_ptr_array_index(enum_ft_b->entries, i); - - if (compare_enumeration_mappings(mapping_a, mapping_b)) { - BT_LOGV("Enumeration field types differ: different mappings: " - "ft-a-mapping-addr=%p, ft-b-mapping-addr=%p, " - "ft-a-mapping-name=\"%s\", ft-b-mapping-name=\"%s\"", - mapping_a, mapping_b, - g_quark_to_string(mapping_a->string), - g_quark_to_string(mapping_b->string)); - goto end; - } - } - - /* Equal */ - ret = 0; - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - struct bt_ctf_field_type_common_string *string_ft_a = BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_string *string_ft_b = BT_CTF_FROM_COMMON(ft_b); - - /* Encoding */ - if (string_ft_a->encoding != string_ft_b->encoding) { - BT_LOGV("String field types differ: different encodings: " - "ft-a-encoding=%s, ft-b-encoding=%s", - bt_ctf_string_encoding_string(string_ft_a->encoding), - bt_ctf_string_encoding_string(string_ft_b->encoding)); - goto end; - } - - /* Equal */ - ret = 0; - -end: - return ret; -} - -static -int compare_structure_variant_members( - struct bt_ctf_field_type_common *member_a_ft, - struct bt_ctf_field_type_common *member_b_ft, - GQuark member_a_name, GQuark member_b_name) -{ - int ret = 1; - - /* Label */ - if (member_a_name != member_b_name) { - BT_LOGV("Structure/variant field type fields differ: different names: " - "field-a-name=%s, field-b-name=%s", - g_quark_to_string(member_a_name), - g_quark_to_string(member_b_name)); - goto end; - } - - /* Type */ - ret = bt_ctf_field_type_common_compare(member_a_ft, member_b_ft); - if (ret == 1) { - BT_LOGV("Structure/variant field type fields differ: different field types: " - "field-name=\"%s\", field-a-ft-addr=%p, field-b-ft-addr=%p", - g_quark_to_string(member_a_name), - member_a_ft, member_b_ft); - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_structure_compare_recursive( - struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - int i; - struct bt_ctf_field_type_common_structure *struct_ft_a = - BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_structure *struct_ft_b = - BT_CTF_FROM_COMMON(ft_b); - - /* Alignment */ - if (bt_ctf_field_type_common_get_alignment(ft_a) != - bt_ctf_field_type_common_get_alignment(ft_b)) { - BT_LOGV("Structure field types differ: different alignments: " - "ft-a-align=%u, ft-b-align=%u", - bt_ctf_field_type_common_get_alignment(ft_a), - bt_ctf_field_type_common_get_alignment(ft_b)); - goto end; - } - - /* Fields */ - if (struct_ft_a->fields->len != struct_ft_b->fields->len) { - BT_LOGV("Structure field types differ: different field counts: " - "ft-a-field-count=%u, ft-b-field-count=%u", - struct_ft_a->fields->len, struct_ft_b->fields->len); - goto end; - } - - for (i = 0; i < struct_ft_a->fields->len; ++i) { - struct bt_ctf_field_type_common_structure_field *field_a = - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - struct_ft_a, i); - struct bt_ctf_field_type_common_structure_field *field_b = - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - struct_ft_b, i); - - ret = compare_structure_variant_members(field_a->type, - field_b->type, field_a->name, field_b->name); - if (ret) { - /* compare_structure_variant_members() logs what differs */ - BT_LOGV_STR("Structure field types differ: different fields."); - goto end; - } - } - - /* Equal */ - ret = 0; - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_variant_compare_recursive( - struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - int i; - struct bt_ctf_field_type_common_variant *var_ft_a = BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_variant *var_ft_b = BT_CTF_FROM_COMMON(ft_b); - - /* Tag name */ - if (strcmp(var_ft_a->tag_name->str, var_ft_b->tag_name->str)) { - BT_LOGV("Variant field types differ: different tag field names: " - "ft-a-tag-field-name=\"%s\", ft-b-tag-field-name=\"%s\"", - var_ft_a->tag_name->str, var_ft_b->tag_name->str); - goto end; - } - - /* Tag type */ - ret = bt_ctf_field_type_common_compare(BT_CTF_TO_COMMON(var_ft_a->tag_ft), - BT_CTF_TO_COMMON(var_ft_b->tag_ft)); - if (ret) { - BT_LOGV("Variant field types differ: different tag field types: " - "ft-a-tag-ft-addr=%p, ft-b-tag-ft-addr=%p", - var_ft_a->tag_ft, var_ft_b->tag_ft); - goto end; - } - - ret = 1; - - /* Fields */ - if (var_ft_a->choices->len != var_ft_b->choices->len) { - BT_LOGV("Variant field types differ: different field counts: " - "ft-a-field-count=%u, ft-b-field-count=%u", - var_ft_a->choices->len, var_ft_b->choices->len); - goto end; - } - - for (i = 0; i < var_ft_a->choices->len; ++i) { - struct bt_ctf_field_type_common_variant_choice *choice_a = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - var_ft_a, i); - struct bt_ctf_field_type_common_variant_choice *choice_b = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - var_ft_b, i); - - ret = compare_structure_variant_members(choice_a->type, - choice_b->type, choice_a->name, choice_b->name); - if (ret) { - /* compare_structure_variant_members() logs what differs */ - BT_LOGV_STR("Variant field types differ: different fields."); - goto end; - } - } - - /* Equal */ - ret = 0; - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_array_compare_recursive( - struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - struct bt_ctf_field_type_common_array *array_ft_a = BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_array *array_ft_b = BT_CTF_FROM_COMMON(ft_b); - - /* Length */ - if (array_ft_a->length != array_ft_b->length) { - BT_LOGV("Structure field types differ: different lengths: " - "ft-a-length=%u, ft-b-length=%u", - array_ft_a->length, array_ft_b->length); - goto end; - } - - /* Element type */ - ret = bt_ctf_field_type_common_compare(array_ft_a->element_ft, - array_ft_b->element_ft); - if (ret == 1) { - BT_LOGV("Array field types differ: different element field types: " - "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p", - array_ft_a->element_ft, array_ft_b->element_ft); - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_sequence_compare_recursive( - struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = -1; - struct bt_ctf_field_type_common_sequence *seq_ft_a = BT_CTF_FROM_COMMON(ft_a); - struct bt_ctf_field_type_common_sequence *seq_ft_b = BT_CTF_FROM_COMMON(ft_b); - - /* Length name */ - if (strcmp(seq_ft_a->length_field_name->str, - seq_ft_b->length_field_name->str)) { - BT_LOGV("Sequence field types differ: different length field names: " - "ft-a-length-field-name=\"%s\", " - "ft-b-length-field-name=\"%s\"", - seq_ft_a->length_field_name->str, - seq_ft_b->length_field_name->str); - goto end; - } - - /* Element type */ - ret = bt_ctf_field_type_common_compare(seq_ft_a->element_ft, - seq_ft_b->element_ft); - if (ret == 1) { - BT_LOGV("Sequence field types differ: different element field types: " - "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p", - seq_ft_a->element_ft, seq_ft_b->element_ft); - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a, - struct bt_ctf_field_type_common *ft_b) -{ - int ret = 1; - - BT_ASSERT_PRE_NON_NULL(ft_a, "Field type A"); - BT_ASSERT_PRE_NON_NULL(ft_b, "Field type B"); - - if (ft_a == ft_b) { - /* Same reference: equal (even if both are NULL) */ - ret = 0; - goto end; - } - - if (!ft_a) { - BT_LOGW_STR("Invalid parameter: field type A is NULL."); - ret = -1; - goto end; - } - - if (!ft_b) { - BT_LOGW_STR("Invalid parameter: field type B is NULL."); - ret = -1; - goto end; - } - - if (ft_a->id != ft_b->id) { - /* Different type IDs */ - BT_LOGV("Field types differ: different IDs: " - "ft-a-addr=%p, ft-b-addr=%p, " - "ft-a-id=%s, ft-b-id=%s", - ft_a, ft_b, - bt_ctf_field_type_id_string(ft_a->id), - bt_ctf_field_type_id_string(ft_b->id)); - goto end; - } - - if (ft_a->id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) { - /* Both have unknown type IDs */ - BT_LOGW_STR("Invalid parameter: field type IDs are unknown."); - goto end; - } - - BT_ASSERT(ft_a->methods->compare); - ret = ft_a->methods->compare(ft_a, ft_b); - if (ret == 1) { - BT_LOGV("Field types differ: ft-a-addr=%p, ft-b-addr=%p", - ft_a, ft_b); - } - -end: - return ret; -} - -BT_HIDDEN -int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft) -{ - int64_t field_count = -1; - - switch (ft->id) { - case BT_CTF_FIELD_TYPE_ID_STRUCT: - field_count = - bt_ctf_field_type_common_structure_get_field_count(ft); - break; - case BT_CTF_FIELD_TYPE_ID_VARIANT: - field_count = - bt_ctf_field_type_common_variant_get_field_count(ft); - break; - case BT_CTF_FIELD_TYPE_ID_ARRAY: - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - /* - * Array and sequence types always contain a single member - * (the element type). - */ - field_count = 1; - break; - default: - break; - } - - return field_count; -} - -BT_HIDDEN -struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index( - struct bt_ctf_field_type_common *ft, int index) -{ - struct bt_ctf_field_type_common *field_type = NULL; - - switch (ft->id) { - case BT_CTF_FIELD_TYPE_ID_STRUCT: - { - int ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - ft, NULL, &field_type, index); - if (ret) { - field_type = NULL; - goto end; - } - break; - } - case BT_CTF_FIELD_TYPE_ID_VARIANT: - { - int ret = bt_ctf_field_type_common_variant_borrow_field_by_index( - ft, NULL, &field_type, index); - if (ret) { - field_type = NULL; - goto end; - } - break; - } - case BT_CTF_FIELD_TYPE_ID_ARRAY: - field_type = - bt_ctf_field_type_common_array_borrow_element_field_type(ft); - break; - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - field_type = - bt_ctf_field_type_common_sequence_borrow_element_field_type(ft); - break; - default: - break; - } - -end: - return field_type; -} - -BT_HIDDEN -int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft, - const char *name) -{ - int field_index = -1; - - switch (ft->id) { - case BT_CTF_FIELD_TYPE_ID_STRUCT: - field_index = bt_ctf_field_type_common_structure_get_field_name_index( - ft, name); - break; - case BT_CTF_FIELD_TYPE_ID_VARIANT: - field_index = bt_ctf_field_type_common_variant_get_field_name_index( - ft, name); - break; - default: - break; - } - - return field_index; -} - -BT_HIDDEN -struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - return var_ft->tag_field_path; -} - -BT_HIDDEN -struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path( - struct bt_ctf_field_type_common *ft) -{ - struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft); - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE, - "Field type"); - return seq_ft->length_field_path; -} - -BT_HIDDEN -int bt_ctf_field_type_common_validate_single_clock_class( - struct bt_ctf_field_type_common *ft, - struct bt_ctf_clock_class **expected_clock_class) -{ - int ret = 0; - - if (!ft) { - goto end; - } - - BT_ASSERT(expected_clock_class); - - switch (ft->id) { - case BT_CTF_FIELD_TYPE_ID_INTEGER: - { - struct bt_ctf_clock_class *mapped_clock_class = - bt_ctf_field_type_common_integer_borrow_mapped_clock_class(ft); - - if (!mapped_clock_class) { - goto end; - } - - if (!*expected_clock_class) { - /* Move reference to output parameter */ - *expected_clock_class = bt_ctf_object_get_ref(mapped_clock_class); - mapped_clock_class = NULL; - BT_LOGV("Setting expected clock class: " - "expected-clock-class-addr=%p", - *expected_clock_class); - } else { - if (mapped_clock_class != *expected_clock_class) { - BT_LOGW("Integer field type is not mapped to " - "the expected clock class: " - "mapped-clock-class-addr=%p, " - "mapped-clock-class-name=\"%s\", " - "expected-clock-class-addr=%p, " - "expected-clock-class-name=\"%s\"", - mapped_clock_class, - bt_ctf_clock_class_get_name(mapped_clock_class), - *expected_clock_class, - bt_ctf_clock_class_get_name(*expected_clock_class)); - bt_ctf_object_put_ref(mapped_clock_class); - ret = -1; - goto end; - } - } - - break; - } - case BT_CTF_FIELD_TYPE_ID_ENUM: - case BT_CTF_FIELD_TYPE_ID_ARRAY: - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - { - struct bt_ctf_field_type_common *sub_ft = NULL; - - switch (ft->id) { - case BT_CTF_FIELD_TYPE_ID_ENUM: - sub_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type( - ft); - break; - case BT_CTF_FIELD_TYPE_ID_ARRAY: - sub_ft = bt_ctf_field_type_common_array_borrow_element_field_type( - ft); - break; - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - sub_ft = bt_ctf_field_type_common_sequence_borrow_element_field_type( - ft); - break; - default: - BT_LOGF("Unexpected field type ID: id=%d", ft->id); - abort(); - } - - BT_ASSERT(sub_ft); - ret = bt_ctf_field_type_common_validate_single_clock_class(sub_ft, - expected_clock_class); - break; - } - case BT_CTF_FIELD_TYPE_ID_STRUCT: - { - uint64_t i; - int64_t count = bt_ctf_field_type_common_structure_get_field_count( - ft); - - for (i = 0; i < count; i++) { - const char *name; - struct bt_ctf_field_type_common *member_type; - - ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - ft, &name, &member_type, i); - BT_ASSERT(ret == 0); - ret = bt_ctf_field_type_common_validate_single_clock_class( - member_type, expected_clock_class); - if (ret) { - BT_LOGW("Structure field type's field's type " - "is not recursively mapped to the " - "expected clock class: " - "field-ft-addr=%p, field-name=\"%s\"", - member_type, name); - goto end; - } - } - break; - } - case BT_CTF_FIELD_TYPE_ID_VARIANT: - { - uint64_t i; - int64_t count = bt_ctf_field_type_common_variant_get_field_count( - ft); - - for (i = 0; i < count; i++) { - const char *name; - struct bt_ctf_field_type_common *member_type; - - ret = bt_ctf_field_type_common_variant_borrow_field_by_index( - ft, &name, &member_type, i); - BT_ASSERT(ret == 0); - ret = bt_ctf_field_type_common_validate_single_clock_class( - member_type, expected_clock_class); - if (ret) { - BT_LOGW("Variant field type's field's type " - "is not recursively mapped to the " - "expected clock class: " - "field-ft-addr=%p, field-name=\"%s\"", - member_type, name); - goto end; - } - } - break; - } - default: - break; - } - -end: - return ret; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( - struct bt_ctf_field_type *ft); - -static -struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive( - struct bt_ctf_field_type *ft); - -static -struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( - struct bt_ctf_field_type *ft); - -static -struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive( - struct bt_ctf_field_type *ft); - -static -struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive( - struct bt_ctf_field_type *ft); - -static -struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive( - struct bt_ctf_field_type *ft); - -static -struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive( - struct bt_ctf_field_type *type); - -static -struct bt_ctf_field_type *bt_ctf_field_type_string_copy( - struct bt_ctf_field_type *type); - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_integer_methods = { - .freeze = bt_ctf_field_type_common_generic_freeze, - .validate = bt_ctf_field_type_common_integer_validate, - .set_byte_order = bt_ctf_field_type_common_integer_set_byte_order, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_integer_copy, - .compare = bt_ctf_field_type_common_integer_compare, -}; - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_floating_point_methods = { - .freeze = bt_ctf_field_type_common_generic_freeze, - .validate = NULL, - .set_byte_order = bt_ctf_field_type_common_floating_point_set_byte_order, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_floating_point_copy, - .compare = bt_ctf_field_type_common_floating_point_compare, -}; - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_enumeration_methods = { - .freeze = bt_ctf_field_type_common_enumeration_freeze_recursive, - .validate = bt_ctf_field_type_common_enumeration_validate_recursive, - .set_byte_order = bt_ctf_field_type_common_enumeration_set_byte_order_recursive, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_enumeration_copy_recursive, - .compare = bt_ctf_field_type_common_enumeration_compare_recursive, -}; - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_string_methods = { - .freeze = bt_ctf_field_type_common_generic_freeze, - .validate = NULL, - .set_byte_order = NULL, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_string_copy, - .compare = bt_ctf_field_type_common_string_compare, -}; - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_array_methods = { - .freeze = bt_ctf_field_type_common_array_freeze_recursive, - .validate = bt_ctf_field_type_common_array_validate_recursive, - .set_byte_order = bt_ctf_field_type_common_array_set_byte_order_recursive, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_array_copy_recursive, - .compare = bt_ctf_field_type_common_array_compare_recursive, -}; - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_sequence_methods = { - .freeze = bt_ctf_field_type_common_sequence_freeze_recursive, - .validate = bt_ctf_field_type_common_sequence_validate_recursive, - .set_byte_order = bt_ctf_field_type_common_sequence_set_byte_order_recursive, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_sequence_copy_recursive, - .compare = bt_ctf_field_type_common_sequence_compare_recursive, -}; - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_structure_methods = { - .freeze = bt_ctf_field_type_common_structure_freeze_recursive, - .validate = bt_ctf_field_type_common_structure_validate_recursive, - .set_byte_order = bt_ctf_field_type_common_structure_set_byte_order_recursive, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_structure_copy_recursive, - .compare = bt_ctf_field_type_common_structure_compare_recursive, -}; - -static struct bt_ctf_field_type_common_methods bt_ctf_field_type_variant_methods = { - .freeze = bt_ctf_field_type_common_variant_freeze_recursive, - .validate = bt_ctf_field_type_common_variant_validate_recursive, - .set_byte_order = bt_ctf_field_type_common_variant_set_byte_order_recursive, - .copy = (bt_ctf_field_type_common_method_copy) - bt_ctf_field_type_variant_copy_recursive, - .compare = bt_ctf_field_type_common_variant_compare_recursive, -}; - -typedef int (*bt_ctf_field_type_serialize_func)(struct bt_ctf_field_type_common *, - struct metadata_context *); - -BT_HIDDEN -int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type, - struct metadata_context *context) -{ - int ret; - struct bt_ctf_field_type_common *type_common = (void *) type; - bt_ctf_field_type_serialize_func serialize_func; - - BT_ASSERT(type); - BT_ASSERT(context); - - /* Make sure field type is valid before serializing it */ - ret = bt_ctf_field_type_common_validate((void *) type); - if (ret) { - BT_LOGW("Cannot serialize field type's metadata: field type is invalid: " - "addr=%p", type); - goto end; - } - - serialize_func = type_common->spec.writer.serialize_func; - ret = serialize_func((void *) type, context); - -end: - return ret; -} - -static -const char *get_encoding_string(enum bt_ctf_string_encoding encoding) -{ - const char *encoding_string; - - switch (encoding) { - case BT_CTF_STRING_ENCODING_NONE: - encoding_string = "none"; - break; - case BT_CTF_STRING_ENCODING_ASCII: - encoding_string = "ASCII"; - break; - case BT_CTF_STRING_ENCODING_UTF8: - encoding_string = "UTF8"; - break; - default: - encoding_string = "unknown"; - break; - } - - return encoding_string; -} - -static -const char *get_integer_base_string(enum bt_ctf_integer_base base) -{ - const char *base_string; - - switch (base) { - case BT_CTF_INTEGER_BASE_DECIMAL: - case BT_CTF_INTEGER_BASE_UNSPECIFIED: - base_string = "decimal"; - break; - case BT_CTF_INTEGER_BASE_HEXADECIMAL: - base_string = "hexadecimal"; - break; - case BT_CTF_INTEGER_BASE_OCTAL: - base_string = "octal"; - break; - case BT_CTF_INTEGER_BASE_BINARY: - base_string = "binary"; - break; - default: - base_string = "unknown"; - break; - } - - return base_string; -} - -static -void append_field_name(struct metadata_context *context, - const char *name) -{ - g_string_append_c(context->string, ' '); - - if (!bt_ctf_identifier_is_valid(name) || *name == '_') { - g_string_append_c(context->string, '_'); - } - - g_string_append(context->string, name); -} - -static -int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - struct bt_ctf_field_type_common_integer *integer = BT_CTF_FROM_COMMON(type); - int ret = 0; - - BT_LOGD("Serializing CTF writer integer field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - g_string_append_printf(context->string, - "integer { size = %u; align = %u; signed = %s; encoding = %s; base = %s; byte_order = %s", - integer->size, type->alignment, - (integer->is_signed ? "true" : "false"), - get_encoding_string(integer->encoding), - get_integer_base_string(integer->base), - bt_ctf_get_byte_order_string(integer->user_byte_order)); - if (integer->mapped_clock_class) { - const char *clock_name = bt_ctf_clock_class_get_name( - integer->mapped_clock_class); - - BT_ASSERT(clock_name); - g_string_append_printf(context->string, - "; map = clock.%s.value", clock_name); - } - - g_string_append(context->string, "; }"); - return ret; -} - -static -int bt_ctf_field_type_enumeration_serialize_recursive( - struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - size_t entry; - int ret; - struct bt_ctf_field_type_common_enumeration *enumeration = - BT_CTF_FROM_COMMON(type); - struct bt_ctf_field_type_common *container_type; - int container_signed; - - BT_LOGD("Serializing CTF writer enumeration field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - container_type = - bt_ctf_field_type_common_enumeration_borrow_container_field_type(type); - BT_ASSERT(container_type); - container_signed = bt_ctf_field_type_common_integer_is_signed( - container_type); - BT_ASSERT(container_signed >= 0); - g_string_append(context->string, "enum : "); - BT_LOGD_STR("Serializing CTF writer enumeration field type's container field type's metadata."); - ret = bt_ctf_field_type_serialize_recursive( - (void *) enumeration->container_ft, context); - if (ret) { - BT_LOGW("Cannot serialize CTF writer enumeration field type's container field type's metadata: " - "container-ft-addr=%p", enumeration->container_ft); - goto end; - } - - g_string_append(context->string, " { "); - for (entry = 0; entry < enumeration->entries->len; entry++) { - struct bt_ctf_enumeration_mapping *mapping = - enumeration->entries->pdata[entry]; - const char *label = g_quark_to_string(mapping->string); - - g_string_append(context->string, "\""); - - if (!bt_ctf_identifier_is_valid(label) || label[0] == '_') { - g_string_append(context->string, "_"); - } - - g_string_append_printf(context->string, "%s\" = ", label); - - if (container_signed) { - if (mapping->range_start._signed == - mapping->range_end._signed) { - g_string_append_printf(context->string, - "%" PRId64, - mapping->range_start._signed); - } else { - g_string_append_printf(context->string, - "%" PRId64 " ... %" PRId64, - mapping->range_start._signed, - mapping->range_end._signed); - } - } else { - if (mapping->range_start._unsigned == - mapping->range_end._unsigned) { - g_string_append_printf(context->string, - "%" PRIu64, - mapping->range_start._unsigned); - } else { - g_string_append_printf(context->string, - "%" PRIu64 " ... %" PRIu64, - mapping->range_start._unsigned, - mapping->range_end._unsigned); - } - } - - g_string_append(context->string, - ((entry != (enumeration->entries->len - 1)) ? - ", " : " }")); - } - - if (context->field_name->len) { - append_field_name(context, - context->field_name->str); - g_string_assign(context->field_name, ""); - } - -end: - return ret; -} - -static -int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - struct bt_ctf_field_type_common_floating_point *floating_point = - BT_CTF_FROM_COMMON(type); - - BT_LOGD("Serializing CTF writer floating point number field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - g_string_append_printf(context->string, - "floating_point { exp_dig = %u; mant_dig = %u; byte_order = %s; align = %u; }", - floating_point->exp_dig, - floating_point->mant_dig, - bt_ctf_get_byte_order_string(floating_point->user_byte_order), - type->alignment); - return 0; -} - -static -int bt_ctf_field_type_structure_serialize_recursive( - struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - size_t i; - unsigned int indent; - int ret = 0; - struct bt_ctf_field_type_common_structure *structure = BT_CTF_FROM_COMMON(type); - GString *structure_field_name = context->field_name; - - BT_LOGD("Serializing CTF writer structure field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - context->field_name = g_string_new(""); - - context->current_indentation_level++; - g_string_append(context->string, "struct {\n"); - - for (i = 0; i < structure->fields->len; i++) { - struct bt_ctf_field_type_common_structure_field *field = - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - structure, i); - - BT_LOGD("Serializing CTF writer structure field type's field metadata: " - "index=%zu, " - "field-ft-addr=%p, field-name=\"%s\"", - i, field, g_quark_to_string(field->name)); - - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - g_string_assign(context->field_name, - g_quark_to_string(field->name)); - ret = bt_ctf_field_type_serialize_recursive( - (void *) field->type, context); - if (ret) { - BT_LOGW("Cannot serialize CTF writer structure field type's field's metadata: " - "index=%zu, " - "field-ft-addr=%p, field-name=\"%s\"", - i, field->type, - g_quark_to_string(field->name)); - goto end; - } - - if (context->field_name->len) { - append_field_name(context, - context->field_name->str); - } - g_string_append(context->string, ";\n"); - } - - context->current_indentation_level--; - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - g_string_append_printf(context->string, "} align(%u)", - type->alignment); - -end: - g_string_free(context->field_name, TRUE); - context->field_name = structure_field_name; - return ret; -} - -static -int bt_ctf_field_type_variant_serialize_recursive( - struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - size_t i; - unsigned int indent; - int ret = 0; - struct bt_ctf_field_type_common_variant *variant = BT_CTF_FROM_COMMON(type); - GString *variant_field_name = context->field_name; - - BT_LOGD("Serializing CTF writer variant field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - context->field_name = g_string_new(""); - if (variant->tag_name->len > 0) { - g_string_append(context->string, "variant <"); - append_field_name(context, variant->tag_name->str); - g_string_append(context->string, "> {\n"); - } else { - g_string_append(context->string, "variant {\n"); - } - - context->current_indentation_level++; - for (i = 0; i < variant->choices->len; i++) { - struct bt_ctf_field_type_common_variant_choice *field = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - variant, i); - - BT_LOGD("Serializing CTF writer variant field type's field metadata: " - "index=%zu, " - "field-ft-addr=%p, field-name=\"%s\"", - i, field, g_quark_to_string(field->name)); - - g_string_assign(context->field_name, - g_quark_to_string(field->name)); - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - g_string_assign(context->field_name, - g_quark_to_string(field->name)); - ret = bt_ctf_field_type_serialize_recursive( - (void *) field->type, context); - if (ret) { - BT_LOGW("Cannot serialize CTF writer variant field type's field's metadata: " - "index=%zu, " - "field-ft-addr=%p, field-name=\"%s\"", - i, field->type, - g_quark_to_string(field->name)); - goto end; - } - - if (context->field_name->len) { - append_field_name(context, - context->field_name->str); - g_string_append_c(context->string, ';'); - } - - g_string_append_c(context->string, '\n'); - } - - context->current_indentation_level--; - for (indent = 0; indent < context->current_indentation_level; - indent++) { - g_string_append_c(context->string, '\t'); - } - - g_string_append(context->string, "}"); - -end: - g_string_free(context->field_name, TRUE); - context->field_name = variant_field_name; - return ret; -} - -static -int bt_ctf_field_type_array_serialize_recursive( - struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - int ret = 0; - struct bt_ctf_field_type_common_array *array = BT_CTF_FROM_COMMON(type); - - BT_LOGD("Serializing CTF writer array field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - BT_LOGD_STR("Serializing CTF writer array field type's element field type's metadata."); - ret = bt_ctf_field_type_serialize_recursive( - (void *) array->element_ft, context); - if (ret) { - BT_LOGW("Cannot serialize CTF writer array field type's element field type's metadata: " - "element-ft-addr=%p", array->element_ft); - goto end; - } - - if (context->field_name->len) { - append_field_name(context, - context->field_name->str); - - g_string_append_printf(context->string, "[%u]", array->length); - g_string_assign(context->field_name, ""); - } else { - g_string_append_printf(context->string, "[%u]", array->length); - } - -end: - return ret; -} - -static -int bt_ctf_field_type_sequence_serialize_recursive( - struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - int ret = 0; - struct bt_ctf_field_type_common_sequence *sequence = BT_CTF_FROM_COMMON(type); - - BT_LOGD("Serializing CTF writer sequence field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - BT_LOGD_STR("Serializing CTF writer sequence field type's element field type's metadata."); - ret = bt_ctf_field_type_serialize_recursive( - (void *) sequence->element_ft, context); - if (ret) { - BT_LOGW("Cannot serialize CTF writer sequence field type's element field type's metadata: " - "element-ft-addr=%p", sequence->element_ft); - goto end; - } - - if (context->field_name->len) { - append_field_name(context, context->field_name->str); - g_string_assign(context->field_name, ""); - } - g_string_append(context->string, "["); - append_field_name(context, sequence->length_field_name->str); - g_string_append(context->string, "]"); - -end: - return ret; -} - -static -int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type_common *type, - struct metadata_context *context) -{ - struct bt_ctf_field_type_common_string *string = BT_CTF_FROM_COMMON(type); - - BT_LOGD("Serializing CTF writer string field type's metadata: " - "ft-addr=%p, metadata-context-addr=%p", type, context); - g_string_append_printf(context->string, - "string { encoding = %s; }", - get_encoding_string(string->encoding)); - return 0; -} - -struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size) -{ - struct bt_ctf_field_type_common_integer *integer = NULL; - - BT_LOGD("Creating CTF writer integer field type object: size=%u", size); - - if (size == 0 || size > 64) { - BT_LOGW("Invalid parameter: size must be between 1 and 64: " - "size=%u", size); - goto error; - } - - integer = g_new0(struct bt_ctf_field_type_common_integer, 1); - if (!integer) { - BT_LOGE_STR("Failed to allocate one integer field type."); - goto error; - } - - bt_ctf_field_type_common_integer_initialize(BT_CTF_TO_COMMON(integer), - size, bt_ctf_field_type_common_integer_destroy, - &bt_ctf_field_type_integer_methods); - integer->common.spec.writer.serialize_func = - bt_ctf_field_type_integer_serialize; - BT_LOGD("Created CTF writer integer field type object: addr=%p, size=%u", - integer, size); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(integer); - -end: - return (void *) integer; -} - -int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_integer_get_size((void *) ft); -} - -bt_bool bt_ctf_field_type_integer_is_signed(struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_integer_is_signed((void *) ft); -} - -int bt_ctf_field_type_integer_set_is_signed(struct bt_ctf_field_type *ft, - bt_bool is_signed) -{ - return bt_ctf_field_type_common_integer_set_is_signed((void *) ft, - is_signed); -} - -int bt_ctf_field_type_integer_set_size(struct bt_ctf_field_type *ft, - unsigned int size) -{ - return bt_ctf_field_type_common_integer_set_size((void *) ft, size); -} - -enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base( - struct bt_ctf_field_type *ft) -{ - return (int) bt_ctf_field_type_common_integer_get_base((void *) ft); -} - -int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *ft, - enum bt_ctf_integer_base base) -{ - return bt_ctf_field_type_common_integer_set_base((void *) ft, - (int) base); -} - -enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding( - struct bt_ctf_field_type *ft) -{ - return (int) bt_ctf_field_type_common_integer_get_encoding((void *) ft); -} - -int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *ft, - enum bt_ctf_string_encoding encoding) -{ - return bt_ctf_field_type_common_integer_set_encoding((void *) ft, - (int) encoding); -} - -struct bt_ctf_clock_class *bt_ctf_field_type_integer_get_mapped_clock_class( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_object_get_ref(bt_ctf_field_type_common_integer_borrow_mapped_clock_class( - (void *) ft)); -} - -int bt_ctf_field_type_integer_set_mapped_clock_class( - struct bt_ctf_field_type *ft, - struct bt_ctf_clock_class *clock_class) -{ - return bt_ctf_field_type_common_integer_set_mapped_clock_class((void *) ft, - clock_class); -} - -int bt_ctf_field_type_enumeration_signed_get_mapping_by_index( - struct bt_ctf_field_type *ft, uint64_t index, - const char **mapping_name, int64_t *range_begin, - int64_t *range_end) -{ - return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index( - (void *) ft, index, mapping_name, range_begin, range_end); -} - -int bt_ctf_field_type_enumeration_unsigned_get_mapping_by_index( - struct bt_ctf_field_type *ft, uint64_t index, - const char **mapping_name, uint64_t *range_begin, - uint64_t *range_end) -{ - return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index( - (void *) ft, index, mapping_name, range_begin, range_end); -} - -struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( - struct bt_ctf_field_type *container_ft) -{ - struct bt_ctf_field_type_common_enumeration *enumeration = NULL; - struct bt_ctf_field_type_common *int_ft = (void *) container_ft; - - BT_LOGD("Creating CTF writer enumeration field type object: int-ft-addr=%p", - container_ft); - - if (!container_ft) { - BT_LOGW_STR("Invalid parameter: field type is NULL."); - goto error; - } - - if (int_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid parameter: container field type is not an integer field type: " - "container-ft-addr=%p, container-ft-id=%s", - container_ft, bt_ctf_field_type_id_string(int_ft->id)); - goto error; - } - - enumeration = g_new0(struct bt_ctf_field_type_common_enumeration, 1); - if (!enumeration) { - BT_LOGE_STR("Failed to allocate one enumeration field type."); - goto error; - } - - bt_ctf_field_type_common_enumeration_initialize(BT_CTF_TO_COMMON(enumeration), - int_ft, bt_ctf_field_type_common_enumeration_destroy_recursive, - &bt_ctf_field_type_enumeration_methods); - enumeration->common.spec.writer.serialize_func = - bt_ctf_field_type_enumeration_serialize_recursive; - BT_LOGD("Created CTF writer enumeration field type object: addr=%p, " - "int-ft-addr=%p, int-ft-size=%u", - enumeration, container_ft, - bt_ctf_field_type_integer_get_size(container_ft)); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration); - -end: - return (void *) enumeration; -} - -struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_field_type( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_object_get_ref( - bt_ctf_field_type_common_enumeration_borrow_container_field_type( - (void *) ft)); -} - -int bt_ctf_field_type_enumeration_signed_add_mapping( - struct bt_ctf_field_type *ft, const char *string, - int64_t range_start, int64_t range_end) -{ - return bt_ctf_field_type_common_enumeration_signed_add_mapping( - (void *) ft, string, range_start, range_end); -} - -int bt_ctf_field_type_enumeration_unsigned_add_mapping( - struct bt_ctf_field_type *ft, const char *string, - uint64_t range_start, uint64_t range_end) -{ - return bt_ctf_field_type_common_enumeration_unsigned_add_mapping( - (void *) ft, string, range_start, range_end); -} - -int64_t bt_ctf_field_type_enumeration_get_mapping_count( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_enumeration_get_mapping_count((void *) ft); -} - -struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void) -{ - struct bt_ctf_field_type_common_floating_point *floating_point = - g_new0(struct bt_ctf_field_type_common_floating_point, 1); - - BT_LOGD_STR("Creating CTF writer floating point number field type object."); - - if (!floating_point) { - BT_LOGE_STR("Failed to allocate one floating point number field type."); - goto end; - } - - bt_ctf_field_type_common_floating_point_initialize( - BT_CTF_TO_COMMON(floating_point), - bt_ctf_field_type_common_floating_point_destroy, - &bt_ctf_field_type_floating_point_methods); - floating_point->common.spec.writer.serialize_func = - bt_ctf_field_type_floating_point_serialize; - BT_LOGD("Created CTF writer floating point number field type object: addr=%p, " - "exp-size=%u, mant-size=%u", floating_point, - floating_point->exp_dig, floating_point->mant_dig); - -end: - return (void *) floating_point; -} - -int bt_ctf_field_type_floating_point_get_exponent_digits( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_floating_point_get_exponent_digits( - (void *) ft); -} - -int bt_ctf_field_type_floating_point_set_exponent_digits( - struct bt_ctf_field_type *ft, unsigned int exponent_digits) -{ - return bt_ctf_field_type_common_floating_point_set_exponent_digits( - (void *) ft, exponent_digits); -} - -int bt_ctf_field_type_floating_point_get_mantissa_digits( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_floating_point_get_mantissa_digits( - (void *) ft); -} - -int bt_ctf_field_type_floating_point_set_mantissa_digits( - struct bt_ctf_field_type *ft, unsigned int mantissa_digits) -{ - return bt_ctf_field_type_common_floating_point_set_mantissa_digits( - (void *) ft, mantissa_digits); -} - -struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void) -{ - struct bt_ctf_field_type_common_structure *structure = - g_new0(struct bt_ctf_field_type_common_structure, 1); - - BT_LOGD_STR("Creating CTF writer structure field type object."); - - if (!structure) { - BT_LOGE_STR("Failed to allocate one structure field type."); - goto error; - } - - bt_ctf_field_type_common_structure_initialize(BT_CTF_TO_COMMON(structure), - bt_ctf_field_type_common_structure_destroy_recursive, - &bt_ctf_field_type_structure_methods); - structure->common.spec.writer.serialize_func = - bt_ctf_field_type_structure_serialize_recursive; - BT_LOGD("Created CTF writer structure field type object: addr=%p", - structure); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(structure); - -end: - return (void *) structure; -} - -int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *ft, - struct bt_ctf_field_type *field_type, - const char *field_name) -{ - return bt_ctf_field_type_common_structure_add_field((void *) ft, - (void *) field_type, field_name); -} - -int64_t bt_ctf_field_type_structure_get_field_count(struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_structure_get_field_count((void *) ft); -} - -int bt_ctf_field_type_structure_get_field_by_index( - struct bt_ctf_field_type *ft, - const char **field_name, - struct bt_ctf_field_type **field_type, uint64_t index) -{ - int ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - (void *) ft, field_name, (void *) field_type, index); - - if (ret == 0 && field_type) { - bt_ctf_object_get_ref(*field_type); - } - - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name( - struct bt_ctf_field_type *ft, const char *name) -{ - return bt_ctf_object_get_ref(bt_ctf_field_type_common_structure_borrow_field_type_by_name( - (void *) ft, name)); -} - -struct bt_ctf_field_type *bt_ctf_field_type_variant_create( - struct bt_ctf_field_type *tag_ft, const char *tag_name) -{ - struct bt_ctf_field_type_common_variant *var_ft = NULL; - - BT_LOGD("Creating CTF writer variant field type object: " - "tag-ft-addr=%p, tag-field-name=\"%s\"", - tag_ft, tag_name); - - if (tag_name && !bt_ctf_identifier_is_valid(tag_name)) { - BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: " - "tag-ft-addr=%p, tag-field-name=\"%s\"", - tag_ft, tag_name); - goto error; - } - - var_ft = g_new0(struct bt_ctf_field_type_common_variant, 1); - if (!var_ft) { - BT_LOGE_STR("Failed to allocate one variant field type."); - goto error; - } - - bt_ctf_field_type_common_variant_initialize(BT_CTF_TO_COMMON(var_ft), - (void *) tag_ft, tag_name, - bt_ctf_field_type_common_variant_destroy_recursive, - &bt_ctf_field_type_variant_methods); - var_ft->common.spec.writer.serialize_func = - bt_ctf_field_type_variant_serialize_recursive; - BT_LOGD("Created CTF writer variant field type object: addr=%p, " - "tag-ft-addr=%p, tag-field-name=\"%s\"", - var_ft, tag_ft, tag_name); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(var_ft); - -end: - return (void *) var_ft; -} - -struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_field_type( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_tag_field_type( - (void *) ft)); -} - -const char *bt_ctf_field_type_variant_get_tag_name(struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_variant_get_tag_name((void *) ft); -} - -int bt_ctf_field_type_variant_set_tag_name( - struct bt_ctf_field_type *ft, const char *name) -{ - return bt_ctf_field_type_common_variant_set_tag_name((void *) ft, name); -} - -int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *ft, - struct bt_ctf_field_type *field_type, - const char *field_name) -{ - return bt_ctf_field_type_common_variant_add_field((void *) ft, - (void *) field_type, field_name); -} - -struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name( - struct bt_ctf_field_type *ft, - const char *field_name) -{ - return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_field_type_by_name( - (void *) ft, field_name)); -} - -struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag( - struct bt_ctf_field_type *ft, - struct bt_ctf_field *tag_field) -{ - int ret; - int64_t choice_index; - struct bt_ctf_field *container; - struct bt_ctf_field_type_common_variant *var_ft = (void *) ft; - struct bt_ctf_field_type *ret_ft = NULL; - - BT_ASSERT_PRE_NON_NULL(ft, "Field type"); - BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT, - "Field type"); - BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID( - (struct bt_ctf_field_common *) tag_field, - BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((struct bt_ctf_field_common *) tag_field, - "Tag field"); - - container = bt_ctf_field_enumeration_borrow_container(tag_field); - BT_ASSERT(container); - - if (var_ft->tag_ft->container_ft->is_signed) { - int64_t val; - - ret = bt_ctf_field_integer_signed_get_value(container, - &val); - BT_ASSERT(ret == 0); - choice_index = bt_ctf_field_type_common_variant_find_choice_index( - (void *) ft, (uint64_t) val, true); - } else { - uint64_t val; - - ret = bt_ctf_field_integer_unsigned_get_value(container, - &val); - BT_ASSERT(ret == 0); - choice_index = bt_ctf_field_type_common_variant_find_choice_index( - (void *) ft, val, false); - } - - if (choice_index < 0) { - BT_LIB_LOGW("Cannot find variant field type's field: " - "var-ft-addr=%p, tag-field-addr=%p", ft, tag_field); - goto end; - } - - ret = bt_ctf_field_type_variant_get_field_by_index(ft, NULL, - &ret_ft, choice_index); - BT_ASSERT(ret == 0); - -end: - return ret_ft; -} - -int64_t bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_variant_get_field_count((void *) ft); -} - -int bt_ctf_field_type_variant_get_field_by_index(struct bt_ctf_field_type *ft, - const char **field_name, struct bt_ctf_field_type **field_type, - uint64_t index) -{ - int ret = bt_ctf_field_type_common_variant_borrow_field_by_index( - (void *) ft, field_name, (void *) field_type, index); - - if (ret == 0 && field_type) { - bt_ctf_object_get_ref(*field_type); - } - - return ret; -} - -struct bt_ctf_field_type *bt_ctf_field_type_array_create( - struct bt_ctf_field_type *element_ft, unsigned int length) -{ - struct bt_ctf_field_type_common_array *array = NULL; - - BT_LOGD("Creating CTF writer array field type object: element-ft-addr=%p, " - "length=%u", element_ft, length); - - if (!element_ft) { - BT_LOGW_STR("Invalid parameter: element field type is NULL."); - goto error; - } - - if (length == 0) { - BT_LOGW_STR("Invalid parameter: length is zero."); - goto error; - } - - array = g_new0(struct bt_ctf_field_type_common_array, 1); - if (!array) { - BT_LOGE_STR("Failed to allocate one array field type."); - goto error; - } - - bt_ctf_field_type_common_array_initialize(BT_CTF_TO_COMMON(array), - (void *) element_ft, length, - bt_ctf_field_type_common_array_destroy_recursive, - &bt_ctf_field_type_array_methods); - array->common.spec.writer.serialize_func = - bt_ctf_field_type_array_serialize_recursive; - BT_LOGD("Created CTF writer array field type object: addr=%p, " - "element-ft-addr=%p, length=%u", - array, element_ft, length); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(array); - -end: - return (void *) array; -} - -struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_field_type( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_object_get_ref(bt_ctf_field_type_common_array_borrow_element_field_type( - (void *) ft)); -} - -int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_array_get_length((void *) ft); -} - -struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( - struct bt_ctf_field_type *element_ft, - const char *length_field_name) -{ - struct bt_ctf_field_type_common_sequence *sequence = NULL; - - BT_LOGD("Creating CTF writer sequence field type object: element-ft-addr=%p, " - "length-field-name=\"%s\"", element_ft, length_field_name); - - if (!element_ft) { - BT_LOGW_STR("Invalid parameter: element field type is NULL."); - goto error; - } - - if (!bt_ctf_identifier_is_valid(length_field_name)) { - BT_LOGW("Invalid parameter: length field name is not a valid CTF identifier: " - "length-field-name=\"%s\"", length_field_name); - goto error; - } - - sequence = g_new0(struct bt_ctf_field_type_common_sequence, 1); - if (!sequence) { - BT_LOGE_STR("Failed to allocate one sequence field type."); - goto error; - } - - bt_ctf_field_type_common_sequence_initialize(BT_CTF_TO_COMMON(sequence), - (void *) element_ft, length_field_name, - bt_ctf_field_type_common_sequence_destroy_recursive, - &bt_ctf_field_type_sequence_methods); - sequence->common.spec.writer.serialize_func = - bt_ctf_field_type_sequence_serialize_recursive; - BT_LOGD("Created CTF writer sequence field type object: addr=%p, " - "element-ft-addr=%p, length-field-name=\"%s\"", - sequence, element_ft, length_field_name); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(sequence); - -end: - return (void *) sequence; -} - -struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_field_type( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_object_get_ref(bt_ctf_field_type_common_sequence_borrow_element_field_type( - (void *) ft)); -} - -const char *bt_ctf_field_type_sequence_get_length_field_name( - struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_sequence_get_length_field_name((void *) ft); -} - -struct bt_ctf_field_type *bt_ctf_field_type_string_create(void) -{ - struct bt_ctf_field_type_common_string *string = - g_new0(struct bt_ctf_field_type_common_string, 1); - - BT_LOGD_STR("Creating CTF writer string field type object."); - - if (!string) { - BT_LOGE_STR("Failed to allocate one string field type."); - return NULL; - } - - bt_ctf_field_type_common_string_initialize(BT_CTF_TO_COMMON(string), - bt_ctf_field_type_common_string_destroy, - &bt_ctf_field_type_string_methods); - string->common.spec.writer.serialize_func = - bt_ctf_field_type_string_serialize; - BT_LOGD("Created CTF writer string field type object: addr=%p", string); - return (void *) string; -} - -enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding( - struct bt_ctf_field_type *ft) -{ - return (int) bt_ctf_field_type_common_string_get_encoding((void *) ft); -} - -int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *ft, - enum bt_ctf_string_encoding encoding) -{ - return bt_ctf_field_type_common_string_set_encoding((void *) ft, - (int) encoding); -} - -int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *ft) -{ - return bt_ctf_field_type_common_get_alignment((void *) ft); -} - -int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *ft, - unsigned int alignment) -{ - return bt_ctf_field_type_common_set_alignment((void *) ft, alignment); -} - -enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order( - struct bt_ctf_field_type *ft) -{ - return (int) bt_ctf_field_type_common_get_byte_order((void *) ft); -} - -int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *ft, - enum bt_ctf_byte_order byte_order) -{ - return bt_ctf_field_type_common_set_byte_order((void *) ft, - (int) byte_order); -} - -enum bt_ctf_field_type_id bt_ctf_field_type_get_type_id( - struct bt_ctf_field_type *ft) -{ - return (int) bt_ctf_field_type_common_get_type_id((void *) ft); -} - -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft) -{ - return (void *) bt_ctf_field_type_common_copy((void *) ft); -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( - struct bt_ctf_field_type *ft) -{ - struct bt_ctf_field_type_common_integer *int_ft = (void *) ft; - struct bt_ctf_field_type_common_integer *copy_ft; - - BT_LOGD("Copying CTF writer integer field type's: addr=%p", ft); - copy_ft = (void *) bt_ctf_field_type_integer_create(int_ft->size); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer integer field type."); - goto end; - } - - copy_ft->mapped_clock_class = bt_ctf_object_get_ref(int_ft->mapped_clock_class); - copy_ft->user_byte_order = int_ft->user_byte_order; - copy_ft->is_signed = int_ft->is_signed; - copy_ft->size = int_ft->size; - copy_ft->base = int_ft->base; - copy_ft->encoding = int_ft->encoding; - BT_LOGD("Copied CTF writer integer field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - return (void *) copy_ft; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive( - struct bt_ctf_field_type *ft) -{ - size_t i; - struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) ft; - struct bt_ctf_field_type_common_enumeration *copy_ft = NULL; - struct bt_ctf_field_type_common_enumeration *container_copy_ft; - - BT_LOGD("Copying CTF writer enumeration field type's: addr=%p", ft); - - /* Copy the source enumeration's container */ - BT_LOGD_STR("Copying CTF writer enumeration field type's container field type."); - container_copy_ft = BT_CTF_FROM_COMMON(bt_ctf_field_type_common_copy( - BT_CTF_TO_COMMON(enum_ft->container_ft))); - if (!container_copy_ft) { - BT_LOGE_STR("Cannot copy CTF writer enumeration field type's container field type."); - goto end; - } - - copy_ft = (void *) bt_ctf_field_type_enumeration_create( - (void *) container_copy_ft); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer enumeration field type."); - goto end; - } - - /* Copy all enumaration entries */ - for (i = 0; i < enum_ft->entries->len; i++) { - struct bt_ctf_enumeration_mapping *mapping = g_ptr_array_index( - enum_ft->entries, i); - struct bt_ctf_enumeration_mapping *copy_mapping = g_new0( - struct bt_ctf_enumeration_mapping, 1); - - if (!copy_mapping) { - BT_LOGE_STR("Failed to allocate one enumeration mapping."); - goto error; - } - - *copy_mapping = *mapping; - g_ptr_array_add(copy_ft->entries, copy_mapping); - } - - BT_LOGD("Copied CTF writer enumeration field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - bt_ctf_object_put_ref(container_copy_ft); - return (void *) copy_ft; - -error: - bt_ctf_object_put_ref(container_copy_ft); - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); - return (void *) copy_ft; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( - struct bt_ctf_field_type *ft) -{ - struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft); - struct bt_ctf_field_type_common_floating_point *copy_ft; - - BT_LOGD("Copying CTF writer floating point number field type's: addr=%p", ft); - copy_ft = (void *) bt_ctf_field_type_floating_point_create(); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer floating point number field type."); - goto end; - } - - copy_ft->user_byte_order = flt_ft->user_byte_order; - copy_ft->exp_dig = flt_ft->exp_dig; - copy_ft->mant_dig = flt_ft->mant_dig; - BT_LOGD("Copied CTF writer floating point number field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - return (void *) copy_ft; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive( - struct bt_ctf_field_type *ft) -{ - int64_t i; - GHashTableIter iter; - gpointer key, value; - struct bt_ctf_field_type_common_structure *struct_ft = (void *) ft; - struct bt_ctf_field_type_common_structure *copy_ft; - - BT_LOGD("Copying CTF writer structure field type's: addr=%p", ft); - copy_ft = (void *) bt_ctf_field_type_structure_create(); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer structure field type."); - goto end; - } - - /* Copy field_name_to_index */ - g_hash_table_iter_init(&iter, struct_ft->field_name_to_index); - while (g_hash_table_iter_next(&iter, &key, &value)) { - g_hash_table_insert(copy_ft->field_name_to_index, - key, value); - } - - g_array_set_size(copy_ft->fields, struct_ft->fields->len); - - for (i = 0; i < struct_ft->fields->len; i++) { - struct bt_ctf_field_type_common_structure_field *entry, *copy_entry; - struct bt_ctf_field_type_common *field_ft_copy; - - entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - struct_ft, i); - copy_entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - copy_ft, i); - BT_LOGD("Copying CTF writer structure field type's field: " - "index=%" PRId64 ", " - "field-ft-addr=%p, field-name=\"%s\"", - i, entry, g_quark_to_string(entry->name)); - - field_ft_copy = (void *) bt_ctf_field_type_copy( - (void *) entry->type); - if (!field_ft_copy) { - BT_LOGE("Cannot copy CTF writer structure field type's field: " - "index=%" PRId64 ", " - "field-ft-addr=%p, field-name=\"%s\"", - i, entry, g_quark_to_string(entry->name)); - goto error; - } - - copy_entry->name = entry->name; - copy_entry->type = field_ft_copy; - } - - BT_LOGD("Copied CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - return (void *) copy_ft; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); - return NULL; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive( - struct bt_ctf_field_type *ft) -{ - int64_t i; - GHashTableIter iter; - gpointer key, value; - struct bt_ctf_field_type_common *tag_ft_copy = NULL; - struct bt_ctf_field_type_common_variant *var_ft = (void *) ft; - struct bt_ctf_field_type_common_variant *copy_ft = NULL; - - BT_LOGD("Copying CTF writer variant field type's: addr=%p", ft); - if (var_ft->tag_ft) { - BT_LOGD_STR("Copying CTF writer variant field type's tag field type."); - tag_ft_copy = bt_ctf_field_type_common_copy( - BT_CTF_TO_COMMON(var_ft->tag_ft)); - if (!tag_ft_copy) { - BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field type."); - goto end; - } - } - - copy_ft = (void *) bt_ctf_field_type_variant_create( - (void *) tag_ft_copy, - var_ft->tag_name->len ? var_ft->tag_name->str : NULL); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer variant field type."); - goto end; - } - - /* Copy field_name_to_index */ - g_hash_table_iter_init(&iter, var_ft->choice_name_to_index); - while (g_hash_table_iter_next(&iter, &key, &value)) { - g_hash_table_insert(copy_ft->choice_name_to_index, - key, value); - } - - g_array_set_size(copy_ft->choices, var_ft->choices->len); - - for (i = 0; i < var_ft->choices->len; i++) { - struct bt_ctf_field_type_common_variant_choice *entry, *copy_entry; - struct bt_ctf_field_type_common *field_ft_copy; - uint64_t range_i; - - entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i); - copy_entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - copy_ft, i); - BT_LOGD("Copying CTF writer variant field type's field: " - "index=%" PRId64 ", " - "field-ft-addr=%p, field-name=\"%s\"", - i, entry, g_quark_to_string(entry->name)); - - field_ft_copy = (void *) bt_ctf_field_type_copy( - (void *) entry->type); - if (!field_ft_copy) { - BT_LOGE("Cannot copy CTF writer variant field type's field: " - "index=%" PRId64 ", " - "field-ft-addr=%p, field-name=\"%s\"", - i, entry, g_quark_to_string(entry->name)); - g_free(copy_entry); - goto error; - } - - copy_entry->name = entry->name; - copy_entry->type = field_ft_copy; - - /* Copy ranges */ - copy_entry->ranges = g_array_new(FALSE, TRUE, - sizeof(struct bt_ctf_field_type_common_variant_choice_range)); - BT_ASSERT(copy_entry->ranges); - g_array_set_size(copy_entry->ranges, entry->ranges->len); - - for (range_i = 0; range_i < entry->ranges->len; range_i++) { - copy_entry->ranges[range_i] = entry->ranges[range_i]; - } - } - - if (var_ft->tag_field_path) { - BT_LOGD_STR("Copying CTF writer variant field type's tag field path."); - copy_ft->tag_field_path = bt_ctf_field_path_copy( - var_ft->tag_field_path); - if (!copy_ft->tag_field_path) { - BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field path."); - goto error; - } - } - - copy_ft->choices_up_to_date = var_ft->choices_up_to_date; - BT_LOGD("Copied CTF writer variant field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - bt_ctf_object_put_ref(tag_ft_copy); - return (void *) copy_ft; - -error: - bt_ctf_object_put_ref(tag_ft_copy); - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); - return NULL; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive( - struct bt_ctf_field_type *ft) -{ - struct bt_ctf_field_type_common *container_ft_copy = NULL; - struct bt_ctf_field_type_common_array *array_ft = (void *) ft; - struct bt_ctf_field_type_common_array *copy_ft = NULL; - - BT_LOGD("Copying CTF writer array field type's: addr=%p", ft); - BT_LOGD_STR("Copying CTF writer array field type's element field type."); - container_ft_copy = bt_ctf_field_type_common_copy(array_ft->element_ft); - if (!container_ft_copy) { - BT_LOGE_STR("Cannot copy CTF writer array field type's element field type."); - goto end; - } - - copy_ft = (void *) bt_ctf_field_type_array_create( - (void *) container_ft_copy, array_ft->length); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer array field type."); - goto end; - } - - BT_LOGD("Copied CTF writer array field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - bt_ctf_object_put_ref(container_ft_copy); - return (void *) copy_ft; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive( - struct bt_ctf_field_type *ft) -{ - struct bt_ctf_field_type_common *container_ft_copy = NULL; - struct bt_ctf_field_type_common_sequence *seq_ft = (void *) ft; - struct bt_ctf_field_type_common_sequence *copy_ft = NULL; - - BT_LOGD("Copying CTF writer sequence field type's: addr=%p", ft); - BT_LOGD_STR("Copying CTF writer sequence field type's element field type."); - container_ft_copy = bt_ctf_field_type_common_copy(seq_ft->element_ft); - if (!container_ft_copy) { - BT_LOGE_STR("Cannot copy CTF writer sequence field type's element field type."); - goto end; - } - - copy_ft = (void *) bt_ctf_field_type_sequence_create( - (void *) container_ft_copy, - seq_ft->length_field_name->len ? - seq_ft->length_field_name->str : NULL); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer sequence field type."); - goto end; - } - - if (seq_ft->length_field_path) { - BT_LOGD_STR("Copying CTF writer sequence field type's length field path."); - copy_ft->length_field_path = bt_ctf_field_path_copy( - seq_ft->length_field_path); - if (!copy_ft->length_field_path) { - BT_LOGE_STR("Cannot copy CTF writer sequence field type's length field path."); - goto error; - } - } - - BT_LOGD("Copied CTF writer sequence field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - bt_ctf_object_put_ref(container_ft_copy); - return (void *) copy_ft; -error: - bt_ctf_object_put_ref(container_ft_copy); - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft); - return NULL; -} - -static -struct bt_ctf_field_type *bt_ctf_field_type_string_copy(struct bt_ctf_field_type *ft) -{ - struct bt_ctf_field_type_common_string *string_ft = (void *) ft; - struct bt_ctf_field_type_common_string *copy_ft = NULL; - - BT_LOGD("Copying CTF writer string field type's: addr=%p", ft); - copy_ft = (void *) bt_ctf_field_type_string_create(); - if (!copy_ft) { - BT_LOGE_STR("Cannot create CTF writer string field type."); - goto end; - } - - copy_ft->encoding = string_ft->encoding; - BT_LOGD("Copied CTF writer string field type: original-ft-addr=%p, copy-ft-addr=%p", - ft, copy_ft); - -end: - return (void *) copy_ft; -} diff --git a/lib/ctf-writer/field-wrapper.c b/lib/ctf-writer/field-wrapper.c deleted file mode 100644 index f5629fcd..00000000 --- a/lib/ctf-writer/field-wrapper.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-FIELD-WRAPPER" -#include - -#include -#include -#include -#include -#include - -BT_HIDDEN -struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data) -{ - struct bt_ctf_field_wrapper *field_wrapper = - g_new0(struct bt_ctf_field_wrapper, 1); - - BT_LOGD_STR("Creating empty field wrapper object."); - - if (!field_wrapper) { - BT_LOGE("Failed to allocate one field wrapper."); - goto end; - } - - bt_ctf_object_init_unique(&field_wrapper->base); - BT_LOGD("Created empty field wrapper object: addr=%p", - field_wrapper); - -end: - return field_wrapper; -} - -BT_HIDDEN -void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field_wrapper) -{ - BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper); - BT_ASSERT(!field_wrapper->field); - BT_LOGD_STR("Putting stream class."); - g_free(field_wrapper); -} - -BT_HIDDEN -struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create( - struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft) -{ - struct bt_ctf_field_wrapper *field_wrapper = NULL; - - BT_ASSERT(pool); - BT_ASSERT(ft); - field_wrapper = bt_ctf_object_pool_create_object(pool); - if (!field_wrapper) { - BT_LIB_LOGE("Cannot allocate one field wrapper from field wrapper pool: " - "%![pool-]+o", pool); - goto error; - } - - BT_ASSERT(field_wrapper->field); - goto end; - -error: - if (field_wrapper) { - bt_ctf_field_wrapper_destroy(field_wrapper); - field_wrapper = NULL; - } - -end: - return field_wrapper; -} diff --git a/lib/ctf-writer/fields.c b/lib/ctf-writer/fields.c deleted file mode 100644 index a0f00a9b..00000000 --- a/lib/ctf-writer/fields.c +++ /dev/null @@ -1,1860 +0,0 @@ -/* - * Copyright 2013, 2014 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-FIELDS" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BT_ASSERT_PRE_CTF_FIELD_IS_INT_OR_ENUM(_field, _name) \ - BT_ASSERT_PRE((_field)->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || \ - (_field)->type->id == BT_CTF_FIELD_TYPE_ID_ENUM, \ - _name " is not an integer or an enumeration field: " \ - "field-addr=%p", (_field)) - -BT_HIDDEN -struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field) -{ - struct bt_ctf_field_common *copy = NULL; - - BT_ASSERT_PRE_NON_NULL(field, "Field"); - BT_ASSERT(field_type_common_has_known_id(field->type)); - BT_ASSERT(field->methods->copy); - copy = field->methods->copy(field); - if (!copy) { - BT_LOGW("Cannot create field: ft-addr=%p", field->type); - goto end; - } - - bt_ctf_field_common_set(copy, field->payload_set); - -end: - return copy; -} - -BT_HIDDEN -int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field, - struct bt_ctf_field_type_common *type, - bool is_shared, bt_ctf_object_release_func release_func, - struct bt_ctf_field_common_methods *methods, - bt_ctf_field_common_create_func field_create_func, - GDestroyNotify field_release_func) -{ - int ret = 0; - struct bt_ctf_field_type_common_structure *structure_type = - BT_CTF_FROM_COMMON(type); - struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); - size_t i; - - BT_LOGD("Initializing common structure field object: ft-addr=%p", type); - bt_ctf_field_common_initialize(field, type, is_shared, - release_func, methods); - structure->fields = g_ptr_array_new_with_free_func(field_release_func); - g_ptr_array_set_size(structure->fields, structure_type->fields->len); - - /* Create all fields contained in the structure field. */ - for (i = 0; i < structure_type->fields->len; i++) { - struct bt_ctf_field_common *field; - struct bt_ctf_field_type_common_structure_field *struct_field = - BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX( - structure_type, i); - field = field_create_func(struct_field->type); - if (!field) { - BT_LOGE("Failed to create structure field's member: name=\"%s\", index=%zu", - g_quark_to_string(struct_field->name), i); - ret = -1; - goto end; - } - - g_ptr_array_index(structure->fields, i) = field; - } - - BT_LOGD("Initialized common structure field object: addr=%p, ft-addr=%p", - field, type); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field, - struct bt_ctf_field_type_common *type, - bool is_shared, bt_ctf_object_release_func release_func, - struct bt_ctf_field_common_methods *methods, - bt_ctf_field_common_create_func field_create_func, - GDestroyNotify field_release_func) -{ - int ret = 0; - struct bt_ctf_field_type_common_variant *variant_type = - BT_CTF_FROM_COMMON(type); - struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); - size_t i; - - BT_LOGD("Initializing common variant field object: ft-addr=%p", type); - bt_ctf_field_common_initialize(field, type, is_shared, - release_func, methods); - ret = bt_ctf_field_type_common_variant_update_choices(type); - if (ret) { - BT_LOGE("Cannot update common variant field type choices: " - "ret=%d", ret); - goto end; - } - - variant->fields = g_ptr_array_new_with_free_func(field_release_func); - g_ptr_array_set_size(variant->fields, variant_type->choices->len); - - /* Create all fields contained in the variant field. */ - for (i = 0; i < variant_type->choices->len; i++) { - struct bt_ctf_field_common *field; - struct bt_ctf_field_type_common_variant_choice *var_choice = - BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX( - variant_type, i); - - field = field_create_func(var_choice->type); - if (!field) { - BT_LOGE("Failed to create variant field's member: name=\"%s\", index=%zu", - g_quark_to_string(var_choice->name), i); - ret = -1; - goto end; - } - - g_ptr_array_index(variant->fields, i) = field; - } - - BT_LOGD("Initialized common variant field object: addr=%p, ft-addr=%p", - field, type); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field, - struct bt_ctf_field_type_common *type, - bool is_shared, bt_ctf_object_release_func release_func, - struct bt_ctf_field_common_methods *methods) -{ - int ret = 0; - struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field); - - BT_LOGD("Initializing common string field object: ft-addr=%p", type); - bt_ctf_field_common_initialize(field, type, is_shared, - release_func, methods); - string->buf = g_array_sized_new(FALSE, FALSE, sizeof(char), 1); - if (!string->buf) { - ret = -1; - goto end; - } - - g_array_index(string->buf, char, 0) = '\0'; - BT_LOGD("Initialized common string field object: addr=%p, ft-addr=%p", - field, type); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field, - struct bt_ctf_field_type_common *type, - bool is_shared, bt_ctf_object_release_func release_func, - struct bt_ctf_field_common_methods *methods, - bt_ctf_field_common_create_func field_create_func, - GDestroyNotify field_destroy_func) -{ - struct bt_ctf_field_type_common_array *array_type = BT_CTF_FROM_COMMON(type); - struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); - unsigned int array_length; - int ret = 0; - uint64_t i; - - BT_LOGD("Initializing common array field object: ft-addr=%p", type); - BT_ASSERT(type); - bt_ctf_field_common_initialize(field, type, is_shared, - release_func, methods); - array_length = array_type->length; - array->elements = g_ptr_array_sized_new(array_length); - if (!array->elements) { - ret = -1; - goto end; - } - - g_ptr_array_set_free_func(array->elements, field_destroy_func); - g_ptr_array_set_size(array->elements, array_length); - - for (i = 0; i < array_length; i++) { - array->elements->pdata[i] = field_create_func( - array_type->element_ft); - if (!array->elements->pdata[i]) { - ret = -1; - goto end; - } - } - - BT_LOGD("Initialized common array field object: addr=%p, ft-addr=%p", - field, type); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field, - struct bt_ctf_field_type_common *type, - bool is_shared, bt_ctf_object_release_func release_func, - struct bt_ctf_field_common_methods *methods, - GDestroyNotify field_destroy_func) -{ - struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - int ret = 0; - - BT_LOGD("Initializing common sequence field object: ft-addr=%p", type); - BT_ASSERT(type); - bt_ctf_field_common_initialize(field, type, is_shared, - release_func, methods); - sequence->elements = g_ptr_array_new(); - if (!sequence->elements) { - ret = -1; - goto end; - } - - g_ptr_array_set_free_func(sequence->elements, field_destroy_func); - BT_LOGD("Initialized common sequence field object: addr=%p, ft-addr=%p", - field, type); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field) -{ - return (field && field->payload_set) ? 0 : -1; -} - -BT_HIDDEN -int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field) -{ - int64_t i; - int ret = 0; - struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - for (i = 0; i < structure->fields->len; i++) { - ret = bt_ctf_field_common_validate_recursive( - (void *) structure->fields->pdata[i]); - - if (ret) { - int this_ret; - const char *name; - - this_ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - field->type, &name, NULL, i); - BT_ASSERT(this_ret == 0); - BT_ASSERT_PRE_MSG("Invalid structure field's field: " - "struct-field-addr=%p, field-name=\"%s\", " - "index=%" PRId64 ", field-addr=%p", - field, name, i, structure->fields->pdata[i]); - goto end; - } - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field) -{ - int ret = 0; - struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - if (!variant->current_field) { - ret = -1; - goto end; - } - - ret = bt_ctf_field_common_validate_recursive(variant->current_field); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field) -{ - int64_t i; - int ret = 0; - struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - for (i = 0; i < array->elements->len; i++) { - ret = bt_ctf_field_common_validate_recursive((void *) array->elements->pdata[i]); - if (ret) { - BT_ASSERT_PRE_MSG("Invalid array field's element field: " - "array-field-addr=%p, " PRId64 ", " - "elem-field-addr=%p", - field, i, array->elements->pdata[i]); - goto end; - } - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field) -{ - size_t i; - int ret = 0; - struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - for (i = 0; i < sequence->elements->len; i++) { - ret = bt_ctf_field_common_validate_recursive( - (void *) sequence->elements->pdata[i]); - if (ret) { - BT_ASSERT_PRE_MSG("Invalid sequence field's element field: " - "seq-field-addr=%p, " PRId64 ", " - "elem-field-addr=%p", - field, i, sequence->elements->pdata[i]); - goto end; - } - } -end: - return ret; -} - -BT_HIDDEN -void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field) -{ - BT_ASSERT(field); - field->payload_set = false; -} - -BT_HIDDEN -void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field) -{ - int64_t i; - struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - for (i = 0; i < structure->fields->len; i++) { - struct bt_ctf_field_common *member = structure->fields->pdata[i]; - - if (!member) { - /* - * Structure members are lazily initialized; - * skip if this member has not been allocated - * yet. - */ - continue; - } - - bt_ctf_field_common_reset_recursive(member); - } -} - -BT_HIDDEN -void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field) -{ - struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - variant->current_field = NULL; -} - -BT_HIDDEN -void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field) -{ - size_t i; - struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - for (i = 0; i < array->elements->len; i++) { - struct bt_ctf_field_common *member = array->elements->pdata[i]; - - if (!member) { - /* - * Array elements are lazily initialized; skip - * if this member has not been allocated yet. - */ - continue; - } - - bt_ctf_field_common_reset_recursive(member); - } -} - -BT_HIDDEN -void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field) -{ - struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - uint64_t i; - - BT_ASSERT(field); - - for (i = 0; i < sequence->elements->len; i++) { - if (sequence->elements->pdata[i]) { - bt_ctf_field_common_reset_recursive( - sequence->elements->pdata[i]); - } - } - - sequence->length = 0; -} - -BT_HIDDEN -void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field, - bool is_frozen) -{ - field->frozen = is_frozen; -} - -BT_HIDDEN -void bt_ctf_field_common_structure_set_is_frozen_recursive( - struct bt_ctf_field_common *field, bool is_frozen) -{ - uint64_t i; - struct bt_ctf_field_common_structure *structure_field = - BT_CTF_FROM_COMMON(field); - - BT_LOGD("Freezing structure field object: addr=%p", field); - - for (i = 0; i < structure_field->fields->len; i++) { - struct bt_ctf_field_common *struct_field = - g_ptr_array_index(structure_field->fields, i); - - BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64, - struct_field, i); - bt_ctf_field_common_set_is_frozen_recursive(struct_field, - is_frozen); - } - - bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); -} - -BT_HIDDEN -void bt_ctf_field_common_variant_set_is_frozen_recursive( - struct bt_ctf_field_common *field, bool is_frozen) -{ - uint64_t i; - struct bt_ctf_field_common_variant *variant_field = BT_CTF_FROM_COMMON(field); - - BT_LOGD("Freezing variant field object: addr=%p", field); - - for (i = 0; i < variant_field->fields->len; i++) { - struct bt_ctf_field_common *var_field = - g_ptr_array_index(variant_field->fields, i); - - BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64, - var_field, i); - bt_ctf_field_common_set_is_frozen_recursive(var_field, is_frozen); - } - - bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); -} - -BT_HIDDEN -void bt_ctf_field_common_array_set_is_frozen_recursive( - struct bt_ctf_field_common *field, bool is_frozen) -{ - int64_t i; - struct bt_ctf_field_common_array *array_field = BT_CTF_FROM_COMMON(field); - - BT_LOGD("Freezing array field object: addr=%p", field); - - for (i = 0; i < array_field->elements->len; i++) { - struct bt_ctf_field_common *elem_field = - g_ptr_array_index(array_field->elements, i); - - BT_LOGD("Freezing array field object's element field: " - "element-field-addr=%p, index=%" PRId64, - elem_field, i); - bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen); - } - - bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); -} - -BT_HIDDEN -void bt_ctf_field_common_sequence_set_is_frozen_recursive( - struct bt_ctf_field_common *field, bool is_frozen) -{ - int64_t i; - struct bt_ctf_field_common_sequence *sequence_field = - BT_CTF_FROM_COMMON(field); - - BT_LOGD("Freezing sequence field object: addr=%p", field); - - for (i = 0; i < sequence_field->length; i++) { - struct bt_ctf_field_common *elem_field = - g_ptr_array_index(sequence_field->elements, i); - - BT_LOGD("Freezing sequence field object's element field: " - "element-field-addr=%p, index=%" PRId64, - elem_field, i); - bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen); - } - - bt_ctf_field_common_generic_set_is_frozen(field, is_frozen); -} - -BT_HIDDEN -void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field, - bool is_frozen) -{ - if (!field) { - goto end; - } - - BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d", - field, is_frozen); - BT_ASSERT(field_type_common_has_known_id(field->type)); - BT_ASSERT(field->methods->set_is_frozen); - field->methods->set_is_frozen(field, is_frozen); - -end: - return; -} - -BT_HIDDEN -bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field) -{ - return field && field->payload_set; -} - -BT_HIDDEN -bt_bool bt_ctf_field_common_structure_is_set_recursive( - struct bt_ctf_field_common *field) -{ - bt_bool is_set = BT_FALSE; - size_t i; - struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - for (i = 0; i < structure->fields->len; i++) { - is_set = bt_ctf_field_common_is_set_recursive( - structure->fields->pdata[i]); - if (!is_set) { - goto end; - } - } - -end: - return is_set; -} - -BT_HIDDEN -bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field) -{ - struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); - bt_bool is_set = BT_FALSE; - - BT_ASSERT(field); - - if (variant->current_field) { - is_set = bt_ctf_field_common_is_set_recursive( - variant->current_field); - } - - return is_set; -} - -BT_HIDDEN -bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field) -{ - size_t i; - bt_bool is_set = BT_FALSE; - struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - for (i = 0; i < array->elements->len; i++) { - is_set = bt_ctf_field_common_is_set_recursive(array->elements->pdata[i]); - if (!is_set) { - goto end; - } - } - -end: - return is_set; -} - -BT_HIDDEN -bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field) -{ - size_t i; - bt_bool is_set = BT_FALSE; - struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - - BT_ASSERT(field); - - if (!sequence->elements) { - goto end; - } - - for (i = 0; i < sequence->elements->len; i++) { - is_set = bt_ctf_field_common_is_set_recursive( - sequence->elements->pdata[i]); - if (!is_set) { - goto end; - } - } - -end: - return is_set; -} - -static struct bt_ctf_field_common_methods bt_ctf_field_integer_methods = { - .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen, - .validate = bt_ctf_field_common_generic_validate, - .copy = NULL, - .is_set = bt_ctf_field_common_generic_is_set, - .reset = bt_ctf_field_common_generic_reset, -}; - -static struct bt_ctf_field_common_methods bt_ctf_field_floating_point_methods = { - .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen, - .validate = bt_ctf_field_common_generic_validate, - .copy = NULL, - .is_set = bt_ctf_field_common_generic_is_set, - .reset = bt_ctf_field_common_generic_reset, -}; - -static -void bt_ctf_field_enumeration_set_is_frozen_recursive( - struct bt_ctf_field_common *field, bool is_frozen); - -static -int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field); - -static -bt_bool bt_ctf_field_enumeration_is_set_recursive( - struct bt_ctf_field_common *field); - -static -void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field); - -static struct bt_ctf_field_common_methods bt_ctf_field_enumeration_methods = { - .set_is_frozen = bt_ctf_field_enumeration_set_is_frozen_recursive, - .validate = bt_ctf_field_enumeration_validate_recursive, - .copy = NULL, - .is_set = bt_ctf_field_enumeration_is_set_recursive, - .reset = bt_ctf_field_enumeration_reset_recursive, -}; - -static struct bt_ctf_field_common_methods bt_ctf_field_string_methods = { - .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen, - .validate = bt_ctf_field_common_generic_validate, - .copy = NULL, - .is_set = bt_ctf_field_common_generic_is_set, - .reset = bt_ctf_field_common_generic_reset, -}; - -static struct bt_ctf_field_common_methods bt_ctf_field_structure_methods = { - .set_is_frozen = bt_ctf_field_common_structure_set_is_frozen_recursive, - .validate = bt_ctf_field_common_structure_validate_recursive, - .copy = NULL, - .is_set = bt_ctf_field_common_structure_is_set_recursive, - .reset = bt_ctf_field_common_structure_reset_recursive, -}; - -static struct bt_ctf_field_common_methods bt_ctf_field_sequence_methods = { - .set_is_frozen = bt_ctf_field_common_sequence_set_is_frozen_recursive, - .validate = bt_ctf_field_common_sequence_validate_recursive, - .copy = NULL, - .is_set = bt_ctf_field_common_sequence_is_set_recursive, - .reset = bt_ctf_field_common_sequence_reset_recursive, -}; - -static struct bt_ctf_field_common_methods bt_ctf_field_array_methods = { - .set_is_frozen = bt_ctf_field_common_array_set_is_frozen_recursive, - .validate = bt_ctf_field_common_array_validate_recursive, - .copy = NULL, - .is_set = bt_ctf_field_common_array_is_set_recursive, - .reset = bt_ctf_field_common_array_reset_recursive, -}; - -static -void bt_ctf_field_variant_set_is_frozen_recursive(struct bt_ctf_field_common *field, - bool is_frozen); - -static -int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field); - -static -bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field); - -static -void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field); - -static struct bt_ctf_field_common_methods bt_ctf_field_variant_methods = { - .set_is_frozen = bt_ctf_field_variant_set_is_frozen_recursive, - .validate = bt_ctf_field_variant_validate_recursive, - .copy = NULL, - .is_set = bt_ctf_field_variant_is_set_recursive, - .reset = bt_ctf_field_variant_reset_recursive, -}; - -static -struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *bt_ctf_field_enumeration_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *bt_ctf_field_floating_point_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *bt_ctf_field_structure_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *); - -static -struct bt_ctf_field *(* const field_create_funcs[])(struct bt_ctf_field_type *) = { - [BT_CTF_FIELD_TYPE_ID_INTEGER] = bt_ctf_field_integer_create, - [BT_CTF_FIELD_TYPE_ID_ENUM] = bt_ctf_field_enumeration_create, - [BT_CTF_FIELD_TYPE_ID_FLOAT] = bt_ctf_field_floating_point_create, - [BT_CTF_FIELD_TYPE_ID_STRUCT] = bt_ctf_field_structure_create, - [BT_CTF_FIELD_TYPE_ID_VARIANT] = bt_ctf_field_variant_create, - [BT_CTF_FIELD_TYPE_ID_ARRAY] = bt_ctf_field_array_create, - [BT_CTF_FIELD_TYPE_ID_SEQUENCE] = bt_ctf_field_sequence_create, - [BT_CTF_FIELD_TYPE_ID_STRING] = bt_ctf_field_string_create, -}; - -typedef int (*bt_ctf_field_serialize_recursive_func)( - struct bt_ctf_field_common *, struct bt_ctfser *, - enum bt_ctf_byte_order); - -static -void bt_ctf_field_integer_destroy(struct bt_ctf_field *field) -{ - BT_LOGD("Destroying CTF writer integer field object: addr=%p", field); - bt_ctf_field_common_integer_finalize((void *) field); - g_free(field); -} - -static -void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field) -{ - BT_LOGD("Destroying CTF writer floating point field object: addr=%p", - field); - bt_ctf_field_common_floating_point_finalize((void *) field); - g_free(field); -} - -static -void bt_ctf_field_enumeration_destroy_recursive(struct bt_ctf_field *field) -{ - struct bt_ctf_field_enumeration *enumeration = BT_CTF_FROM_COMMON(field); - - BT_LOGD("Destroying CTF writer enumeration field object: addr=%p", - field); - BT_LOGD_STR("Putting container field."); - bt_ctf_object_put_ref(enumeration->container); - bt_ctf_field_common_finalize((void *) field); - g_free(field); -} - -static -void bt_ctf_field_structure_destroy_recursive(struct bt_ctf_field *field) -{ - BT_LOGD("Destroying CTF writer structure field object: addr=%p", field); - bt_ctf_field_common_structure_finalize_recursive((void *) field); - g_free(field); -} - -static -void bt_ctf_field_variant_destroy_recursive(struct bt_ctf_field *field) -{ - struct bt_ctf_field_variant *variant = BT_CTF_FROM_COMMON(field); - - BT_LOGD("Destroying CTF writer variant field object: addr=%p", field); - BT_LOGD_STR("Putting tag field."); - bt_ctf_object_put_ref(variant->tag); - bt_ctf_field_common_variant_finalize_recursive((void *) field); - g_free(field); -} - -static -void bt_ctf_field_array_destroy_recursive(struct bt_ctf_field *field) -{ - BT_LOGD("Destroying CTF writer array field object: addr=%p", field); - bt_ctf_field_common_array_finalize_recursive((void *) field); - g_free(field); -} - -static -void bt_ctf_field_sequence_destroy_recursive(struct bt_ctf_field *field) -{ - BT_LOGD("Destroying CTF writer sequence field object: addr=%p", field); - bt_ctf_field_common_sequence_finalize_recursive((void *) field); - g_free(field); -} - -static -void bt_ctf_field_string_destroy(struct bt_ctf_field *field) -{ - BT_LOGD("Destroying CTF writer string field object: addr=%p", field); - bt_ctf_field_common_string_finalize((void *) field); - g_free(field); -} - -BT_HIDDEN -int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - struct bt_ctf_field_common *field_common = (void *) field; - bt_ctf_field_serialize_recursive_func serialize_func; - - BT_ASSERT(ctfser); - BT_ASSERT_PRE_NON_NULL(field, "Field"); - BT_ASSERT(field_common->spec.writer.serialize_func); - serialize_func = field_common->spec.writer.serialize_func; - return serialize_func(field_common, ctfser, - native_byte_order); -} - -static -int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - int ret; - struct bt_ctf_field_type_common_integer *int_type = - BT_CTF_FROM_COMMON(field->type); - struct bt_ctf_field_common_integer *int_field = - BT_CTF_FROM_COMMON(field); - enum bt_ctf_byte_order byte_order; - - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field"); - BT_LOGV("Serializing CTF writer integer field: addr=%p, native-bo=%s", - field, - bt_ctf_byte_order_string(native_byte_order)); - byte_order = int_type->user_byte_order; - if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { - byte_order = native_byte_order; - } - - if (int_type->is_signed) { - ret = bt_ctfser_write_signed_int(ctfser, - int_field->payload.signd, int_type->common.alignment, - int_type->size, - byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? - LITTLE_ENDIAN : BIG_ENDIAN); - } else { - ret = bt_ctfser_write_unsigned_int(ctfser, - int_field->payload.unsignd, int_type->common.alignment, - int_type->size, - byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? - LITTLE_ENDIAN : BIG_ENDIAN); - } - - if (unlikely(ret)) { - BT_LOGE("Cannot serialize integer field: ret=%d", ret); - goto end; - } - -end: - return ret; -} - -static -int bt_ctf_field_enumeration_serialize_recursive( - struct bt_ctf_field_common *field, struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - struct bt_ctf_field_enumeration *enumeration = (void *) field; - - BT_LOGV("Serializing enumeration field: addr=%p, native-bo=%s", - field, bt_ctf_byte_order_string(native_byte_order)); - BT_LOGV_STR("Serializing enumeration field's payload field."); - return bt_ctf_field_serialize_recursive( - (void *) enumeration->container, ctfser, native_byte_order); -} - -static -int bt_ctf_field_floating_point_serialize(struct bt_ctf_field_common *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - int ret = -1; - struct bt_ctf_field_type_common_floating_point *flt_type = - BT_CTF_FROM_COMMON(field->type); - struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field); - enum bt_ctf_byte_order byte_order; - - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field"); - BT_LOGV("Serializing floating point number field: " - "addr=%p, native-bo=%s", field, - bt_ctf_byte_order_string(native_byte_order)); - - byte_order = flt_type->user_byte_order; - if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { - byte_order = native_byte_order; - } - - if (flt_type->mant_dig == FLT_MANT_DIG) { - ret = bt_ctfser_write_float32(ctfser, flt_field->payload, - flt_type->common.alignment, - byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? - LITTLE_ENDIAN : BIG_ENDIAN); - } else if (flt_type->mant_dig == DBL_MANT_DIG) { - ret = bt_ctfser_write_float64(ctfser, flt_field->payload, - flt_type->common.alignment, - byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ? - LITTLE_ENDIAN : BIG_ENDIAN); - } else { - abort(); - } - - if (unlikely(ret)) { - BT_LOGE("Cannot serialize floating point number field: " - "ret=%d", ret); - goto end; - } - -end: - return ret; -} - -static -int bt_ctf_field_structure_serialize_recursive(struct bt_ctf_field_common *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - int64_t i; - int ret; - struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field); - - BT_LOGV("Serializing structure field: addr=%p, native-bo=%s", - field, bt_ctf_byte_order_string(native_byte_order)); - ret = bt_ctfser_align_offset_in_current_packet(ctfser, - field->type->alignment); - if (unlikely(ret)) { - BT_LOGE("Cannot align offset before serializing structure field: " - "ret=%d", ret); - goto end; - } - - for (i = 0; i < structure->fields->len; i++) { - struct bt_ctf_field_common *member = g_ptr_array_index( - structure->fields, i); - const char *field_name = NULL; - - BT_LOGV("Serializing structure field's field: ser-offset=%" PRIu64 ", " - "field-addr=%p, index=%" PRIu64, - bt_ctfser_get_offset_in_current_packet_bits(ctfser), - member, i); - - if (unlikely(!member)) { - ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - field->type, &field_name, NULL, i); - BT_ASSERT(ret == 0); - BT_LOGW("Cannot serialize structure field's field: field is not set: " - "struct-field-addr=%p, " - "field-name=\"%s\", index=%" PRId64, - field, field_name, i); - ret = -1; - goto end; - } - - ret = bt_ctf_field_serialize_recursive((void *) member, ctfser, - native_byte_order); - if (unlikely(ret)) { - ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - field->type, &field_name, NULL, i); - BT_ASSERT(ret == 0); - BT_LOGW("Cannot serialize structure field's field: " - "struct-field-addr=%p, field-addr=%p, " - "field-name=\"%s\", index=%" PRId64, - field->type, member, field_name, i); - break; - } - } - -end: - return ret; -} - -static -int bt_ctf_field_variant_serialize_recursive(struct bt_ctf_field_common *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field); - - BT_LOGV("Serializing variant field: addr=%p, native-bo=%s", - field, bt_ctf_byte_order_string(native_byte_order)); - BT_LOGV_STR("Serializing variant field's payload field."); - return bt_ctf_field_serialize_recursive( - (void *) variant->current_field, ctfser, native_byte_order); -} - -static -int bt_ctf_field_array_serialize_recursive(struct bt_ctf_field_common *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - int64_t i; - int ret = 0; - struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field); - - BT_LOGV("Serializing array field: addr=%p, native-bo=%s", - field, bt_ctf_byte_order_string(native_byte_order)); - - for (i = 0; i < array->elements->len; i++) { - struct bt_ctf_field_common *elem_field = - g_ptr_array_index(array->elements, i); - - BT_LOGV("Serializing array field's element field: " - "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64, - bt_ctfser_get_offset_in_current_packet_bits(ctfser), - elem_field, i); - ret = bt_ctf_field_serialize_recursive( - (void *) elem_field, ctfser, native_byte_order); - if (unlikely(ret)) { - BT_LOGW("Cannot serialize array field's element field: " - "array-field-addr=%p, field-addr=%p, " - "index=%" PRId64, field, elem_field, i); - goto end; - } - } - -end: - return ret; -} - -static -int bt_ctf_field_sequence_serialize_recursive(struct bt_ctf_field_common *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - int64_t i; - int ret = 0; - struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field); - - BT_LOGV("Serializing sequence field: addr=%p, native-bo=%s", - field, bt_ctf_byte_order_string(native_byte_order)); - - for (i = 0; i < sequence->elements->len; i++) { - struct bt_ctf_field_common *elem_field = - g_ptr_array_index(sequence->elements, i); - - BT_LOGV("Serializing sequence field's element field: " - "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64, - bt_ctfser_get_offset_in_current_packet_bits(ctfser), - elem_field, i); - ret = bt_ctf_field_serialize_recursive( - (void *) elem_field, ctfser, native_byte_order); - if (unlikely(ret)) { - BT_LOGW("Cannot serialize sequence field's element field: " - "sequence-field-addr=%p, field-addr=%p, " - "index=%" PRId64, field, elem_field, i); - goto end; - } - } - -end: - return ret; -} - -static -int bt_ctf_field_string_serialize(struct bt_ctf_field_common *field, - struct bt_ctfser *ctfser, - enum bt_ctf_byte_order native_byte_order) -{ - int ret; - struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field); - - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field"); - BT_LOGV("Serializing string field: addr=%p, native-bo=%s", - field, bt_ctf_byte_order_string((int) native_byte_order)); - ret = bt_ctfser_write_string(ctfser, (const char *) string->buf->data); - if (unlikely(ret)) { - BT_LOGE("Cannot serialize string field: ret=%d", ret); - goto end; - } - -end: - return ret; -} - -struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field *field = NULL; - enum bt_ctf_field_type_id type_id; - - BT_ASSERT_PRE_NON_NULL(type, "Field type"); - BT_ASSERT(field_type_common_has_known_id((void *) type)); - BT_ASSERT_PRE(bt_ctf_field_type_common_validate((void *) type) == 0, - "Field type is invalid: ft-addr=%p", type); - type_id = bt_ctf_field_type_get_type_id(type); - field = field_create_funcs[type_id](type); - if (!field) { - goto end; - } - - bt_ctf_field_type_common_freeze((void *) type); - -end: - return field; -} - -struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field) -{ - return bt_ctf_object_get_ref(bt_ctf_field_common_borrow_type((void *) field)); -} - -enum bt_ctf_field_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field) -{ - struct bt_ctf_field_common *field_common = (void *) field; - - BT_ASSERT_PRE_NON_NULL(field, "Field"); - return (int) field_common->type->id; -} - -int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field, - struct bt_ctf_field *length_field) -{ - int ret; - struct bt_ctf_field_common *common_length_field = (void *) length_field; - uint64_t length; - - BT_ASSERT_PRE_NON_NULL(length_field, "Length field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) length_field, "Length field"); - BT_ASSERT_PRE(common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || - common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM, - "Length field must be an integer or enumeration field: field-addr=%p", - length_field); - - if (common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM) { - struct bt_ctf_field_enumeration *enumeration = (void *) - length_field; - - length_field = (void *) enumeration->container; - } - - ret = bt_ctf_field_integer_unsigned_get_value(length_field, &length); - BT_ASSERT(ret == 0); - return bt_ctf_field_common_sequence_set_length((void *) field, - length, (bt_ctf_field_common_create_func) bt_ctf_field_create); -} - -struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index( - struct bt_ctf_field *field, uint64_t index) -{ - return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_index( - (void *) field, index)); -} - -struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name( - struct bt_ctf_field *field, const char *name) -{ - return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_name( - (void *) field, name)); -} - -struct bt_ctf_field *bt_ctf_field_array_get_field( - struct bt_ctf_field *field, uint64_t index) -{ - return bt_ctf_object_get_ref( - bt_ctf_field_common_array_borrow_field((void *) field, index)); -} - -struct bt_ctf_field *bt_ctf_field_sequence_get_field( - struct bt_ctf_field *field, uint64_t index) -{ - return bt_ctf_object_get_ref( - bt_ctf_field_common_sequence_borrow_field((void *) field, index)); -} - -struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field, - struct bt_ctf_field *tag_field) -{ - struct bt_ctf_field_variant *variant_field = (void *) field; - struct bt_ctf_field_enumeration *enum_field = (void *) tag_field; - struct bt_ctf_field_type_common_variant *variant_ft; - struct bt_ctf_field_type_common_enumeration *tag_ft; - struct bt_ctf_field *current_field = NULL; - bt_bool is_signed; - uint64_t tag_uval; - int ret; - - BT_ASSERT_PRE_NON_NULL(field, "Variant field"); - BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) tag_field, "Tag field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID( - (struct bt_ctf_field_common *) tag_field, - BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID( - (struct bt_ctf_field_common *) field, - BT_CTF_FIELD_TYPE_ID_VARIANT, "Field"); - BT_ASSERT_PRE( - bt_ctf_field_common_validate_recursive((void *) tag_field) == 0, - "Tag field is invalid: field-addr=%p", tag_field); - variant_ft = BT_CTF_FROM_COMMON(variant_field->common.common.type); - BT_ASSERT_PRE(bt_ctf_field_type_common_compare( - BT_CTF_TO_COMMON(variant_ft->tag_ft), enum_field->common.type) == 0, - "Unexpected tag field's type: expected-ft-addr=%p, " - "tag-ft-addr=%p", variant_ft->tag_ft, - enum_field->common.type); - tag_ft = BT_CTF_FROM_COMMON(enum_field->common.type); - is_signed = tag_ft->container_ft->is_signed; - - if (is_signed) { - int64_t tag_ival; - - ret = bt_ctf_field_integer_signed_get_value( - (void *) enum_field->container, &tag_ival); - tag_uval = (uint64_t) tag_ival; - } else { - ret = bt_ctf_field_integer_unsigned_get_value( - (void *) enum_field->container, &tag_uval); - } - - BT_ASSERT(ret == 0); - ret = bt_ctf_field_common_variant_set_tag((void *) field, tag_uval, - is_signed); - if (ret) { - goto end; - } - - bt_ctf_object_put_ref(variant_field->tag); - variant_field->tag = bt_ctf_object_get_ref(tag_field); - current_field = bt_ctf_field_variant_get_current_field(field); - BT_ASSERT(current_field); - -end: - return current_field; -} - -struct bt_ctf_field *bt_ctf_field_variant_get_current_field( - struct bt_ctf_field *variant_field) -{ - return bt_ctf_object_get_ref(bt_ctf_field_common_variant_borrow_current_field( - (void *) variant_field)); -} - -BT_HIDDEN -struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container( - struct bt_ctf_field *field) -{ - struct bt_ctf_field_enumeration *enumeration = (void *) field; - - BT_ASSERT_PRE_NON_NULL(field, "Enumeration field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID((struct bt_ctf_field_common *) field, - BT_CTF_FIELD_TYPE_ID_ENUM, "Field"); - BT_ASSERT(enumeration->container); - return (void *) enumeration->container; -} - -struct bt_ctf_field *bt_ctf_field_enumeration_get_container( - struct bt_ctf_field *field) -{ - return bt_ctf_object_get_ref(bt_ctf_field_enumeration_borrow_container(field)); -} - -int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field, - int64_t *value) -{ - struct bt_ctf_field_common_integer *integer = (void *) field; - - BT_ASSERT_PRE_NON_NULL(field, "Integer field"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), - BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); - BT_ASSERT_PRE(bt_ctf_field_type_common_integer_is_signed( - integer->common.type), - "Field's type is unsigned: field-addr=%p", field); - *value = integer->payload.signd; - return 0; -} - -int bt_ctf_field_integer_signed_set_value(struct bt_ctf_field *field, - int64_t value) -{ - int ret = 0; - struct bt_ctf_field_common_integer *integer = (void *) field; - struct bt_ctf_field_type_common_integer *integer_type; - - BT_ASSERT_PRE_NON_NULL(field, "Integer field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), - BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); - integer_type = BT_CTF_FROM_COMMON(integer->common.type); - BT_ASSERT_PRE( - bt_ctf_field_type_common_integer_is_signed(integer->common.type), - "Field's type is unsigned: field-addr=%p", field); - BT_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value), - "Value is out of bounds: value=%" PRId64 ", field-addr=%p", - value, field); - integer->payload.signd = value; - bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true); - return ret; -} - -int bt_ctf_field_integer_unsigned_get_value(struct bt_ctf_field *field, - uint64_t *value) -{ - struct bt_ctf_field_common_integer *integer = (void *) field; - - BT_ASSERT_PRE_NON_NULL(field, "Integer field"); - BT_ASSERT_PRE_NON_NULL(value, "Value"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), - BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); - BT_ASSERT_PRE( - !bt_ctf_field_type_common_integer_is_signed(integer->common.type), - "Field's type is signed: field-addr=%p", field); - *value = integer->payload.unsignd; - return 0; -} - -int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field, - uint64_t value) -{ - struct bt_ctf_field_common_integer *integer = (void *) field; - struct bt_ctf_field_type_common_integer *integer_type; - - BT_ASSERT_PRE_NON_NULL(field, "Integer field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer), - BT_CTF_FIELD_TYPE_ID_INTEGER, "Field"); - integer_type = BT_CTF_FROM_COMMON(integer->common.type); - BT_ASSERT_PRE( - !bt_ctf_field_type_common_integer_is_signed(integer->common.type), - "Field's type is signed: field-addr=%p", field); - BT_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value), - "Value is out of bounds: value=%" PRIu64 ", field-addr=%p", - value, field); - integer->payload.unsignd = value; - bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true); - return 0; -} - -int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field, - double *value) -{ - return bt_ctf_field_common_floating_point_get_value((void *) field, value); -} - -int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field, - double value) -{ - return bt_ctf_field_common_floating_point_set_value((void *) field, value); -} - -const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field) -{ - return bt_ctf_field_common_string_get_value((void *) field); -} - -int bt_ctf_field_string_set_value(struct bt_ctf_field *field, const char *value) -{ - return bt_ctf_field_common_string_set_value((void *) field, value); -} - -int bt_ctf_field_string_append(struct bt_ctf_field *field, const char *value) -{ - return bt_ctf_field_common_string_append((void *) field, value); -} - -int bt_ctf_field_string_append_len(struct bt_ctf_field *field, - const char *value, unsigned int length) -{ - return bt_ctf_field_common_string_append_len((void *) field, value, length); -} - -struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field) -{ - return (void *) bt_ctf_field_common_copy((void *) field); -} - -static -struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_common_integer *integer = - g_new0(struct bt_ctf_field_common_integer, 1); - - BT_LOGD("Creating CTF writer integer field object: ft-addr=%p", type); - - if (integer) { - bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(integer), (void *) type, - true, - (bt_ctf_object_release_func) bt_ctf_field_integer_destroy, - &bt_ctf_field_integer_methods); - integer->common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) bt_ctf_field_integer_serialize; - BT_LOGD("Created CTF writer integer field object: addr=%p, ft-addr=%p", - integer, type); - } else { - BT_LOGE_STR("Failed to allocate one integer field."); - } - - return (void *) integer; -} - -static -struct bt_ctf_field *bt_ctf_field_enumeration_create( - struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) type; - struct bt_ctf_field_enumeration *enumeration = g_new0( - struct bt_ctf_field_enumeration, 1); - - BT_LOGD("Creating CTF writer enumeration field object: ft-addr=%p", type); - - if (!enumeration) { - BT_LOGE_STR("Failed to allocate one enumeration field."); - goto end; - } - - bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(enumeration), - (void *) type, - true, (bt_ctf_object_release_func) - bt_ctf_field_enumeration_destroy_recursive, - &bt_ctf_field_enumeration_methods); - enumeration->container = (void *) bt_ctf_field_create( - BT_CTF_FROM_COMMON(enum_ft->container_ft)); - if (!enumeration->container) { - BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration); - goto end; - } - - enumeration->common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) - bt_ctf_field_enumeration_serialize_recursive; - BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p", - enumeration, type); - -end: - return (void *) enumeration; -} - -static -struct bt_ctf_field *bt_ctf_field_floating_point_create( - struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_common_floating_point *floating_point; - - BT_LOGD("Creating CTF writer floating point number field object: ft-addr=%p", type); - floating_point = g_new0(struct bt_ctf_field_common_floating_point, 1); - - if (floating_point) { - bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(floating_point), - (void *) type, - true, (bt_ctf_object_release_func) - bt_ctf_field_floating_point_destroy, - &bt_ctf_field_floating_point_methods); - floating_point->common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) bt_ctf_field_floating_point_serialize; - BT_LOGD("Created CTF writer floating point number field object: addr=%p, ft-addr=%p", - floating_point, type); - } else { - BT_LOGE_STR("Failed to allocate one floating point number field."); - } - - return (void *) floating_point; -} - -static -struct bt_ctf_field *bt_ctf_field_structure_create( - struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_common_structure *structure = g_new0( - struct bt_ctf_field_common_structure, 1); - int iret; - - BT_LOGD("Creating CTF writer structure field object: ft-addr=%p", type); - - if (!structure) { - BT_LOGE_STR("Failed to allocate one structure field."); - goto end; - } - - iret = bt_ctf_field_common_structure_initialize(BT_CTF_TO_COMMON(structure), - (void *) type, - true, (bt_ctf_object_release_func) - bt_ctf_field_structure_destroy_recursive, - &bt_ctf_field_structure_methods, - (bt_ctf_field_common_create_func) bt_ctf_field_create, - (GDestroyNotify) bt_ctf_object_put_ref); - structure->common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) bt_ctf_field_structure_serialize_recursive; - if (iret) { - BT_CTF_OBJECT_PUT_REF_AND_RESET(structure); - goto end; - } - - BT_LOGD("Created CTF writer structure field object: addr=%p, ft-addr=%p", - structure, type); - -end: - return (void *) structure; -} - -static -struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_type_common_variant *var_ft = (void *) type; - struct bt_ctf_field_variant *variant = g_new0( - struct bt_ctf_field_variant, 1); - - BT_LOGD("Creating CTF writer variant field object: ft-addr=%p", type); - - if (!variant) { - BT_LOGE_STR("Failed to allocate one variant field."); - goto end; - } - - bt_ctf_field_common_variant_initialize(BT_CTF_TO_COMMON(BT_CTF_TO_COMMON(variant)), - (void *) type, - true, (bt_ctf_object_release_func) - bt_ctf_field_variant_destroy_recursive, - &bt_ctf_field_variant_methods, - (bt_ctf_field_common_create_func) bt_ctf_field_create, - (GDestroyNotify) bt_ctf_object_put_ref); - variant->tag = (void *) bt_ctf_field_create( - BT_CTF_FROM_COMMON(var_ft->tag_ft)); - variant->common.common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive; - BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p", - variant, type); - -end: - return (void *) variant; -} - -static -struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_common_array *array = - g_new0(struct bt_ctf_field_common_array, 1); - int ret; - - BT_LOGD("Creating CTF writer array field object: ft-addr=%p", type); - BT_ASSERT(type); - - if (!array) { - BT_LOGE_STR("Failed to allocate one array field."); - goto end; - } - - ret = bt_ctf_field_common_array_initialize(BT_CTF_TO_COMMON(array), - (void *) type, - true, (bt_ctf_object_release_func) - bt_ctf_field_array_destroy_recursive, - &bt_ctf_field_array_methods, - (bt_ctf_field_common_create_func) bt_ctf_field_create, - (GDestroyNotify) bt_ctf_object_put_ref); - array->common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) bt_ctf_field_array_serialize_recursive; - if (ret) { - BT_CTF_OBJECT_PUT_REF_AND_RESET(array); - goto end; - } - - BT_LOGD("Created CTF writer array field object: addr=%p, ft-addr=%p", - array, type); - -end: - return (void *) array; -} - -static -struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_common_sequence *sequence = g_new0( - struct bt_ctf_field_common_sequence, 1); - - BT_LOGD("Creating CTF writer sequence field object: ft-addr=%p", type); - - if (sequence) { - bt_ctf_field_common_sequence_initialize(BT_CTF_TO_COMMON(sequence), - (void *) type, - true, (bt_ctf_object_release_func) - bt_ctf_field_sequence_destroy_recursive, - &bt_ctf_field_sequence_methods, - (GDestroyNotify) bt_ctf_object_put_ref); - sequence->common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) bt_ctf_field_sequence_serialize_recursive; - BT_LOGD("Created CTF writer sequence field object: addr=%p, ft-addr=%p", - sequence, type); - } else { - BT_LOGE_STR("Failed to allocate one sequence field."); - } - - return (void *) sequence; -} - -static -struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type) -{ - struct bt_ctf_field_common_string *string = g_new0( - struct bt_ctf_field_common_string, 1); - - BT_LOGD("Creating CTF writer string field object: ft-addr=%p", type); - - if (string) { - bt_ctf_field_common_string_initialize(BT_CTF_TO_COMMON(string), - (void *) type, - true, (bt_ctf_object_release_func) - bt_ctf_field_string_destroy, - &bt_ctf_field_string_methods); - string->common.spec.writer.serialize_func = - (bt_ctf_field_serialize_recursive_func) bt_ctf_field_string_serialize; - BT_LOGD("Created CTF writer string field object: addr=%p, ft-addr=%p", - string, type); - } else { - BT_LOGE_STR("Failed to allocate one string field."); - } - - return (void *) string; -} - -static -void bt_ctf_field_enumeration_set_is_frozen_recursive( - struct bt_ctf_field_common *field, bool is_frozen) -{ - struct bt_ctf_field_enumeration *enumeration = (void *) field; - - if (enumeration->container) { - bt_ctf_field_common_set_is_frozen_recursive( - (void *) enumeration->container, is_frozen); - } - - bt_ctf_field_common_generic_set_is_frozen((void *) field, is_frozen); -} - -static -int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field) -{ - int ret = -1; - struct bt_ctf_field_enumeration *enumeration = (void *) field; - - if (enumeration->container) { - ret = bt_ctf_field_common_validate_recursive( - (void *) enumeration->container); - } - - return ret; -} - -static -bt_bool bt_ctf_field_enumeration_is_set_recursive(struct bt_ctf_field_common *field) -{ - bt_bool is_set = BT_FALSE; - struct bt_ctf_field_enumeration *enumeration = (void *) field; - - if (enumeration->container) { - is_set = bt_ctf_field_common_is_set_recursive( - (void *) enumeration->container); - } - - return is_set; -} - -static -void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field) -{ - struct bt_ctf_field_enumeration *enumeration = (void *) field; - - if (enumeration->container) { - bt_ctf_field_common_reset_recursive( - (void *) enumeration->container); - } - - bt_ctf_field_common_generic_reset((void *) field); -} - -static -void bt_ctf_field_variant_set_is_frozen_recursive( - struct bt_ctf_field_common *field, bool is_frozen) -{ - struct bt_ctf_field_variant *variant = (void *) field; - - if (variant->tag) { - bt_ctf_field_common_set_is_frozen_recursive( - (void *) variant->tag, is_frozen); - } - - bt_ctf_field_common_variant_set_is_frozen_recursive((void *) field, - is_frozen); -} - -static -int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field) -{ - int ret; - struct bt_ctf_field_variant *variant = (void *) field; - - if (variant->tag) { - ret = bt_ctf_field_common_validate_recursive( - (void *) variant->tag); - if (ret) { - goto end; - } - } - - ret = bt_ctf_field_common_variant_validate_recursive((void *) field); - -end: - return ret; -} - -static -bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field) -{ - bt_bool is_set; - struct bt_ctf_field_variant *variant = (void *) field; - - if (variant->tag) { - is_set = bt_ctf_field_common_is_set_recursive( - (void *) variant->tag); - if (is_set) { - goto end; - } - } - - is_set = bt_ctf_field_common_variant_is_set_recursive((void *) field); - -end: - return is_set; -} - -static -void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field) -{ - struct bt_ctf_field_variant *variant = (void *) field; - - if (variant->tag) { - bt_ctf_field_common_reset_recursive( - (void *) variant->tag); - } - - bt_ctf_field_common_variant_reset_recursive((void *) field); -} - -BT_ASSERT_PRE_FUNC -static inline bool field_to_set_has_expected_type( - struct bt_ctf_field_common *struct_field, - const char *name, struct bt_ctf_field_common *value) -{ - bool ret = true; - struct bt_ctf_field_type_common *expected_field_type = NULL; - - expected_field_type = - bt_ctf_field_type_common_structure_borrow_field_type_by_name( - struct_field->type, name); - - if (bt_ctf_field_type_common_compare(expected_field_type, value->type)) { - BT_ASSERT_PRE_MSG("Value field's type is different from the expected field type: " - "value-ft-addr=%p, expected-ft-addr=%p", value->type, - expected_field_type); - ret = false; - goto end; - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field, - const char *name, struct bt_ctf_field *value) -{ - int ret = 0; - GQuark field_quark; - struct bt_ctf_field_common *common_field = (void *) field; - struct bt_ctf_field_common_structure *structure = - BT_CTF_FROM_COMMON(common_field); - struct bt_ctf_field_common *common_value = (void *) value; - size_t index; - GHashTable *field_name_to_index; - struct bt_ctf_field_type_common_structure *structure_ft; - - BT_ASSERT_PRE_NON_NULL(field, "Parent field"); - BT_ASSERT_PRE_NON_NULL(name, "Field name"); - BT_ASSERT_PRE_NON_NULL(value, "Value field"); - BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(common_field, - BT_CTF_FIELD_TYPE_ID_STRUCT, "Parent field"); - BT_ASSERT_PRE(field_to_set_has_expected_type(common_field, - name, common_value), - "Value field's type is different from the expected field type."); - field_quark = g_quark_from_string(name); - structure_ft = BT_CTF_FROM_COMMON(common_field->type); - field_name_to_index = structure_ft->field_name_to_index; - if (!g_hash_table_lookup_extended(field_name_to_index, - GUINT_TO_POINTER(field_quark), NULL, - (gpointer *) &index)) { - BT_LOGV("Invalid parameter: no such field in structure field's type: " - "struct-field-addr=%p, struct-ft-addr=%p, " - "field-ft-addr=%p, name=\"%s\"", - field, common_field->type, common_value->type, name); - ret = -1; - goto end; - } - bt_ctf_object_get_ref(value); - BT_CTF_OBJECT_MOVE_REF(structure->fields->pdata[index], value); - -end: - return ret; -} diff --git a/lib/ctf-writer/functor.c b/lib/ctf-writer/functor.c deleted file mode 100644 index e8ad20f8..00000000 --- a/lib/ctf-writer/functor.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * functor.c - * - * Babeltrace CTF Writer - * - * Copyright 2013, 2014 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * 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 - -BT_HIDDEN -void value_exists(gpointer element, gpointer search_query) -{ - if (element == ((struct bt_ctf_search_query *)search_query)->value) { - ((struct bt_ctf_search_query *)search_query)->found = 1; - } -} diff --git a/lib/ctf-writer/object-pool.c b/lib/ctf-writer/object-pool.c deleted file mode 100644 index e62356be..00000000 --- a/lib/ctf-writer/object-pool.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "OBJECT-POOL" -#include - -#include -#include -#include - -int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool, - bt_ctf_object_pool_new_object_func new_object_func, - bt_ctf_object_pool_destroy_object_func destroy_object_func, - void *data) -{ - int ret = 0; - - BT_ASSERT(new_object_func); - BT_ASSERT(destroy_object_func); - BT_LOGD("Initializing object pool: addr=%p, data-addr=%p", - pool, data); - pool->objects = g_ptr_array_new(); - if (!pool->objects) { - BT_LOGE_STR("Failed to allocate a GPtrArray."); - goto error; - } - - pool->funcs.new_object = new_object_func; - pool->funcs.destroy_object = destroy_object_func; - pool->data = data; - pool->size = 0; - BT_LIB_LOGD("Initialized object pool: %!+o", pool); - goto end; - -error: - if (pool) { - bt_ctf_object_pool_finalize(pool); - } - - ret = -1; - -end: - return ret; -} - -void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool) -{ - uint64_t i; - - BT_ASSERT(pool); - BT_LIB_LOGD("Finalizing object pool: %!+o", pool); - - if (pool->objects) { - for (i = 0; i < pool->size; i++) { - void *obj = pool->objects->pdata[i]; - - if (obj) { - pool->funcs.destroy_object(obj, pool->data); - } - } - - g_ptr_array_free(pool->objects, TRUE); - pool->objects = NULL; - } -} diff --git a/lib/ctf-writer/object.c b/lib/ctf-writer/object.c deleted file mode 100644 index b6185121..00000000 --- a/lib/ctf-writer/object.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2015 Jérémie Galarneau - * - * 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 - -void *bt_ctf_object_get_ref(void *obj) -{ - if (unlikely(!obj)) { - goto end; - } - - bt_ctf_object_get_no_null_check(obj); - -end: - return obj; -} - -void bt_ctf_object_put_ref(void *obj) -{ - if (unlikely(!obj)) { - return; - } - - bt_ctf_object_put_no_null_check(obj); -} diff --git a/lib/ctf-writer/resolve.c b/lib/ctf-writer/resolve.c deleted file mode 100644 index bbb81ac6..00000000 --- a/lib/ctf-writer/resolve.c +++ /dev/null @@ -1,1339 +0,0 @@ -/* - * resolve.c - * - * Babeltrace - CTF writer: Type resolving internal - * - * Copyright 2015 Jérémie Galarneau - * Copyright 2016 Philippe Proulx - * - * Authors: Jérémie Galarneau - * Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-RESOLVE" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef GPtrArray type_stack; - -/* - * A stack frame. - * - * `type` contains a compound field type (structure, variant, array, - * or sequence) and `index` indicates the index of the field type in - * the upper frame (-1 for array and sequence field types). - * - * `type` is owned by the stack frame. - */ -struct type_stack_frame { - struct bt_ctf_field_type_common *type; - int index; -}; - -/* - * The current context of the resolving engine. - * - * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2) - * in the following order: - * - * * Packet header - * * Packet context - * * Event header - * * Stream event context - * * Event context - * * Event payload - */ -struct resolve_context { - struct bt_ctf_private_value *environment; - struct bt_ctf_field_type_common *scopes[6]; - - /* Root scope being visited */ - enum bt_ctf_scope root_scope; - type_stack *type_stack; - struct bt_ctf_field_type_common *cur_field_type; -}; - -/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */ -static const char * const absolute_path_prefixes[] = { - [BT_CTF_SCOPE_ENV] = "env.", - [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = "trace.packet.header.", - [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = "stream.packet.context.", - [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = "stream.event.header.", - [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = "stream.event.context.", - [BT_CTF_SCOPE_EVENT_CONTEXT] = "event.context.", - [BT_CTF_SCOPE_EVENT_FIELDS] = "event.fields.", -}; - -/* Number of path tokens used for the absolute prefixes */ -static const int absolute_path_prefix_ptoken_counts[] = { - [BT_CTF_SCOPE_ENV] = 1, - [BT_CTF_SCOPE_TRACE_PACKET_HEADER] = 3, - [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT] = 3, - [BT_CTF_SCOPE_STREAM_EVENT_HEADER] = 3, - [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT] = 3, - [BT_CTF_SCOPE_EVENT_CONTEXT] = 2, - [BT_CTF_SCOPE_EVENT_FIELDS] = 2, -}; - -/* - * Destroys a type stack frame. - */ -static -void type_stack_destroy_notify(gpointer data) -{ - struct type_stack_frame *frame = data; - - BT_CTF_OBJECT_PUT_REF_AND_RESET(frame->type); - g_free(frame); -} - -/* - * Creates a type stack. - * - * Return value is owned by the caller. - */ -static -type_stack *type_stack_create(void) -{ - return g_ptr_array_new_with_free_func(type_stack_destroy_notify); -} - -/* - * Destroys a type stack. - */ -static -void type_stack_destroy(type_stack *stack) -{ - g_ptr_array_free(stack, TRUE); -} - -/* - * Pushes a field type onto a type stack. - * - * `type` is owned by the caller (stack frame gets a new reference). - */ -static -int type_stack_push(type_stack *stack, struct bt_ctf_field_type_common *type) -{ - int ret = 0; - struct type_stack_frame *frame = NULL; - - if (!stack || !type) { - BT_LOGW("Invalid parameter: stack or type is NULL."); - ret = -1; - goto end; - } - - frame = g_new0(struct type_stack_frame, 1); - if (!frame) { - BT_LOGE_STR("Failed to allocate one field type stack frame."); - ret = -1; - goto end; - } - - BT_LOGV("Pushing field type on context's stack: " - "ft-addr=%p, stack-size-before=%u", type, stack->len); - frame->type = bt_ctf_object_get_ref(type); - g_ptr_array_add(stack, frame); - -end: - return ret; -} - -/* - * Checks whether or not `stack` is empty. - */ -static -bt_bool type_stack_empty(type_stack *stack) -{ - return stack->len == 0; -} - -/* - * Returns the number of frames in `stack`. - */ -static -size_t type_stack_size(type_stack *stack) -{ - return stack->len; -} - -/* - * Returns the top frame of `stack`. - * - * Return value is owned by `stack`. - */ -static -struct type_stack_frame *type_stack_peek(type_stack *stack) -{ - struct type_stack_frame *entry = NULL; - - if (!stack || type_stack_empty(stack)) { - goto end; - } - - entry = g_ptr_array_index(stack, stack->len - 1); -end: - return entry; -} - -/* - * Returns the frame at index `index` in `stack`. - * - * Return value is owned by `stack`. - */ -static -struct type_stack_frame *type_stack_at(type_stack *stack, - size_t index) -{ - struct type_stack_frame *entry = NULL; - - if (!stack || index >= stack->len) { - goto end; - } - - entry = g_ptr_array_index(stack, index); - -end: - return entry; -} - -/* - * Removes the top frame of `stack`. - */ -static -void type_stack_pop(type_stack *stack) -{ - if (!type_stack_empty(stack)) { - /* - * This will call the frame's destructor and free it, as - * well as put its contained field type. - */ - BT_LOGV("Popping context's stack: stack-size-before=%u", - stack->len); - g_ptr_array_set_size(stack, stack->len - 1); - } -} - -/* - * Returns the scope field type of `scope` in the context `ctx`. - * - * Return value is owned by `ctx` on success. - */ -static -struct bt_ctf_field_type_common *get_type_from_ctx(struct resolve_context *ctx, - enum bt_ctf_scope scope) -{ - BT_ASSERT(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER && - scope <= BT_CTF_SCOPE_EVENT_FIELDS); - - return ctx->scopes[scope - BT_CTF_SCOPE_TRACE_PACKET_HEADER]; -} - -/* - * Returns the CTF scope from a path string. May return - * CTF_NODE_UNKNOWN if the path is found to be relative. - */ -static -enum bt_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr) -{ - enum bt_ctf_scope scope; - enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN; - const size_t prefixes_count = sizeof(absolute_path_prefixes) / - sizeof(*absolute_path_prefixes); - - for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_SCOPE_ENV + - prefixes_count; scope++) { - /* - * Chech if path string starts with a known absolute - * path prefix. - * - * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES. - */ - if (strncmp(pathstr, absolute_path_prefixes[scope], - strlen(absolute_path_prefixes[scope]))) { - /* Prefix does not match: try the next one */ - BT_LOGV("Prefix does not match: trying the next one: " - "path=\"%s\", path-prefix=\"%s\", scope=%s", - pathstr, absolute_path_prefixes[scope], - bt_ctf_scope_string(scope)); - continue; - } - - /* Found it! */ - ret = scope; - BT_LOGV("Found root scope from absolute path: " - "path=\"%s\", scope=%s", pathstr, - bt_ctf_scope_string(scope)); - goto end; - } - -end: - return ret; -} - -/* - * Destroys a path token. - */ -static -void ptokens_destroy_func(gpointer ptoken, gpointer data) -{ - g_string_free(ptoken, TRUE); -} - -/* - * Destroys a path token list. - */ -static -void ptokens_destroy(GList *ptokens) -{ - if (!ptokens) { - return; - } - - g_list_foreach(ptokens, ptokens_destroy_func, NULL); - g_list_free(ptokens); -} - -/* - * Returns the string contained in a path token. - */ -static -const char *ptoken_get_string(GList *ptoken) -{ - GString *tokenstr = (GString *) ptoken->data; - - return tokenstr->str; -} - -/* - * Converts a path string to a path token list, that is, splits the - * individual words of a path string into a list of individual - * strings. - * - * Return value is owned by the caller on success. - */ -static -GList *pathstr_to_ptokens(const char *pathstr) -{ - const char *at = pathstr; - const char *last = at; - GList *ptokens = NULL; - - for (;;) { - if (*at == '.' || *at == '\0') { - GString *tokenstr; - - if (at == last) { - /* Error: empty token */ - BT_LOGW("Empty path token: path=\"%s\", pos=%u", - pathstr, (int) (at - pathstr)); - goto error; - } - - tokenstr = g_string_new(NULL); - g_string_append_len(tokenstr, last, at - last); - ptokens = g_list_append(ptokens, tokenstr); - last = at + 1; - } - - if (*at == '\0') { - break; - } - - at++; - } - - return ptokens; - -error: - ptokens_destroy(ptokens); - return NULL; -} - -/* - * Converts a path token list to a field path object. The path token - * list is relative from `type`. The index of the source looking for - * its target within `type` is indicated by `src_index`. This can be - * `INT_MAX` if the source is contained in `type`. - * - * `ptokens` is owned by the caller. `field_path` is an output parameter - * owned by the caller that must be filled here. `type` is owned by the - * caller. - */ -static -int ptokens_to_field_path(GList *ptokens, struct bt_ctf_field_path *field_path, - struct bt_ctf_field_type_common *type, int src_index) -{ - int ret = 0; - GList *cur_ptoken = ptokens; - bt_bool first_level_done = BT_FALSE; - - /* Get our own reference */ - bt_ctf_object_get_ref(type); - - /* Locate target */ - while (cur_ptoken) { - int child_index; - struct bt_ctf_field_type_common *child_type; - const char *field_name = ptoken_get_string(cur_ptoken); - enum bt_ctf_field_type_id type_id = - bt_ctf_field_type_common_get_type_id(type); - - BT_LOGV("Current path token: token=\"%s\"", field_name); - - /* Find to which index corresponds the current path token */ - if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY || - type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) { - child_index = -1; - } else { - child_index = bt_ctf_field_type_common_get_field_index(type, - field_name); - if (child_index < 0) { - /* - * Error: field name does not exist or - * wrong current type. - */ - BT_LOGW("Cannot get index of field type: " - "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d", - field_name, src_index, child_index, first_level_done); - ret = -1; - goto end; - } else if (child_index > src_index && - !first_level_done) { - BT_LOGW("Child field type is located after source field type: " - "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d", - field_name, src_index, child_index, first_level_done); - ret = -1; - goto end; - } - - /* Next path token */ - cur_ptoken = g_list_next(cur_ptoken); - first_level_done = BT_TRUE; - } - - /* Create new field path entry */ - g_array_append_val(field_path->indexes, child_index); - - /* Get child field type */ - child_type = bt_ctf_field_type_common_borrow_field_at_index(type, - child_index); - if (!child_type) { - BT_LOGW("Cannot get child field type: " - "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d", - field_name, src_index, child_index, first_level_done); - ret = -1; - goto end; - } - - /* Move child type to current type */ - bt_ctf_object_get_ref(child_type); - BT_CTF_OBJECT_MOVE_REF(type, child_type); - } - -end: - bt_ctf_object_put_ref(type); - return ret; -} - -/* - * Converts a known absolute path token list to a field path object - * within the resolving context `ctx`. - * - * `ptokens` is owned by the caller. `field_path` is an output parameter - * owned by the caller that must be filled here. - */ -static -int absolute_ptokens_to_field_path(GList *ptokens, - struct bt_ctf_field_path *field_path, - struct resolve_context *ctx) -{ - int ret = 0; - GList *cur_ptoken; - struct bt_ctf_field_type_common *type; - - /* Skip absolute path tokens */ - cur_ptoken = g_list_nth(ptokens, - absolute_path_prefix_ptoken_counts[field_path->root]); - - /* Start with root type */ - type = get_type_from_ctx(ctx, field_path->root); - if (!type) { - /* Error: root type is not available */ - BT_LOGW("Root field type is not available: " - "root-scope=%s", - bt_ctf_scope_string(field_path->root)); - ret = -1; - goto end; - } - - /* Locate target */ - ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX); - -end: - return ret; -} - -/* - * Converts a known relative path token list to a field path object - * within the resolving context `ctx`. - * - * `ptokens` is owned by the caller. `field_path` is an output parameter - * owned by the caller that must be filled here. - */ -static -int relative_ptokens_to_field_path(GList *ptokens, - struct bt_ctf_field_path *field_path, - struct resolve_context *ctx) -{ - int ret = 0; - int parent_pos_in_stack; - struct bt_ctf_field_path *tail_field_path = bt_ctf_field_path_create(); - - if (!tail_field_path) { - BT_LOGE_STR("Cannot create empty field path."); - ret = -1; - goto end; - } - - parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1; - - while (parent_pos_in_stack >= 0) { - struct bt_ctf_field_type_common *parent_type = - type_stack_at(ctx->type_stack, - parent_pos_in_stack)->type; - int cur_index = type_stack_at(ctx->type_stack, - parent_pos_in_stack)->index; - - BT_LOGV("Locating target field type from current parent field type: " - "parent-pos=%d, parent-ft-addr=%p, cur-index=%d", - parent_pos_in_stack, parent_type, cur_index); - - /* Locate target from current parent type */ - ret = ptokens_to_field_path(ptokens, tail_field_path, - parent_type, cur_index); - if (ret) { - /* Not found... yet */ - BT_LOGV_STR("Not found at this point."); - bt_ctf_field_path_clear(tail_field_path); - } else { - /* Found: stitch tail field path to head field path */ - int i = 0; - int tail_field_path_len = - tail_field_path->indexes->len; - - while (BT_TRUE) { - struct bt_ctf_field_type_common *cur_type = - type_stack_at(ctx->type_stack, i)->type; - int index = type_stack_at( - ctx->type_stack, i)->index; - - if (cur_type == parent_type) { - break; - } - - g_array_append_val(field_path->indexes, - index); - i++; - } - - for (i = 0; i < tail_field_path_len; i++) { - int index = g_array_index( - tail_field_path->indexes, - int, i); - - g_array_append_val(field_path->indexes, - index); - } - break; - } - - parent_pos_in_stack--; - } - - if (parent_pos_in_stack < 0) { - /* Not found: look in previous scopes */ - field_path->root--; - - while (field_path->root >= BT_CTF_SCOPE_TRACE_PACKET_HEADER) { - struct bt_ctf_field_type_common *root_type; - bt_ctf_field_path_clear(field_path); - - BT_LOGV("Looking into potential root scope: scope=%s", - bt_ctf_scope_string(field_path->root)); - root_type = get_type_from_ctx(ctx, field_path->root); - if (!root_type) { - field_path->root--; - continue; - } - - /* Locate target in previous scope */ - ret = ptokens_to_field_path(ptokens, field_path, - root_type, INT_MAX); - if (ret) { - /* Not found yet */ - BT_LOGV_STR("Not found in this scope."); - field_path->root--; - continue; - } - - /* Found */ - BT_LOGV_STR("Found in this scope."); - break; - } - } - -end: - BT_CTF_OBJECT_PUT_REF_AND_RESET(tail_field_path); - return ret; -} - -/* - * Converts a path string to a field path object within the resolving - * context `ctx`. - * - * Return value is owned by the caller on success. - */ -static -struct bt_ctf_field_path *pathstr_to_field_path(const char *pathstr, - struct resolve_context *ctx) -{ - int ret; - enum bt_ctf_scope root_scope; - GList *ptokens = NULL; - struct bt_ctf_field_path *field_path = NULL; - - /* Create field path */ - field_path = bt_ctf_field_path_create(); - if (!field_path) { - BT_LOGE_STR("Cannot create empty field path."); - ret = -1; - goto end; - } - - /* Convert path string to path tokens */ - ptokens = pathstr_to_ptokens(pathstr); - if (!ptokens) { - BT_LOGW("Cannot convert path string to path tokens: " - "path=\"%s\"", pathstr); - ret = -1; - goto end; - } - - /* Absolute or relative path? */ - root_scope = get_root_scope_from_absolute_pathstr(pathstr); - - if (root_scope == BT_CTF_SCOPE_UNKNOWN) { - /* Relative path: start with current root scope */ - field_path->root = ctx->root_scope; - BT_LOGV("Detected relative path: starting with current root scope: " - "scope=%s", bt_ctf_scope_string(field_path->root)); - ret = relative_ptokens_to_field_path(ptokens, field_path, ctx); - if (ret) { - BT_LOGW("Cannot get relative field path of path string: " - "path=\"%s\", start-scope=%s, end-scope=%s", - pathstr, bt_ctf_scope_string(ctx->root_scope), - bt_ctf_scope_string(field_path->root)); - goto end; - } - } else if (root_scope == BT_CTF_SCOPE_ENV) { - BT_LOGW("Sequence field types referring the trace environment are not supported as of this version: " - "path=\"%s\"", pathstr); - ret = -1; - goto end; - } else { - /* Absolute path: use found root scope */ - field_path->root = root_scope; - BT_LOGV("Detected absolute path: using root scope: " - "scope=%s", bt_ctf_scope_string(field_path->root)); - ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx); - if (ret) { - BT_LOGW("Cannot get absolute field path of path string: " - "path=\"%s\", root-scope=%s", - pathstr, bt_ctf_scope_string(root_scope)); - goto end; - } - } - - if (ret == 0) { - GString *field_path_pretty = - bt_ctf_field_path_string(field_path); - const char *field_path_pretty_str = - field_path_pretty ? field_path_pretty->str : NULL; - - BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"", - pathstr, field_path_pretty_str); - - if (field_path_pretty) { - g_string_free(field_path_pretty, TRUE); - } - } - -end: - if (ret) { - BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path); - } - - ptokens_destroy(ptokens); - return field_path; -} - -/* - * Retrieves a field type by following the field path `field_path` in - * the resolving context `ctx`. - * - * Return value is owned by the caller on success. - */ -static -struct bt_ctf_field_type_common *field_path_to_field_type( - struct bt_ctf_field_path *field_path, - struct resolve_context *ctx) -{ - int i; - struct bt_ctf_field_type_common *type; - - /* Start with root type */ - type = get_type_from_ctx(ctx, field_path->root); - bt_ctf_object_get_ref(type); - if (!type) { - /* Error: root type is not available */ - BT_LOGW("Root field type is not available: root-scope=%s", - bt_ctf_scope_string(field_path->root)); - goto error; - } - - /* Locate target */ - for (i = 0; i < field_path->indexes->len; i++) { - struct bt_ctf_field_type_common *child_type; - int child_index = - g_array_index(field_path->indexes, int, i); - - /* Get child field type */ - child_type = bt_ctf_field_type_common_borrow_field_at_index(type, - child_index); - if (!child_type) { - BT_LOGW("Cannot get field type: " - "parent-ft-addr=%p, index=%d", type, i); - goto error; - } - - /* Move child type to current type */ - bt_ctf_object_get_ref(child_type); - BT_CTF_OBJECT_MOVE_REF(type, child_type); - } - - return type; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(type); - return type; -} - -/* - * Returns the equivalent field path object of the context type stack. - * - * Return value is owned by the caller on success. - */ -static -struct bt_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx) -{ - int i; - struct bt_ctf_field_path *field_path; - - /* Create field path */ - field_path = bt_ctf_field_path_create(); - if (!field_path) { - BT_LOGE_STR("Cannot create empty field path."); - goto error; - } - - field_path->root = ctx->root_scope; - - for (i = 0; i < type_stack_size(ctx->type_stack); i++) { - struct type_stack_frame *frame; - - frame = type_stack_at(ctx->type_stack, i); - g_array_append_val(field_path->indexes, frame->index); - } - - return field_path; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path); - return field_path; -} - -/* - * Returns the lowest common ancestor of two field path objects - * having the same root scope. - * - * `field_path1` and `field_path2` are owned by the caller. - */ -static -int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1, - struct bt_ctf_field_path *field_path2) -{ - int lca_index = 0; - int field_path1_len, field_path2_len; - - if (BT_LOG_ON_VERBOSE) { - GString *field_path1_pretty = - bt_ctf_field_path_string(field_path1); - GString *field_path2_pretty = - bt_ctf_field_path_string(field_path2); - const char *field_path1_pretty_str = - field_path1_pretty ? field_path1_pretty->str : NULL; - const char *field_path2_pretty_str = - field_path2_pretty ? field_path2_pretty->str : NULL; - - BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: " - "field-path-1=\"%s\", field-path-2=\"%s\"", - field_path1_pretty_str, field_path2_pretty_str); - - if (field_path1_pretty) { - g_string_free(field_path1_pretty, TRUE); - } - - if (field_path2_pretty) { - g_string_free(field_path2_pretty, TRUE); - } - } - - /* - * Start from both roots and find the first mismatch. - */ - BT_ASSERT(field_path1->root == field_path2->root); - field_path1_len = field_path1->indexes->len; - field_path2_len = field_path2->indexes->len; - - while (BT_TRUE) { - int target_index, ctx_index; - - if (lca_index == field_path2_len || - lca_index == field_path1_len) { - /* - * This means that both field paths never split. - * This is invalid because the target cannot be - * an ancestor of the source. - */ - BT_LOGW("Source field type is an ancestor of target field type or vice versa: " - "lca-index=%d, field-path-1-len=%d, " - "field-path-2-len=%d", - lca_index, field_path1_len, field_path2_len); - lca_index = -1; - break; - } - - target_index = g_array_index(field_path1->indexes, int, - lca_index); - ctx_index = g_array_index(field_path2->indexes, int, - lca_index); - - if (target_index != ctx_index) { - /* LCA index is the previous */ - break; - } - - lca_index++; - } - - BT_LOGV("Found LCA: lca-index=%d", lca_index); - return lca_index; -} - -/* - * Validates a target field path. - * - * `target_field_path` and `target_type` are owned by the caller. - */ -static -int validate_target_field_path(struct bt_ctf_field_path *target_field_path, - struct bt_ctf_field_type_common *target_type, - struct resolve_context *ctx) -{ - int ret = 0; - struct bt_ctf_field_path *ctx_field_path; - int target_field_path_len = target_field_path->indexes->len; - int lca_index; - enum bt_ctf_field_type_id ctx_cur_field_type_id; - enum bt_ctf_field_type_id target_type_id; - - /* Get context field path */ - ctx_field_path = get_ctx_stack_field_path(ctx); - if (!ctx_field_path) { - BT_LOGW_STR("Cannot get field path from context's stack."); - ret = -1; - goto end; - } - - /* - * Make sure the target is not a root. - */ - if (target_field_path_len == 0) { - BT_LOGW_STR("Target field path's length is 0 (targeting the root)."); - ret = -1; - goto end; - } - - /* - * Make sure the root of the target field path is not located - * after the context field path's root. - */ - if (target_field_path->root > ctx_field_path->root) { - BT_LOGW("Target field type is located after source field type: " - "target-root=%s, source-root=%s", - bt_ctf_scope_string(target_field_path->root), - bt_ctf_scope_string(ctx_field_path->root)); - ret = -1; - goto end; - } - - if (target_field_path->root == ctx_field_path->root) { - int target_index, ctx_index; - - /* - * Find the index of the lowest common ancestor of both field - * paths. - */ - lca_index = get_field_paths_lca_index(target_field_path, - ctx_field_path); - if (lca_index < 0) { - BT_LOGW_STR("Cannot get least common ancestor."); - ret = -1; - goto end; - } - - /* - * Make sure the target field path is located before the - * context field path. - */ - target_index = g_array_index(target_field_path->indexes, - int, lca_index); - ctx_index = g_array_index(ctx_field_path->indexes, - int, lca_index); - - if (target_index >= ctx_index) { - BT_LOGW("Target field type's index is greater than or equal to source field type's index in LCA: " - "lca-index=%d, target-index=%d, source-index=%d", - lca_index, target_index, ctx_index); - ret = -1; - goto end; - } - } - - /* - * Make sure the target type has the right type and properties. - */ - ctx_cur_field_type_id = bt_ctf_field_type_common_get_type_id( - ctx->cur_field_type); - target_type_id = bt_ctf_field_type_common_get_type_id(target_type); - - switch (ctx_cur_field_type_id) { - case BT_CTF_FIELD_TYPE_ID_VARIANT: - if (target_type_id != BT_CTF_FIELD_TYPE_ID_ENUM) { - BT_LOGW("Variant field type's tag field type is not an enumeration field type: " - "tag-ft-addr=%p, tag-ft-id=%s", - target_type, - bt_ctf_field_type_id_string(target_type_id)); - ret = -1; - goto end; - } - break; - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - if (target_type_id != BT_CTF_FIELD_TYPE_ID_INTEGER || - bt_ctf_field_type_common_integer_is_signed(target_type)) { - BT_LOGW("Sequence field type's length field type is not an unsigned integer field type: " - "length-ft-addr=%p, length-ft-id=%s", - target_type, - bt_ctf_field_type_id_string(target_type_id)); - ret = -1; - goto end; - } - break; - default: - abort(); - } - -end: - BT_CTF_OBJECT_PUT_REF_AND_RESET(ctx_field_path); - return ret; -} - -/* - * Resolves a variant or sequence field type `type`. - * - * `type` is owned by the caller. - */ -static -int resolve_sequence_or_variant_type(struct bt_ctf_field_type_common *type, - struct resolve_context *ctx) -{ - int ret = 0; - const char *pathstr; - enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type); - struct bt_ctf_field_path *target_field_path = NULL; - struct bt_ctf_field_type_common *target_type = NULL; - GString *target_field_path_pretty = NULL; - const char *target_field_path_pretty_str; - - - /* Get path string */ - switch (type_id) { - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - pathstr = - bt_ctf_field_type_common_sequence_get_length_field_name(type); - break; - case BT_CTF_FIELD_TYPE_ID_VARIANT: - pathstr = - bt_ctf_field_type_common_variant_get_tag_name(type); - break; - default: - abort(); - } - - if (!pathstr) { - BT_LOGW_STR("Cannot get path string."); - ret = -1; - goto end; - } - - /* Get target field path out of path string */ - target_field_path = pathstr_to_field_path(pathstr, ctx); - if (!target_field_path) { - BT_LOGW("Cannot get target field path for path string: " - "path=\"%s\"", pathstr); - ret = -1; - goto end; - } - - target_field_path_pretty = bt_ctf_field_path_string(target_field_path); - target_field_path_pretty_str = - target_field_path_pretty ? target_field_path_pretty->str : NULL; - - /* Get target field type */ - target_type = field_path_to_field_type(target_field_path, ctx); - if (!target_type) { - BT_LOGW("Cannot get target field type for path string: " - "path=\"%s\", target-field-path=\"%s\"", - pathstr, target_field_path_pretty_str); - ret = -1; - goto end; - } - - ret = validate_target_field_path(target_field_path, target_type, ctx); - if (ret) { - BT_LOGW("Invalid target field path for path string: " - "path=\"%s\", target-field-path=\"%s\"", - pathstr, target_field_path_pretty_str); - goto end; - } - - /* Set target field path and target field type */ - switch (type_id) { - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - ret = bt_ctf_field_type_common_sequence_set_length_field_path( - type, target_field_path); - if (ret) { - BT_LOGW("Cannot set sequence field type's length field path: " - "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"", - ret, type, pathstr, - target_field_path_pretty_str); - goto end; - } - break; - case BT_CTF_FIELD_TYPE_ID_VARIANT: - ret = bt_ctf_field_type_common_variant_set_tag_field_path( - type, target_field_path); - if (ret) { - BT_LOGW("Cannot set varaint field type's tag field path: " - "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"", - ret, type, pathstr, - target_field_path_pretty_str); - goto end; - } - - ret = bt_ctf_field_type_common_variant_set_tag_field_type( - type, target_type); - if (ret) { - BT_LOGW("Cannot set varaint field type's tag field type: " - "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"", - ret, type, pathstr, - target_field_path_pretty_str); - goto end; - } - break; - default: - abort(); - } - -end: - if (target_field_path_pretty) { - g_string_free(target_field_path_pretty, TRUE); - } - - BT_CTF_OBJECT_PUT_REF_AND_RESET(target_field_path); - BT_CTF_OBJECT_PUT_REF_AND_RESET(target_type); - return ret; -} - -/* - * Resolves a field type `type`. - * - * `type` is owned by the caller. - */ -static -int resolve_type(struct bt_ctf_field_type_common *type, struct resolve_context *ctx) -{ - int ret = 0; - enum bt_ctf_field_type_id type_id; - - if (!type) { - /* Type is not available; still valid */ - goto end; - } - - type_id = bt_ctf_field_type_common_get_type_id(type); - ctx->cur_field_type = type; - - /* Resolve sequence/variant field type */ - switch (type_id) { - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - case BT_CTF_FIELD_TYPE_ID_VARIANT: - ret = resolve_sequence_or_variant_type(type, ctx); - if (ret) { - BT_LOGW("Cannot resolve sequence field type's length or variant field type's tag: " - "ret=%d, ft-addr=%p", ret, type); - goto end; - } - break; - default: - break; - } - - /* Recurse into compound types */ - switch (type_id) { - case BT_CTF_FIELD_TYPE_ID_STRUCT: - case BT_CTF_FIELD_TYPE_ID_VARIANT: - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - case BT_CTF_FIELD_TYPE_ID_ARRAY: - { - int64_t field_count, f_index; - - ret = type_stack_push(ctx->type_stack, type); - if (ret) { - BT_LOGW("Cannot push field type on context's stack: " - "ft-addr=%p", type); - goto end; - } - - field_count = bt_ctf_field_type_common_get_field_count(type); - if (field_count < 0) { - BT_LOGW("Cannot get field type's field count: " - "ret=%" PRId64 ", ft-addr=%p", - field_count, type); - ret = field_count; - goto end; - } - - for (f_index = 0; f_index < field_count; f_index++) { - struct bt_ctf_field_type_common *child_type = - bt_ctf_field_type_common_borrow_field_at_index(type, - f_index); - - if (!child_type) { - BT_LOGW("Cannot get field type's child field: " - "ft-addr=%p, index=%" PRId64 ", " - "count=%" PRId64, type, f_index, - field_count); - ret = -1; - goto end; - } - - if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY|| - type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) { - type_stack_peek(ctx->type_stack)->index = -1; - } else { - type_stack_peek(ctx->type_stack)->index = - f_index; - } - - BT_LOGV("Resolving field type's child field type: " - "parent-ft-addr=%p, child-ft-addr=%p, " - "index=%" PRId64 ", count=%" PRId64, - type, child_type, f_index, field_count); - ret = resolve_type(child_type, ctx); - if (ret) { - goto end; - } - } - - type_stack_pop(ctx->type_stack); - break; - } - default: - break; - } - -end: - return ret; -} - -/* - * Resolves the root field type corresponding to the scope `root_scope`. - */ -static -int resolve_root_type(enum bt_ctf_scope root_scope, struct resolve_context *ctx) -{ - int ret; - - BT_ASSERT(type_stack_size(ctx->type_stack) == 0); - ctx->root_scope = root_scope; - ret = resolve_type(get_type_from_ctx(ctx, root_scope), ctx); - ctx->root_scope = BT_CTF_SCOPE_UNKNOWN; - - return ret; -} - -BT_HIDDEN -int bt_ctf_resolve_types( - struct bt_ctf_private_value *environment, - struct bt_ctf_field_type_common *packet_header_type, - struct bt_ctf_field_type_common *packet_context_type, - struct bt_ctf_field_type_common *event_header_type, - struct bt_ctf_field_type_common *stream_event_ctx_type, - struct bt_ctf_field_type_common *event_context_type, - struct bt_ctf_field_type_common *event_payload_type, - enum bt_ctf_resolve_flag flags) -{ - int ret = 0; - struct resolve_context ctx = { - .environment = environment, - .scopes = { - packet_header_type, - packet_context_type, - event_header_type, - stream_event_ctx_type, - event_context_type, - event_payload_type, - }, - .root_scope = BT_CTF_SCOPE_UNKNOWN, - }; - - BT_LOGV("Resolving field types: " - "packet-header-ft-addr=%p, " - "packet-context-ft-addr=%p, " - "event-header-ft-addr=%p, " - "stream-event-context-ft-addr=%p, " - "event-context-ft-addr=%p, " - "event-payload-ft-addr=%p", - packet_header_type, packet_context_type, event_header_type, - stream_event_ctx_type, event_context_type, event_payload_type); - - /* Initialize type stack */ - ctx.type_stack = type_stack_create(); - if (!ctx.type_stack) { - BT_LOGE_STR("Cannot create field type stack."); - ret = -1; - goto end; - } - - /* Resolve packet header type */ - if (flags & BT_CTF_RESOLVE_FLAG_PACKET_HEADER) { - ret = resolve_root_type(BT_CTF_SCOPE_TRACE_PACKET_HEADER, &ctx); - if (ret) { - BT_LOGW("Cannot resolve trace packet header field type: " - "ret=%d", ret); - goto end; - } - } - - /* Resolve packet context type */ - if (flags & BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT) { - ret = resolve_root_type(BT_CTF_SCOPE_STREAM_PACKET_CONTEXT, &ctx); - if (ret) { - BT_LOGW("Cannot resolve stream packet context field type: " - "ret=%d", ret); - goto end; - } - } - - /* Resolve event header type */ - if (flags & BT_CTF_RESOLVE_FLAG_EVENT_HEADER) { - ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_HEADER, &ctx); - if (ret) { - BT_LOGW("Cannot resolve stream event header field type: " - "ret=%d", ret); - goto end; - } - } - - /* Resolve stream event context type */ - if (flags & BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) { - ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_CONTEXT, &ctx); - if (ret) { - BT_LOGW("Cannot resolve stream event context field type: " - "ret=%d", ret); - goto end; - } - } - - /* Resolve event context type */ - if (flags & BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT) { - ret = resolve_root_type(BT_CTF_SCOPE_EVENT_CONTEXT, &ctx); - if (ret) { - BT_LOGW("Cannot resolve event context field type: " - "ret=%d", ret); - goto end; - } - } - - /* Resolve event payload type */ - if (flags & BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) { - ret = resolve_root_type(BT_CTF_SCOPE_EVENT_FIELDS, &ctx); - if (ret) { - BT_LOGW("Cannot resolve event payload field type: " - "ret=%d", ret); - goto end; - } - } - - BT_LOGV_STR("Resolved field types."); - -end: - type_stack_destroy(ctx.type_stack); - - return ret; -} diff --git a/lib/ctf-writer/stream-class.c b/lib/ctf-writer/stream-class.c deleted file mode 100644 index bcb79f51..00000000 --- a/lib/ctf-writer/stream-class.c +++ /dev/null @@ -1,1145 +0,0 @@ -/* - * Copyright 2013, 2014 Jérémie Galarneau - * Copyright 2017-2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-STREAM-CLASS" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -BT_HIDDEN -int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class, - const char *name, bt_ctf_object_release_func release_func) -{ - BT_LOGD("Initializing common stream class object: name=\"%s\"", name); - - bt_ctf_object_init_shared_with_parent(&stream_class->base, release_func); - stream_class->name = g_string_new(name); - stream_class->event_classes = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_ctf_object_try_spec_release); - if (!stream_class->event_classes) { - BT_LOGE_STR("Failed to allocate a GPtrArray."); - goto error; - } - - stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash, - g_int64_equal, g_free, NULL); - if (!stream_class->event_classes_ht) { - BT_LOGE_STR("Failed to allocate a GHashTable."); - goto error; - } - - BT_LOGD("Initialized common stream class object: addr=%p, name=\"%s\"", - stream_class, name); - return 0; - -error: - return -1; -} - -BT_HIDDEN -void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class) -{ - BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64, - stream_class, bt_ctf_stream_class_common_get_name(stream_class), - bt_ctf_stream_class_common_get_id(stream_class)); - bt_ctf_object_put_ref(stream_class->clock_class); - - if (stream_class->event_classes_ht) { - g_hash_table_destroy(stream_class->event_classes_ht); - } - if (stream_class->event_classes) { - BT_LOGD_STR("Destroying event classes."); - g_ptr_array_free(stream_class->event_classes, TRUE); - } - - if (stream_class->name) { - g_string_free(stream_class->name, TRUE); - } - - BT_LOGD_STR("Putting event header field type."); - bt_ctf_object_put_ref(stream_class->event_header_field_type); - BT_LOGD_STR("Putting packet context field type."); - bt_ctf_object_put_ref(stream_class->packet_context_field_type); - BT_LOGD_STR("Putting event context field type."); - bt_ctf_object_put_ref(stream_class->event_context_field_type); -} - -static -void event_class_exists(gpointer element, gpointer query) -{ - struct bt_ctf_event_class_common *event_class_a = element; - struct bt_ctf_search_query *search_query = query; - struct bt_ctf_event_class_common *event_class_b = search_query->value; - int64_t id_a, id_b; - - if (search_query->value == element) { - search_query->found = 1; - goto end; - } - - /* - * Two event classes cannot share the same ID in a given - * stream class. - */ - id_a = bt_ctf_event_class_common_get_id(event_class_a); - id_b = bt_ctf_event_class_common_get_id(event_class_b); - - if (id_a < 0 || id_b < 0) { - /* at least one ID is not set: will be automatically set later */ - goto end; - } - - if (id_a == id_b) { - BT_LOGW("Event class with this ID already exists in the stream class: " - "id=%" PRId64 ", name=\"%s\"", - id_a, bt_ctf_event_class_common_get_name(event_class_a)); - search_query->found = 1; - goto end; - } - -end: - return; -} - -BT_HIDDEN -int bt_ctf_stream_class_common_add_event_class( - struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_event_class_common *event_class, - bt_ctf_validation_flag_copy_field_type_func copy_field_type_func) -{ - int ret = 0; - int64_t *event_id = NULL; - struct bt_ctf_trace_common *trace = NULL; - struct bt_ctf_stream_class_common *old_stream_class = NULL; - struct bt_ctf_validation_output validation_output = { 0 }; - struct bt_ctf_field_type_common *packet_header_type = NULL; - struct bt_ctf_field_type_common *packet_context_type = NULL; - struct bt_ctf_field_type_common *event_header_type = NULL; - struct bt_ctf_field_type_common *stream_event_ctx_type = NULL; - struct bt_ctf_field_type_common *event_context_type = NULL; - struct bt_ctf_field_type_common *event_payload_type = NULL; - const enum bt_ctf_validation_flag validation_flags = - BT_CTF_VALIDATION_FLAG_EVENT; - struct bt_ctf_clock_class *expected_clock_class = NULL; - - BT_ASSERT(copy_field_type_func); - - if (!stream_class || !event_class) { - BT_LOGW("Invalid parameter: stream class or event class is NULL: " - "stream-class-addr=%p, event-class-addr=%p", - stream_class, event_class); - ret = -1; - goto end; - } - - BT_LOGD("Adding event class to stream class: " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", event-class-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64, - stream_class, bt_ctf_stream_class_common_get_name(stream_class), - bt_ctf_stream_class_common_get_id(stream_class), - event_class, - bt_ctf_event_class_common_get_name(event_class), - bt_ctf_event_class_common_get_id(event_class)); - trace = bt_ctf_stream_class_common_borrow_trace(stream_class); - - if (stream_class->frozen) { - /* - * We only check that the event class to be added has a - * single class which matches the stream class's - * expected clock class if the stream class is frozen. - * If it's not, then this event class is added "as is" - * and the validation will be performed when calling - * either bt_ctf_trace_add_stream_class() or - * bt_ctf_event_create(). This is because the stream class's - * field types (packet context, event header, event - * context) could change before the next call to one of - * those two functions. - */ - expected_clock_class = bt_ctf_object_get_ref(stream_class->clock_class); - - /* - * At this point, `expected_clock_class` can be NULL, - * and bt_ctf_event_class_validate_single_clock_class() - * below can set it. - */ - ret = bt_ctf_event_class_common_validate_single_clock_class( - event_class, &expected_clock_class); - if (ret) { - BT_LOGW("Event class contains a field type which is not " - "recursively mapped to its stream class's " - "expected clock class: " - "stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", " - "stream-class-name=\"%s\", " - "expected-clock-class-addr=%p, " - "expected-clock-class-name=\"%s\"", - stream_class, - bt_ctf_stream_class_common_get_id(stream_class), - bt_ctf_stream_class_common_get_name(stream_class), - expected_clock_class, - expected_clock_class ? - bt_ctf_clock_class_get_name(expected_clock_class) : - NULL); - goto end; - } - } - - event_id = g_new(int64_t, 1); - if (!event_id) { - BT_LOGE_STR("Failed to allocate one int64_t."); - ret = -1; - goto end; - } - - /* Check for duplicate event classes */ - struct bt_ctf_search_query query = { .value = event_class, .found = 0 }; - g_ptr_array_foreach(stream_class->event_classes, event_class_exists, - &query); - if (query.found) { - BT_LOGW_STR("Another event class part of this stream class has the same ID."); - ret = -1; - goto end; - } - - old_stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class); - if (old_stream_class) { - /* Event class is already associated to a stream class. */ - BT_LOGW("Event class is already part of another stream class: " - "event-class-stream-class-addr=%p, " - "event-class-stream-class-name=\"%s\", " - "event-class-stream-class-id=%" PRId64, - old_stream_class, - bt_ctf_stream_class_common_get_name(old_stream_class), - bt_ctf_stream_class_common_get_id(old_stream_class)); - ret = -1; - goto end; - } - - if (trace) { - /* - * If the stream class is associated with a trace, then - * both those objects are frozen. Also, this event class - * is about to be frozen. - * - * Therefore the event class must be validated here. - * The trace and stream class should be valid at this - * point. - */ - BT_ASSERT(trace->valid); - BT_ASSERT(stream_class->valid); - packet_header_type = - bt_ctf_trace_common_borrow_packet_header_field_type(trace); - packet_context_type = - bt_ctf_stream_class_common_borrow_packet_context_field_type( - stream_class); - event_header_type = - bt_ctf_stream_class_common_borrow_event_header_field_type( - stream_class); - stream_event_ctx_type = - bt_ctf_stream_class_common_borrow_event_context_field_type( - stream_class); - event_context_type = - bt_ctf_event_class_common_borrow_context_field_type( - event_class); - event_payload_type = - bt_ctf_event_class_common_borrow_payload_field_type( - event_class); - ret = bt_ctf_validate_class_types( - trace->environment, packet_header_type, - packet_context_type, event_header_type, - stream_event_ctx_type, event_context_type, - event_payload_type, trace->valid, - stream_class->valid, event_class->valid, - &validation_output, validation_flags, - copy_field_type_func); - - if (ret) { - /* - * This means something went wrong during the - * validation process, not that the objects are - * invalid. - */ - BT_LOGE("Failed to validate event class: ret=%d", ret); - goto end; - } - - if ((validation_output.valid_flags & validation_flags) != - validation_flags) { - /* Invalid event class */ - BT_LOGW("Invalid trace, stream class, or event class: " - "valid-flags=0x%x", - validation_output.valid_flags); - ret = -1; - goto end; - } - } - - /* Only set an event ID if none was explicitly set before */ - *event_id = bt_ctf_event_class_common_get_id(event_class); - if (*event_id < 0) { - BT_LOGV("Event class has no ID: automatically setting it: " - "id=%" PRId64, stream_class->next_event_id); - - if (bt_ctf_event_class_common_set_id(event_class, - stream_class->next_event_id)) { - BT_LOGE("Cannot set event class's ID: id=%" PRId64, - stream_class->next_event_id); - ret = -1; - goto end; - } - stream_class->next_event_id++; - *event_id = stream_class->next_event_id; - } - - bt_ctf_object_set_parent(&event_class->base, &stream_class->base); - - if (trace) { - /* - * At this point we know that the function will be - * successful. Therefore we can replace the event - * class's field types with what's in the validation - * output structure and mark this event class as valid. - */ - bt_ctf_validation_replace_types(NULL, NULL, event_class, - &validation_output, validation_flags); - event_class->valid = 1; - - /* - * Put what was not moved in - * bt_ctf_validation_replace_types(). - */ - bt_ctf_validation_output_put_types(&validation_output); - } - - /* Add to the event classes of the stream class */ - g_ptr_array_add(stream_class->event_classes, event_class); - g_hash_table_insert(stream_class->event_classes_ht, event_id, - event_class); - event_id = NULL; - - /* Freeze the event class */ - bt_ctf_event_class_common_freeze(event_class); - - /* - * It is safe to set the stream class's unique clock class - * now if the stream class is frozen. - */ - if (stream_class->frozen && expected_clock_class) { - BT_ASSERT(!stream_class->clock_class || - stream_class->clock_class == expected_clock_class); - BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class); - } - - BT_LOGD("Added event class to stream class: " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", event-class-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64, - stream_class, bt_ctf_stream_class_common_get_name(stream_class), - bt_ctf_stream_class_common_get_id(stream_class), - event_class, - bt_ctf_event_class_common_get_name(event_class), - bt_ctf_event_class_common_get_id(event_class)); - -end: - bt_ctf_validation_output_put_types(&validation_output); - bt_ctf_object_put_ref(expected_clock_class); - g_free(event_id); - return ret; -} - -static -int64_t get_event_class_count(void *element) -{ - return bt_ctf_stream_class_get_event_class_count( - (struct bt_ctf_stream_class *) element); -} - -static -void *get_event_class(void *element, int i) -{ - return bt_ctf_stream_class_get_event_class_by_index( - (struct bt_ctf_stream_class *) element, i); -} - -static -int visit_event_class(void *object, bt_ctf_visitor visitor,void *data) -{ - struct bt_ctf_visitor_object obj = { - .object = object, - .type = BT_CTF_VISITOR_OBJECT_TYPE_EVENT_CLASS - }; - - return visitor(&obj, data); -} - -BT_HIDDEN -int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class, - bt_ctf_visitor visitor, void *data) -{ - int ret; - struct bt_ctf_visitor_object obj = { - .object = stream_class, - .type = BT_CTF_VISITOR_OBJECT_TYPE_STREAM_CLASS - }; - - if (!stream_class || !visitor) { - BT_LOGW("Invalid parameter: stream class or visitor is NULL: " - "stream-class-addr=%p, visitor=%p", - stream_class, visitor); - ret = -1; - goto end; - } - - ret = bt_ctf_visitor_helper(&obj, get_event_class_count, - get_event_class, - visit_event_class, visitor, data); - BT_LOGV("bt_ctf_visitor_helper() returned: ret=%d", ret); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class, - bt_ctf_visitor visitor, void *data) -{ - return bt_ctf_stream_class_common_visit(BT_CTF_FROM_COMMON(stream_class), - visitor, data); -} - -BT_HIDDEN -void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class) -{ - if (!stream_class || stream_class->frozen) { - return; - } - - BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64, - stream_class, bt_ctf_stream_class_common_get_name(stream_class), - bt_ctf_stream_class_common_get_id(stream_class)); - stream_class->frozen = 1; - bt_ctf_field_type_common_freeze(stream_class->event_header_field_type); - bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type); - bt_ctf_field_type_common_freeze(stream_class->event_context_field_type); - bt_ctf_clock_class_freeze(stream_class->clock_class); -} - -BT_HIDDEN -int bt_ctf_stream_class_common_validate_single_clock_class( - struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_clock_class **expected_clock_class) -{ - int ret; - uint64_t i; - - BT_ASSERT(stream_class); - BT_ASSERT(expected_clock_class); - ret = bt_ctf_field_type_common_validate_single_clock_class( - stream_class->packet_context_field_type, - expected_clock_class); - if (ret) { - BT_LOGW("Stream class's packet context field type " - "is not recursively mapped to the " - "expected clock class: " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "ft-addr=%p", - stream_class, - bt_ctf_stream_class_common_get_name(stream_class), - stream_class->id, - stream_class->packet_context_field_type); - goto end; - } - - ret = bt_ctf_field_type_common_validate_single_clock_class( - stream_class->event_header_field_type, - expected_clock_class); - if (ret) { - BT_LOGW("Stream class's event header field type " - "is not recursively mapped to the " - "expected clock class: " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "ft-addr=%p", - stream_class, - bt_ctf_stream_class_common_get_name(stream_class), - stream_class->id, - stream_class->event_header_field_type); - goto end; - } - - ret = bt_ctf_field_type_common_validate_single_clock_class( - stream_class->event_context_field_type, - expected_clock_class); - if (ret) { - BT_LOGW("Stream class's event context field type " - "is not recursively mapped to the " - "expected clock class: " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", " - "ft-addr=%p", - stream_class, - bt_ctf_stream_class_common_get_name(stream_class), - stream_class->id, - stream_class->event_context_field_type); - goto end; - } - - for (i = 0; i < stream_class->event_classes->len; i++) { - struct bt_ctf_event_class_common *event_class = - g_ptr_array_index(stream_class->event_classes, i); - - BT_ASSERT(event_class); - ret = bt_ctf_event_class_common_validate_single_clock_class( - event_class, expected_clock_class); - if (ret) { - BT_LOGW("Stream class's event class contains a " - "field type which is not recursively mapped to " - "the expected clock class: " - "stream-class-addr=%p, " - "stream-class-name=\"%s\", " - "stream-class-id=%" PRId64, - stream_class, - bt_ctf_stream_class_common_get_name(stream_class), - stream_class->id); - goto end; - } - } - -end: - return ret; -} - -static -int init_event_header(struct bt_ctf_stream_class *stream_class) -{ - int ret = 0; - struct bt_ctf_field_type *event_header_type = - bt_ctf_field_type_structure_create(); - struct bt_ctf_field_type *_uint32_t = - get_field_type(FIELD_TYPE_ALIAS_UINT32_T); - struct bt_ctf_field_type *_uint64_t = - get_field_type(FIELD_TYPE_ALIAS_UINT64_T); - - if (!event_header_type) { - BT_LOGE_STR("Cannot create empty structure field type."); - ret = -1; - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(event_header_type, - _uint32_t, "id"); - if (ret) { - BT_LOGE_STR("Cannot add `id` field to event header field type."); - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(event_header_type, - _uint64_t, "timestamp"); - if (ret) { - BT_LOGE_STR("Cannot add `timestamp` field to event header field type."); - goto end; - } - - bt_ctf_object_put_ref(stream_class->common.event_header_field_type); - stream_class->common.event_header_field_type = - (void *) event_header_type; - event_header_type = NULL; - -end: - if (ret) { - bt_ctf_object_put_ref(event_header_type); - } - - bt_ctf_object_put_ref(_uint32_t); - bt_ctf_object_put_ref(_uint64_t); - return ret; -} - -static -int init_packet_context(struct bt_ctf_stream_class *stream_class) -{ - int ret = 0; - struct bt_ctf_field_type *packet_context_type = - bt_ctf_field_type_structure_create(); - struct bt_ctf_field_type *_uint64_t = - get_field_type(FIELD_TYPE_ALIAS_UINT64_T); - struct bt_ctf_field_type *ts_begin_end_uint64_t; - - if (!packet_context_type) { - BT_LOGE_STR("Cannot create empty structure field type."); - ret = -1; - goto end; - } - - ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t); - if (!ts_begin_end_uint64_t) { - BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields."); - ret = -1; - goto end; - } - - /* - * We create a stream packet context as proposed in the CTF - * specification. - */ - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - ts_begin_end_uint64_t, "timestamp_begin"); - if (ret) { - BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type."); - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - ts_begin_end_uint64_t, "timestamp_end"); - if (ret) { - BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type."); - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "content_size"); - if (ret) { - BT_LOGE_STR("Cannot add `content_size` field to event header field type."); - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "packet_size"); - if (ret) { - BT_LOGE_STR("Cannot add `packet_size` field to event header field type."); - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(packet_context_type, - _uint64_t, "events_discarded"); - if (ret) { - BT_LOGE_STR("Cannot add `events_discarded` field to event header field type."); - goto end; - } - - bt_ctf_object_put_ref(stream_class->common.packet_context_field_type); - stream_class->common.packet_context_field_type = - (void *) packet_context_type; - packet_context_type = NULL; - -end: - if (ret) { - bt_ctf_object_put_ref(packet_context_type); - goto end; - } - - bt_ctf_object_put_ref(_uint64_t); - bt_ctf_object_put_ref(ts_begin_end_uint64_t); - return ret; -} - -static -void bt_ctf_stream_class_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_stream_class *stream_class; - - stream_class = (void *) obj; - BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64, - stream_class, bt_ctf_stream_class_get_name(stream_class), - bt_ctf_stream_class_get_id(stream_class)); - bt_ctf_stream_class_common_finalize(BT_CTF_TO_COMMON(stream_class)); - bt_ctf_object_put_ref(stream_class->clock); - g_free(stream_class); -} - -struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name) -{ - struct bt_ctf_stream_class *stream_class; - int ret; - - BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name); - stream_class = g_new0(struct bt_ctf_stream_class, 1); - if (!stream_class) { - BT_LOGE_STR("Failed to allocate one CTF writer stream class."); - goto error; - } - - ret = bt_ctf_stream_class_common_initialize(BT_CTF_TO_COMMON(stream_class), - name, bt_ctf_stream_class_destroy); - if (ret) { - /* bt_ctf_stream_class_common_initialize() logs errors */ - goto error; - } - - ret = init_event_header(stream_class); - if (ret) { - BT_LOGE_STR("Cannot initialize stream class's event header field type."); - goto error; - } - - ret = init_packet_context(stream_class); - if (ret) { - BT_LOGE_STR("Cannot initialize stream class's packet context field type."); - goto error; - } - - BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"", - stream_class, name); - return stream_class; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_class); - return stream_class; -} - -static -int try_map_clock_class(struct bt_ctf_stream_class *stream_class, - struct bt_ctf_field_type *parent_ft, const char *field_name) -{ - struct bt_ctf_clock_class *mapped_clock_class = NULL; - int ret = 0; - struct bt_ctf_field_type *ft = - bt_ctf_field_type_structure_get_field_type_by_name(parent_ft, - field_name); - - BT_ASSERT(stream_class->clock); - - if (!ft) { - /* Field does not exist: not an error */ - goto end; - } - - BT_ASSERT(((struct bt_ctf_field_type_common *) ft)->id == - BT_CTF_FIELD_TYPE_ID_INTEGER); - mapped_clock_class = - bt_ctf_field_type_integer_get_mapped_clock_class(ft); - if (!mapped_clock_class) { - struct bt_ctf_field_type *ft_copy; - - if (!stream_class->clock) { - BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", ft-addr=%p", - stream_class, - bt_ctf_stream_class_get_name(stream_class), - bt_ctf_stream_class_get_id(stream_class), ft); - ret = -1; - goto end; - } - - ft_copy = bt_ctf_field_type_copy(ft); - if (!ft_copy) { - BT_LOGE("Failed to copy integer field type: ft-addr=%p", - ft); - } - - ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen( - (void *) ft_copy, stream_class->clock->clock_class); - BT_ASSERT(ret == 0); - - ret = bt_ctf_field_type_common_structure_replace_field( - (void *) parent_ft, field_name, (void *) ft_copy); - bt_ctf_object_put_ref(ft_copy); - BT_LOGV("Automatically mapped field type to stream class's clock class: " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", ft-addr=%p, " - "ft-copy-addr=%p", - stream_class, - bt_ctf_stream_class_get_name(stream_class), - bt_ctf_stream_class_get_id(stream_class), ft, ft_copy); - } - -end: - bt_ctf_object_put_ref(ft); - bt_ctf_object_put_ref(mapped_clock_class); - return ret; -} - -BT_HIDDEN -int bt_ctf_stream_class_map_clock_class( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_field_type *packet_context_type, - struct bt_ctf_field_type *event_header_type) -{ - int ret = 0; - - BT_ASSERT(stream_class); - - if (!stream_class->clock) { - /* No clock class to map to */ - goto end; - } - - if (packet_context_type) { - if (try_map_clock_class(stream_class, packet_context_type, - "timestamp_begin")) { - BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class."); - ret = -1; - goto end; - } - - if (try_map_clock_class(stream_class, packet_context_type, - "timestamp_end")) { - BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class."); - ret = -1; - goto end; - } - } - - if (event_header_type) { - if (try_map_clock_class(stream_class, event_header_type, - "timestamp")) { - BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class."); - ret = -1; - goto end; - } - } - -end: - return ret; -} - -struct bt_ctf_clock *bt_ctf_stream_class_get_clock( - struct bt_ctf_stream_class *stream_class) -{ - struct bt_ctf_clock *clock = NULL; - - if (!stream_class) { - BT_LOGW_STR("Invalid parameter: stream class is NULL."); - goto end; - } - - if (!stream_class->clock) { - BT_LOGV("Stream class has no clock: " - "addr=%p, name=\"%s\", id=%" PRId64, - stream_class, - bt_ctf_stream_class_get_name(stream_class), - bt_ctf_stream_class_get_id(stream_class)); - goto end; - } - - clock = bt_ctf_object_get_ref(stream_class->clock); - -end: - return clock; -} - -int bt_ctf_stream_class_set_clock( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_clock *clock) -{ - int ret = 0; - - if (!stream_class || !clock) { - BT_LOGW("Invalid parameter: stream class or clock is NULL: " - "stream-class-addr=%p, clock-addr=%p", - stream_class, clock); - ret = -1; - goto end; - } - - if (stream_class->common.frozen) { - BT_LOGW("Invalid parameter: stream class is frozen: " - "addr=%p, name=\"%s\", id=%" PRId64, - stream_class, - bt_ctf_stream_class_get_name(stream_class), - bt_ctf_stream_class_get_id(stream_class)); - ret = -1; - goto end; - } - - /* Replace the current clock of this stream class. */ - bt_ctf_object_put_ref(stream_class->clock); - stream_class->clock = bt_ctf_object_get_ref(clock); - BT_LOGV("Set stream class's clock: " - "addr=%p, name=\"%s\", id=%" PRId64 ", " - "clock-addr=%p, clock-name=\"%s\"", - stream_class, - bt_ctf_stream_class_get_name(stream_class), - bt_ctf_stream_class_get_id(stream_class), - stream_class->clock, - bt_ctf_clock_get_name(stream_class->clock)); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class, - struct metadata_context *context) -{ - int ret = 0; - size_t i; - struct bt_ctf_trace *trace; - struct bt_ctf_field_type *packet_header_type = NULL; - - BT_LOGD("Serializing stream class's metadata: " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64 ", metadata-context-addr=%p", - stream_class, - bt_ctf_stream_class_get_name(stream_class), - bt_ctf_stream_class_get_id(stream_class), context); - g_string_assign(context->field_name, ""); - context->current_indentation_level = 1; - if (!stream_class->common.id_set) { - BT_LOGW_STR("Stream class's ID is not set."); - ret = -1; - goto end; - } - - g_string_append(context->string, "stream {\n"); - - /* - * The reference to the trace is only borrowed since the - * serialization of the stream class might have been triggered - * by the trace's destruction. In such a case, the trace's - * reference count would, unexepectedly, go through the sequence - * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction - * and serialization. - */ - trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace( - BT_CTF_TO_COMMON(stream_class))); - BT_ASSERT(trace); - packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace); - trace = NULL; - if (packet_header_type) { - struct bt_ctf_field_type *stream_id_type; - - stream_id_type = - bt_ctf_field_type_structure_get_field_type_by_name( - packet_header_type, "stream_id"); - if (stream_id_type) { - /* - * Only set the stream's id if the trace's packet header - * contains a stream_id field. This field is only - * needed if the trace contains only one stream - * class. - */ - g_string_append_printf(context->string, - "\tid = %" PRId64 ";\n", - stream_class->common.id); - } - bt_ctf_object_put_ref(stream_id_type); - } - if (stream_class->common.event_header_field_type) { - BT_LOGD_STR("Serializing stream class's event header field type's metadata."); - g_string_append(context->string, "\tevent.header := "); - ret = bt_ctf_field_type_serialize_recursive( - (void *) stream_class->common.event_header_field_type, - context); - if (ret) { - BT_LOGW("Cannot serialize stream class's event header field type's metadata: " - "ret=%d", ret); - goto end; - } - g_string_append(context->string, ";"); - } - - - if (stream_class->common.packet_context_field_type) { - BT_LOGD_STR("Serializing stream class's packet context field type's metadata."); - g_string_append(context->string, "\n\n\tpacket.context := "); - ret = bt_ctf_field_type_serialize_recursive( - (void *) stream_class->common.packet_context_field_type, - context); - if (ret) { - BT_LOGW("Cannot serialize stream class's packet context field type's metadata: " - "ret=%d", ret); - goto end; - } - g_string_append(context->string, ";"); - } - - if (stream_class->common.event_context_field_type) { - BT_LOGD_STR("Serializing stream class's event context field type's metadata."); - g_string_append(context->string, "\n\n\tevent.context := "); - ret = bt_ctf_field_type_serialize_recursive( - (void *) stream_class->common.event_context_field_type, - context); - if (ret) { - BT_LOGW("Cannot serialize stream class's event context field type's metadata: " - "ret=%d", ret); - goto end; - } - g_string_append(context->string, ";"); - } - - g_string_append(context->string, "\n};\n\n"); - - for (i = 0; i < stream_class->common.event_classes->len; i++) { - struct bt_ctf_event_class *event_class = - stream_class->common.event_classes->pdata[i]; - - ret = bt_ctf_event_class_serialize(event_class, context); - if (ret) { - BT_LOGW("Cannot serialize event class's metadata: " - "event-class-addr=%p, event-class-name=\"%s\", " - "event-class-id=%" PRId64, - event_class, - bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class)); - goto end; - } - } - -end: - bt_ctf_object_put_ref(packet_header_type); - context->current_indentation_level = 0; - return ret; -} - -struct bt_ctf_trace *bt_ctf_stream_class_get_trace( - struct bt_ctf_stream_class *stream_class) -{ - return bt_ctf_object_get_ref(bt_ctf_stream_class_common_borrow_trace( - BT_CTF_TO_COMMON(stream_class))); -} - -const char *bt_ctf_stream_class_get_name( - struct bt_ctf_stream_class *stream_class) -{ - return bt_ctf_stream_class_common_get_name(BT_CTF_TO_COMMON(stream_class)); -} - -int bt_ctf_stream_class_set_name( - struct bt_ctf_stream_class *stream_class, const char *name) -{ - return bt_ctf_stream_class_common_set_name(BT_CTF_TO_COMMON(stream_class), - name); -} - -int64_t bt_ctf_stream_class_get_id( - struct bt_ctf_stream_class *stream_class) -{ - return bt_ctf_stream_class_common_get_id(BT_CTF_TO_COMMON(stream_class)); -} - -int bt_ctf_stream_class_set_id( - struct bt_ctf_stream_class *stream_class, uint64_t id) -{ - return bt_ctf_stream_class_common_set_id(BT_CTF_TO_COMMON(stream_class), id); -} - -struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type( - struct bt_ctf_stream_class *stream_class) -{ - return bt_ctf_object_get_ref( - bt_ctf_stream_class_common_borrow_packet_context_field_type( - BT_CTF_TO_COMMON(stream_class))); -} - -int bt_ctf_stream_class_set_packet_context_type( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_field_type *packet_context_type) -{ - return bt_ctf_stream_class_common_set_packet_context_field_type( - BT_CTF_TO_COMMON(stream_class), (void *) packet_context_type); -} - -struct bt_ctf_field_type * -bt_ctf_stream_class_get_event_header_type( - struct bt_ctf_stream_class *stream_class) -{ - return bt_ctf_object_get_ref( - bt_ctf_stream_class_common_borrow_event_header_field_type( - BT_CTF_TO_COMMON(stream_class))); -} - -int bt_ctf_stream_class_set_event_header_type( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_field_type *event_header_type) -{ - return bt_ctf_stream_class_common_set_event_header_field_type( - BT_CTF_TO_COMMON(stream_class), (void *) event_header_type); -} - -struct bt_ctf_field_type * -bt_ctf_stream_class_get_event_context_type( - struct bt_ctf_stream_class *stream_class) -{ - return bt_ctf_object_get_ref( - bt_ctf_stream_class_common_borrow_event_context_field_type( - BT_CTF_TO_COMMON(stream_class))); -} - -int bt_ctf_stream_class_set_event_context_type( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_field_type *event_context_type) -{ - return bt_ctf_stream_class_common_set_event_context_field_type( - BT_CTF_TO_COMMON(stream_class), (void *) event_context_type); -} - -int64_t bt_ctf_stream_class_get_event_class_count( - struct bt_ctf_stream_class *stream_class) -{ - return bt_ctf_stream_class_common_get_event_class_count( - BT_CTF_TO_COMMON(stream_class)); -} - -struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index( - struct bt_ctf_stream_class *stream_class, uint64_t index) -{ - return bt_ctf_object_get_ref( - bt_ctf_stream_class_common_borrow_event_class_by_index( - BT_CTF_TO_COMMON(stream_class), index)); -} - -struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id( - struct bt_ctf_stream_class *stream_class, uint64_t id) -{ - return bt_ctf_object_get_ref( - bt_ctf_stream_class_common_borrow_event_class_by_id( - BT_CTF_TO_COMMON(stream_class), id)); -} - -int bt_ctf_stream_class_add_event_class( - struct bt_ctf_stream_class *stream_class, - struct bt_ctf_event_class *event_class) -{ - return bt_ctf_stream_class_common_add_event_class( - BT_CTF_TO_COMMON(stream_class), BT_CTF_TO_COMMON(event_class), - (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy); -} diff --git a/lib/ctf-writer/stream.c b/lib/ctf-writer/stream.c deleted file mode 100644 index 4f0eee03..00000000 --- a/lib/ctf-writer/stream.c +++ /dev/null @@ -1,1953 +0,0 @@ -/* - * Copyright 2013, 2014 Jérémie Galarneau - * Copyright 2017-2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-STREAM" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -BT_HIDDEN -void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream) -{ - BT_LOGD("Finalizing common stream object: addr=%p, name=\"%s\"", - stream, bt_ctf_stream_common_get_name(stream)); - - if (stream->name) { - g_string_free(stream->name, TRUE); - } -} - -BT_HIDDEN -int bt_ctf_stream_common_initialize( - struct bt_ctf_stream_common *stream, - struct bt_ctf_stream_class_common *stream_class, const char *name, - uint64_t id, bt_ctf_object_release_func release_func) -{ - int ret = 0; - struct bt_ctf_trace_common *trace = NULL; - - bt_ctf_object_init_shared_with_parent(&stream->base, release_func); - - if (!stream_class) { - BT_LOGW_STR("Invalid parameter: stream class is NULL."); - goto error; - } - - BT_LOGD("Initializing common stream object: stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-name=\"%s\", " - "stream-id=%" PRIu64, - stream_class, bt_ctf_stream_class_common_get_name(stream_class), - name, id); - trace = bt_ctf_stream_class_common_borrow_trace(stream_class); - if (!trace) { - BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-name=\"%s\"", - stream_class, - bt_ctf_stream_class_common_get_name(stream_class), name); - goto error; - } - - if (id != -1ULL) { - /* - * Validate that the given ID is unique amongst all the - * existing trace's streams created from the same stream - * class. - */ - size_t i; - - for (i = 0; i < trace->streams->len; i++) { - struct bt_ctf_stream_common *trace_stream = - g_ptr_array_index(trace->streams, i); - - if (trace_stream->stream_class != (void *) stream_class) { - continue; - } - - if (trace_stream->id == id) { - BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID."); - goto error; - } - } - } - - /* - * Acquire reference to parent since stream will become publicly - * reachable; it needs its parent to remain valid. - */ - bt_ctf_object_set_parent(&stream->base, &trace->base); - stream->stream_class = stream_class; - stream->id = (int64_t) id; - - if (name) { - stream->name = g_string_new(name); - if (!stream->name) { - BT_LOGE_STR("Failed to allocate a GString."); - goto error; - } - } - - BT_LOGD("Set common stream's trace parent: trace-addr=%p", trace); - - /* Add this stream to the trace's streams */ - BT_LOGD("Created common stream object: addr=%p", stream); - goto end; - -error: - ret = -1; - -end: - return ret; -} - -static -void bt_ctf_stream_destroy(struct bt_ctf_object *obj); - -static -int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t); - -static -int set_integer_field_value(struct bt_ctf_field* field, uint64_t value) -{ - int ret = 0; - struct bt_ctf_field_type *field_type = NULL; - - if (!field) { - BT_LOGW_STR("Invalid parameter: field is NULL."); - ret = -1; - goto end; - } - - field_type = bt_ctf_field_get_type(field); - BT_ASSERT(field_type); - - if (bt_ctf_field_type_get_type_id(field_type) != - BT_CTF_FIELD_TYPE_ID_INTEGER) { - /* Not an integer and the value is unset, error. */ - BT_LOGW("Invalid parameter: field's type is not an integer field type: " - "field-addr=%p, ft-addr=%p, ft-id=%s", - field, field_type, - bt_ctf_field_type_id_string((int) - bt_ctf_field_type_get_type_id(field_type))); - ret = -1; - goto end; - } - - if (bt_ctf_field_type_integer_is_signed(field_type)) { - ret = bt_ctf_field_integer_signed_set_value(field, (int64_t) value); - if (ret) { - /* Value is out of range, error. */ - BT_LOGW("Cannot set signed integer field's value: " - "addr=%p, value=%" PRId64, - field, (int64_t) value); - goto end; - } - } else { - ret = bt_ctf_field_integer_unsigned_set_value(field, value); - if (ret) { - /* Value is out of range, error. */ - BT_LOGW("Cannot set unsigned integer field's value: " - "addr=%p, value=%" PRIu64, - field, value); - goto end; - } - } -end: - bt_ctf_object_put_ref(field_type); - return ret; -} - -static -int set_packet_header_magic(struct bt_ctf_stream *stream) -{ - int ret = 0; - struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field_by_name( - stream->packet_header, "magic"); - const uint32_t magic_value = 0xc1fc1fc1; - - BT_ASSERT(stream); - - if (!magic_field) { - /* No magic field found. Not an error, skip. */ - BT_LOGV("No field named `magic` in packet header: skipping: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - ret = bt_ctf_field_integer_unsigned_set_value(magic_field, - (uint64_t) magic_value); - - if (ret) { - BT_LOGW("Cannot set packet header field's `magic` integer field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - magic_field, (uint64_t) magic_value); - } else { - BT_LOGV("Set packet header field's `magic` field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - magic_field, (uint64_t) magic_value); - } -end: - bt_ctf_object_put_ref(magic_field); - return ret; -} - -static -int set_packet_header_uuid(struct bt_ctf_stream *stream) -{ - int ret = 0; - int64_t i; - struct bt_ctf_trace *trace = NULL; - struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field_by_name( - stream->packet_header, "uuid"); - - BT_ASSERT(stream); - - if (!uuid_field) { - /* No uuid field found. Not an error, skip. */ - BT_LOGV("No field named `uuid` in packet header: skipping: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - trace = (struct bt_ctf_trace *) - bt_ctf_object_get_parent(&stream->common.base); - - for (i = 0; i < 16; i++) { - struct bt_ctf_field *uuid_element = - bt_ctf_field_array_get_field(uuid_field, i); - - ret = bt_ctf_field_integer_unsigned_set_value( - uuid_element, (uint64_t) trace->common.uuid[i]); - bt_ctf_object_put_ref(uuid_element); - if (ret) { - BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, " - "value=%" PRIu64 ", index=%" PRId64, - stream, bt_ctf_stream_get_name(stream), - uuid_element, (uint64_t) trace->common.uuid[i], i); - goto end; - } - } - - BT_LOGV("Set packet header field's `uuid` field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p", - stream, bt_ctf_stream_get_name(stream), uuid_field); - -end: - bt_ctf_object_put_ref(uuid_field); - BT_CTF_OBJECT_PUT_REF_AND_RESET(trace); - return ret; -} -static -int set_packet_header_stream_id(struct bt_ctf_stream *stream) -{ - int ret = 0; - uint32_t stream_id; - struct bt_ctf_field *stream_id_field = - bt_ctf_field_structure_get_field_by_name( - stream->packet_header, "stream_id"); - - if (!stream_id_field) { - /* No stream_id field found. Not an error, skip. */ - BT_LOGV("No field named `stream_id` in packet header: skipping: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - stream_id = stream->common.stream_class->id; - ret = bt_ctf_field_integer_unsigned_set_value(stream_id_field, - (uint64_t) stream_id); - if (ret) { - BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - stream_id_field, (uint64_t) stream_id); - } else { - BT_LOGV("Set packet header field's `stream_id` field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - stream_id_field, (uint64_t) stream_id); - } - -end: - bt_ctf_object_put_ref(stream_id_field); - return ret; -} - -static -int auto_populate_packet_header(struct bt_ctf_stream *stream) -{ - int ret = 0; - - if (!stream->packet_header) { - goto end; - } - - ret = set_packet_header_magic(stream); - if (ret) { - BT_LOGW("Cannot set packet header's magic number field: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - ret = set_packet_header_uuid(stream); - if (ret) { - BT_LOGW("Cannot set packet header's UUID field: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - ret = set_packet_header_stream_id(stream); - if (ret) { - BT_LOGW("Cannot set packet header's stream class ID field: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - BT_LOGV("Automatically populated stream's packet header's known fields: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - -end: - return ret; -} - -static -int set_packet_context_packet_size(struct bt_ctf_stream *stream, - uint64_t packet_size_bits) -{ - int ret = 0; - struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "packet_size"); - - ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits); - if (ret) { - BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - field, packet_size_bits); - } else { - BT_LOGV("Set packet context field's `packet_size` field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - field, packet_size_bits); - } - - bt_ctf_object_put_ref(field); - return ret; -} - -static -int set_packet_context_content_size(struct bt_ctf_stream *stream, - uint64_t content_size_bits) -{ - int ret = 0; - struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "content_size"); - - BT_ASSERT(stream); - - if (!field) { - /* No content size field found. Not an error, skip. */ - BT_LOGV("No field named `content_size` in packet context: skipping: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits); - if (ret) { - BT_LOGW("Cannot set packet context field's `content_size` integer field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - field, content_size_bits); - } else { - BT_LOGV("Set packet context field's `content_size` field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - field, content_size_bits); - } - -end: - bt_ctf_object_put_ref(field); - return ret; -} - -static -int set_packet_context_events_discarded(struct bt_ctf_stream *stream) -{ - int ret = 0; - struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "events_discarded"); - - BT_ASSERT(stream); - - if (!field) { - /* No discarded events count field found. Not an error, skip. */ - BT_LOGV("No field named `events_discarded` in packet context: skipping: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - /* - * If the field is set by the user, make sure that the value is - * greater than or equal to the stream's current count of - * discarded events. We do not allow wrapping here. If it's - * valid, update the stream's current count. - */ - if (bt_ctf_field_is_set_recursive(field)) { - uint64_t user_val; - - ret = bt_ctf_field_integer_unsigned_get_value(field, - &user_val); - if (ret) { - BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p", - stream, bt_ctf_stream_get_name(stream), field); - goto end; - } - - if (user_val < stream->discarded_events) { - BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: " - "value is lesser than the stream's current discarded events count: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, " - "value=%" PRIu64 ", " - "stream-discarded-events-count=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), field, - user_val, stream->discarded_events); - goto end; - } - - stream->discarded_events = user_val; - } else { - ret = bt_ctf_field_integer_unsigned_set_value(field, - stream->discarded_events); - if (ret) { - BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - field, stream->discarded_events); - } else { - BT_LOGV("Set packet context field's `events_discarded` field's value: " - "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - field, stream->discarded_events); - } - } - -end: - bt_ctf_object_put_ref(field); - return ret; -} - -static -void update_clock_value(uint64_t *val, uint64_t new_val, - unsigned int new_val_size) -{ - const uint64_t pow2 = 1ULL << new_val_size; - const uint64_t mask = pow2 - 1; - uint64_t val_masked; - -#ifdef BT_LOG_ENABLED_VERBOSE - uint64_t old_val = *val; -#endif - - if (new_val_size == 64) { - *val = new_val; - goto end; - } - - val_masked = *val & mask; - - if (new_val < val_masked) { - /* Wrapped once */ - new_val |= pow2; - } - - *val &= ~mask; - *val |= new_val; - -end: - BT_LOGV("Updated clock value: old-val=%" PRIu64 ", new-val=%" PRIu64, - old_val, *val); - return; -} - -static -int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val) -{ - int ret = 0; - struct bt_ctf_field_common *field_common = (void *) field; - - if (!field) { - goto end; - } - - switch (bt_ctf_field_get_type_id(field)) { - case BT_CTF_FIELD_TYPE_ID_INTEGER: - { - struct bt_ctf_clock_class *cc = - bt_ctf_field_type_integer_get_mapped_clock_class( - (void *) field_common->type); - int val_size; - uint64_t uval; - - if (!cc) { - goto end; - } - - bt_ctf_object_put_ref(cc); - val_size = bt_ctf_field_type_integer_get_size( - (void *) field_common->type); - BT_ASSERT(val_size >= 1); - - if (bt_ctf_field_type_integer_is_signed( - (void *) field_common->type)) { - int64_t ival; - - ret = bt_ctf_field_integer_signed_get_value(field, &ival); - uval = (uint64_t) ival; - } else { - ret = bt_ctf_field_integer_unsigned_get_value(field, &uval); - } - - if (ret) { - /* Not set */ - goto end; - } - - update_clock_value(val, uval, val_size); - break; - } - case BT_CTF_FIELD_TYPE_ID_ENUM: - { - struct bt_ctf_field *int_field = - bt_ctf_field_enumeration_get_container(field); - - BT_ASSERT(int_field); - ret = visit_field_update_clock_value(int_field, val); - bt_ctf_object_put_ref(int_field); - break; - } - case BT_CTF_FIELD_TYPE_ID_ARRAY: - { - uint64_t i; - int64_t len = bt_ctf_field_type_array_get_length( - (void *) field_common->type); - - BT_ASSERT(len >= 0); - - for (i = 0; i < len; i++) { - struct bt_ctf_field *elem_field = - bt_ctf_field_array_get_field(field, i); - - BT_ASSERT(elem_field); - ret = visit_field_update_clock_value(elem_field, val); - bt_ctf_object_put_ref(elem_field); - if (ret) { - goto end; - } - } - break; - } - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - { - uint64_t i; - int64_t len = bt_ctf_field_common_sequence_get_length( - (void *) field); - - if (len < 0) { - ret = -1; - goto end; - } - - for (i = 0; i < len; i++) { - struct bt_ctf_field *elem_field = - bt_ctf_field_sequence_get_field(field, i); - - BT_ASSERT(elem_field); - ret = visit_field_update_clock_value(elem_field, val); - bt_ctf_object_put_ref(elem_field); - if (ret) { - goto end; - } - } - break; - } - case BT_CTF_FIELD_TYPE_ID_STRUCT: - { - uint64_t i; - int64_t len = bt_ctf_field_type_structure_get_field_count( - (void *) field_common->type); - - BT_ASSERT(len >= 0); - - for (i = 0; i < len; i++) { - struct bt_ctf_field *member_field = - bt_ctf_field_structure_get_field_by_index(field, i); - - BT_ASSERT(member_field); - ret = visit_field_update_clock_value(member_field, val); - bt_ctf_object_put_ref(member_field); - if (ret) { - goto end; - } - } - break; - } - case BT_CTF_FIELD_TYPE_ID_VARIANT: - { - struct bt_ctf_field *cur_field = - bt_ctf_field_variant_get_current_field(field); - - if (!cur_field) { - ret = -1; - goto end; - } - - ret = visit_field_update_clock_value(cur_field, val); - bt_ctf_object_put_ref(cur_field); - break; - } - default: - break; - } - -end: - return ret; -} - -int visit_event_update_clock_value(struct bt_ctf_event *event, uint64_t *val) -{ - int ret = 0; - struct bt_ctf_field *field; - - field = bt_ctf_event_get_header(event); - ret = visit_field_update_clock_value(field, val); - bt_ctf_object_put_ref(field); - if (ret) { - BT_LOGW_STR("Cannot automatically update clock value in " - "event's header."); - goto end; - } - - field = bt_ctf_event_get_stream_event_context(event); - ret = visit_field_update_clock_value(field, val); - bt_ctf_object_put_ref(field); - if (ret) { - BT_LOGW_STR("Cannot automatically update clock value in " - "event's stream event context."); - goto end; - } - - field = bt_ctf_event_get_context(event); - ret = visit_field_update_clock_value(field, val); - bt_ctf_object_put_ref(field); - if (ret) { - BT_LOGW_STR("Cannot automatically update clock value in " - "event's context."); - goto end; - } - - field = bt_ctf_event_get_payload_field(event); - ret = visit_field_update_clock_value(field, val); - bt_ctf_object_put_ref(field); - if (ret) { - BT_LOGW_STR("Cannot automatically update clock value in " - "event's payload."); - goto end; - } - -end: - return ret; -} - -static -int set_packet_context_timestamps(struct bt_ctf_stream *stream) -{ - int ret = 0; - uint64_t val; - uint64_t cur_clock_value; - uint64_t init_clock_value = 0; - struct bt_ctf_field *ts_begin_field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "timestamp_begin"); - struct bt_ctf_field *ts_end_field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "timestamp_end"); - struct bt_ctf_field_common *packet_context = - (void *) stream->packet_context; - uint64_t i; - int64_t len; - - if (ts_begin_field && bt_ctf_field_is_set_recursive(ts_begin_field)) { - /* Use provided `timestamp_begin` value as starting value */ - ret = bt_ctf_field_integer_unsigned_get_value(ts_begin_field, &val); - BT_ASSERT(ret == 0); - init_clock_value = val; - } else if (stream->last_ts_end != -1ULL) { - /* Use last packet's ending timestamp as starting value */ - init_clock_value = stream->last_ts_end; - } - - cur_clock_value = init_clock_value; - - if (stream->last_ts_end != -1ULL && - cur_clock_value < stream->last_ts_end) { - BT_LOGW("Packet's initial timestamp is less than previous " - "packet's final timestamp: " - "stream-addr=%p, stream-name=\"%s\", " - "cur-packet-ts-begin=%" PRIu64 ", " - "prev-packet-ts-end=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - cur_clock_value, stream->last_ts_end); - ret = -1; - goto end; - } - - /* - * Visit all the packet context fields, followed by all the - * fields of all the events, in order, updating our current - * clock value as we visit. - * - * While visiting the packet context fields, do not consider - * `timestamp_begin` and `timestamp_end` because this function's - * purpose is to set them anyway. Also do not consider - * `packet_size`, `content_size`, `events_discarded`, and - * `packet_seq_num` if they are not set because those are - * autopopulating fields. - */ - len = bt_ctf_field_type_structure_get_field_count( - (void *) packet_context->type); - BT_ASSERT(len >= 0); - - for (i = 0; i < len; i++) { - const char *member_name; - struct bt_ctf_field *member_field; - - ret = bt_ctf_field_type_structure_get_field_by_index( - (void *) packet_context->type, &member_name, NULL, i); - BT_ASSERT(ret == 0); - - if (strcmp(member_name, "timestamp_begin") == 0 || - strcmp(member_name, "timestamp_end") == 0) { - continue; - } - - member_field = bt_ctf_field_structure_get_field_by_index( - stream->packet_context, i); - BT_ASSERT(member_field); - - if (strcmp(member_name, "packet_size") == 0 && - !bt_ctf_field_is_set_recursive(member_field)) { - bt_ctf_object_put_ref(member_field); - continue; - } - - if (strcmp(member_name, "content_size") == 0 && - !bt_ctf_field_is_set_recursive(member_field)) { - bt_ctf_object_put_ref(member_field); - continue; - } - - if (strcmp(member_name, "events_discarded") == 0 && - !bt_ctf_field_is_set_recursive(member_field)) { - bt_ctf_object_put_ref(member_field); - continue; - } - - if (strcmp(member_name, "packet_seq_num") == 0 && - !bt_ctf_field_is_set_recursive(member_field)) { - bt_ctf_object_put_ref(member_field); - continue; - } - - ret = visit_field_update_clock_value(member_field, - &cur_clock_value); - bt_ctf_object_put_ref(member_field); - if (ret) { - BT_LOGW("Cannot automatically update clock value " - "in stream's packet context: " - "stream-addr=%p, stream-name=\"%s\", " - "field-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream), - member_name); - goto end; - } - } - - for (i = 0; i < stream->events->len; i++) { - struct bt_ctf_event *event = g_ptr_array_index(stream->events, i); - - BT_ASSERT(event); - ret = visit_event_update_clock_value(event, &cur_clock_value); - if (ret) { - BT_LOGW("Cannot automatically update clock value " - "in stream's packet context: " - "stream-addr=%p, stream-name=\"%s\", " - "index=%" PRIu64 ", event-addr=%p, " - "event-class-id=%" PRId64 ", " - "event-class-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream), - i, event, - bt_ctf_event_class_common_get_id(event->common.class), - bt_ctf_event_class_common_get_name(event->common.class)); - goto end; - } - } - - /* - * Everything is visited, thus the current clock value - * corresponds to the ending timestamp. Validate this value - * against the provided value of `timestamp_end`, if any, - * otherwise set it. - */ - if (ts_end_field && bt_ctf_field_is_set_recursive(ts_end_field)) { - ret = bt_ctf_field_integer_unsigned_get_value(ts_end_field, &val); - BT_ASSERT(ret == 0); - - if (val < cur_clock_value) { - BT_LOGW("Packet's final timestamp is less than " - "computed packet's final timestamp: " - "stream-addr=%p, stream-name=\"%s\", " - "cur-packet-ts-end=%" PRIu64 ", " - "computed-packet-ts-end=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), - val, cur_clock_value); - ret = -1; - goto end; - } - - stream->last_ts_end = val; - } - - if (ts_end_field && !bt_ctf_field_is_set_recursive(ts_end_field)) { - ret = set_integer_field_value(ts_end_field, cur_clock_value); - BT_ASSERT(ret == 0); - stream->last_ts_end = cur_clock_value; - } - - if (!ts_end_field) { - stream->last_ts_end = cur_clock_value; - } - - /* Set `timestamp_begin` field to initial clock value */ - if (ts_begin_field && !bt_ctf_field_is_set_recursive(ts_begin_field)) { - ret = set_integer_field_value(ts_begin_field, init_clock_value); - BT_ASSERT(ret == 0); - } - -end: - bt_ctf_object_put_ref(ts_begin_field); - bt_ctf_object_put_ref(ts_end_field); - return ret; -} - -static -int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts, - uint64_t packet_size_bits, uint64_t content_size_bits) -{ - int ret = 0; - - if (!stream->packet_context) { - goto end; - } - - ret = set_packet_context_packet_size(stream, packet_size_bits); - if (ret) { - BT_LOGW("Cannot set packet context's packet size field: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - ret = set_packet_context_content_size(stream, content_size_bits); - if (ret) { - BT_LOGW("Cannot set packet context's content size field: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - if (set_ts) { - ret = set_packet_context_timestamps(stream); - if (ret) { - BT_LOGW("Cannot set packet context's timestamp fields: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - } - - ret = set_packet_context_events_discarded(stream); - if (ret) { - BT_LOGW("Cannot set packet context's discarded events count field: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - goto end; - } - - BT_LOGV("Automatically populated stream's packet context's known fields: " - "stream-addr=%p, stream-name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - -end: - return ret; -} - -static -void release_event(struct bt_ctf_event *event) -{ - if (bt_ctf_object_get_ref_count(&event->common.base)) { - /* - * The event is being orphaned, but it must guarantee the - * existence of its event class for the duration of its - * lifetime. - */ - bt_ctf_object_get_ref(event->common.class); - BT_CTF_OBJECT_PUT_REF_AND_RESET(event->common.base.parent); - } else { - bt_ctf_object_try_spec_release(&event->common.base); - } -} - -static -int create_stream_file(struct bt_ctf_writer *writer, - struct bt_ctf_stream *stream) -{ - int ret = 0; - GString *filename = g_string_new(NULL); - int64_t stream_class_id; - char *file_path = NULL; - - BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, " - "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"", - writer, stream, bt_ctf_stream_get_name(stream), - stream->common.stream_class, - stream->common.stream_class->name->str); - - if (stream->common.name && stream->common.name->len > 0) { - /* Use stream name's base name as prefix */ - gchar *basename = g_path_get_basename(stream->common.name->str); - - BT_ASSERT(basename); - - if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) { - g_string_assign(filename, "stream"); - } else { - g_string_assign(filename, basename); - } - - g_free(basename); - goto append_ids; - } - - if (stream->common.stream_class->name && - stream->common.stream_class->name->len > 0) { - /* Use stream class name's base name as prefix */ - gchar *basename = - g_path_get_basename( - stream->common.stream_class->name->str); - - BT_ASSERT(basename); - - if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) { - g_string_assign(filename, "stream"); - } else { - g_string_assign(filename, basename); - } - - g_free(basename); - goto append_ids; - } - - /* Default to using `stream-` as prefix */ - g_string_assign(filename, "stream"); - -append_ids: - stream_class_id = bt_ctf_stream_class_common_get_id(stream->common.stream_class); - BT_ASSERT(stream_class_id >= 0); - BT_ASSERT(stream->common.id >= 0); - g_string_append_printf(filename, "-%" PRId64 "-%" PRId64, - stream_class_id, stream->common.id); - - file_path = g_build_filename(writer->path->str, filename->str, NULL); - if (file_path == NULL) { - ret = -1; - goto end; - } - - ret = bt_ctfser_init(&stream->ctfser, file_path); - g_free(file_path); - if (ret) { - /* bt_ctfser_init() logs errors */ - goto end; - } - - BT_LOGD("Created stream file for writing: " - "stream-addr=%p, stream-name=\"%s\", " - "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream), - filename->str); - -end: - g_string_free(filename, TRUE); - return ret; -} - -BT_HIDDEN -struct bt_ctf_stream *bt_ctf_stream_create_with_id( - struct bt_ctf_stream_class *stream_class, - const char *name, uint64_t id) -{ - int ret; - int fd; - struct bt_ctf_stream *stream = NULL; - struct bt_ctf_trace *trace = NULL; - struct bt_ctf_writer *writer = NULL; - - BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-name=\"%s\", " - "stream-id=%" PRIu64, - stream_class, bt_ctf_stream_class_get_name(stream_class), - name, id); - stream = g_new0(struct bt_ctf_stream, 1); - if (!stream) { - BT_LOGE_STR("Failed to allocate one stream."); - goto error; - } - - if (id == -1ULL) { - id = stream_class->next_stream_id; - } - - ret = bt_ctf_stream_common_initialize(BT_CTF_TO_COMMON(stream), - BT_CTF_TO_COMMON(stream_class), name, id, bt_ctf_stream_destroy); - if (ret) { - /* bt_ctf_stream_common_initialize() logs errors */ - goto error; - } - - trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace( - BT_CTF_TO_COMMON(stream_class))); - if (!trace) { - BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-name=\"%s\"", - stream_class, bt_ctf_stream_class_get_name(stream_class), - name); - goto error; - } - - writer = (struct bt_ctf_writer *) - bt_ctf_object_get_parent(&trace->common.base); - stream->last_ts_end = -1ULL; - BT_LOGD("CTF writer stream object belongs writer's trace: " - "writer-addr=%p", writer); - BT_ASSERT(writer); - - if (stream_class->common.packet_context_field_type) { - BT_LOGD("Creating stream's packet context field: " - "ft-addr=%p", - stream_class->common.packet_context_field_type); - stream->packet_context = bt_ctf_field_create( - (void *) stream_class->common.packet_context_field_type); - if (!stream->packet_context) { - BT_LOGW_STR("Cannot create stream's packet context field."); - goto error; - } - - /* Initialize events_discarded */ - ret = try_set_structure_field_integer( - stream->packet_context, "events_discarded", 0); - if (ret < 0) { - BT_LOGW("Cannot set `events_discarded` field in packet context: " - "ret=%d, packet-context-field-addr=%p", - ret, stream->packet_context); - goto error; - } - } - - stream->events = g_ptr_array_new_with_free_func( - (GDestroyNotify) release_event); - if (!stream->events) { - BT_LOGE_STR("Failed to allocate a GPtrArray."); - goto error; - } - - if (trace->common.packet_header_field_type) { - BT_LOGD("Creating stream's packet header field: " - "ft-addr=%p", trace->common.packet_header_field_type); - stream->packet_header = - bt_ctf_field_create( - (void *) trace->common.packet_header_field_type); - if (!stream->packet_header) { - BT_LOGW_STR("Cannot create stream's packet header field."); - goto error; - } - } - - /* - * Attempt to populate the default trace packet header fields - * (magic, uuid and stream_id). This will _not_ fail shall the - * fields not be found or be of an incompatible type; they will - * simply not be populated automatically. The user will have to - * make sure to set the trace packet header fields himself - * before flushing. - */ - ret = auto_populate_packet_header(stream); - if (ret) { - BT_LOGW_STR("Cannot automatically populate the stream's packet header."); - goto error; - } - - /* Create file associated with this stream */ - fd = create_stream_file(writer, stream); - if (fd < 0) { - BT_LOGW_STR("Cannot create stream file."); - goto error; - } - - /* Freeze the writer */ - BT_LOGD_STR("Freezing stream's CTF writer."); - bt_ctf_writer_freeze(writer); - - /* Add this stream to the trace's streams */ - g_ptr_array_add(trace->common.streams, stream); - stream_class->next_stream_id++; - BT_LOGD("Created stream object: addr=%p", stream); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(stream); - -end: - bt_ctf_object_put_ref(writer); - return stream; -} - -struct bt_ctf_stream *bt_ctf_stream_create( - struct bt_ctf_stream_class *stream_class, - const char *name, uint64_t id_param) -{ - return bt_ctf_stream_create_with_id(stream_class, - name, id_param); -} - -int bt_ctf_stream_get_discarded_events_count( - struct bt_ctf_stream *stream, uint64_t *count) -{ - int ret = 0; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - ret = -1; - goto end; - } - - if (!count) { - BT_LOGW_STR("Invalid parameter: count is NULL."); - ret = -1; - goto end; - } - - *count = (uint64_t) stream->discarded_events; - -end: - return ret; -} - -static -int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream, - uint64_t count) -{ - int ret = 0; - struct bt_ctf_field *events_discarded_field = NULL; - - if (!stream->packet_context) { - goto end; - } - - events_discarded_field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "events_discarded"); - if (!events_discarded_field) { - goto end; - } - - ret = bt_ctf_field_integer_unsigned_set_value( - events_discarded_field, count); - if (ret) { - BT_LOGW("Cannot set packet context's `events_discarded` field: " - "field-addr=%p, value=%" PRIu64, - events_discarded_field, count); - goto end; - } - -end: - bt_ctf_object_put_ref(events_discarded_field); - return ret; -} - -void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, - uint64_t event_count) -{ - int ret; - uint64_t new_count; - struct bt_ctf_field *events_discarded_field = NULL; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - goto end; - } - - BT_LOGV("Appending discarded events to stream: " - "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), event_count); - - if (!stream->packet_context) { - BT_LOGW_STR("Invalid parameter: stream has no packet context field."); - goto end; - } - - events_discarded_field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "events_discarded"); - if (!events_discarded_field) { - BT_LOGW_STR("No field named `events_discarded` in stream's packet context."); - goto end; - } - - new_count = stream->discarded_events + event_count; - if (new_count < stream->discarded_events) { - BT_LOGW("New discarded events count is less than the stream's current discarded events count: " - "cur-count=%" PRIu64 ", new-count=%" PRIu64, - stream->discarded_events, new_count); - goto end; - } - - ret = set_packet_context_events_discarded_field(stream, new_count); - if (ret) { - /* set_packet_context_events_discarded_field() logs errors */ - goto end; - } - - stream->discarded_events = new_count; - BT_LOGV("Appended discarded events to stream: " - "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64, - stream, bt_ctf_stream_get_name(stream), event_count); - -end: - bt_ctf_object_put_ref(events_discarded_field); -} - -static int auto_populate_event_header(struct bt_ctf_stream *stream, - struct bt_ctf_event *event) -{ - int ret = 0; - struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL; - struct bt_ctf_clock_class *mapped_clock_class = NULL; - struct bt_ctf_stream_class *stream_class = - BT_CTF_FROM_COMMON(bt_ctf_stream_common_borrow_class( - BT_CTF_TO_COMMON(stream))); - int64_t event_class_id; - - BT_ASSERT(event); - - if (!event->common.header_field) { - goto end; - } - - if (event->common.frozen) { - BT_LOGW_STR("Cannot populate event header field: event is frozen."); - ret = -1; - goto end; - } - - BT_LOGV("Automatically populating event's header field: " - "stream-addr=%p, stream-name=\"%s\", event-addr=%p", - stream, bt_ctf_stream_get_name(stream), event); - - id_field = bt_ctf_field_structure_get_field_by_name( - (void *) event->common.header_field->field, "id"); - event_class_id = bt_ctf_event_class_common_get_id(event->common.class); - BT_ASSERT(event_class_id >= 0); - - if (id_field && bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER) { - ret = set_integer_field_value(id_field, event_class_id); - if (ret) { - BT_LOGW("Cannot set event header's `id` field's value: " - "addr=%p, value=%" PRIu64, id_field, - event_class_id); - goto end; - } - } - - /* - * The conditions to automatically set the timestamp are: - * - * 1. The event header field "timestamp" exists and is an - * integer field. - * 2. This stream's class has a registered clock (set with - * bt_ctf_stream_class_set_clock()). - * 3. The "timestamp" field is not set. - */ - timestamp_field = bt_ctf_field_structure_get_field_by_name( - (void *) event->common.header_field->field, "timestamp"); - if (timestamp_field && stream_class->clock && - bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER && - !bt_ctf_field_is_set_recursive(timestamp_field)) { - mapped_clock_class = - bt_ctf_field_type_integer_get_mapped_clock_class( - (void *) ((struct bt_ctf_field_common *) timestamp_field)->type); - if (mapped_clock_class) { - uint64_t timestamp; - - BT_ASSERT(mapped_clock_class == - stream_class->clock->clock_class); - ret = bt_ctf_clock_get_value( - stream_class->clock, - ×tamp); - BT_ASSERT(ret == 0); - ret = set_integer_field_value(timestamp_field, - timestamp); - if (ret) { - BT_LOGW("Cannot set event header's `timestamp` field's value: " - "addr=%p, value=%" PRIu64, - timestamp_field, timestamp); - goto end; - } - } - } - - BT_LOGV("Automatically populated event's header field: " - "stream-addr=%p, stream-name=\"%s\", event-addr=%p", - stream, bt_ctf_stream_get_name(stream), event); - -end: - bt_ctf_object_put_ref(id_field); - bt_ctf_object_put_ref(timestamp_field); - bt_ctf_object_put_ref(mapped_clock_class); - return ret; -} - -int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, - struct bt_ctf_event *event) -{ - int ret = 0; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - ret = -1; - goto end; - } - - if (!event) { - BT_LOGW_STR("Invalid parameter: event is NULL."); - ret = -1; - goto end; - } - - BT_LOGV("Appending event to stream: " - "stream-addr=%p, stream-name=\"%s\", event-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64, - stream, bt_ctf_stream_get_name(stream), event, - bt_ctf_event_class_common_get_name( - bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))), - bt_ctf_event_class_common_get_id( - bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)))); - - /* - * The event is not supposed to have a parent stream at this - * point. The only other way an event can have a parent stream - * is if it was assigned when setting a packet to the event, - * in which case the packet's stream is not a writer stream, - * and thus the user is trying to append an event which belongs - * to another stream. - */ - if (event->common.base.parent) { - ret = -1; - goto end; - } - - bt_ctf_object_set_parent(&event->common.base, &stream->common.base); - BT_LOGV_STR("Automatically populating the header of the event to append."); - ret = auto_populate_event_header(stream, event); - if (ret) { - /* auto_populate_event_header() reports errors */ - goto error; - } - - /* Make sure the various scopes of the event are set */ - BT_LOGV_STR("Validating event to append."); - BT_ASSERT_PRE(bt_ctf_event_common_validate(BT_CTF_TO_COMMON(event)) == 0, - "Invalid event: event-addr=%p", event); - - /* Save the new event and freeze it */ - BT_LOGV_STR("Freezing the event to append."); - bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true); - g_ptr_array_add(stream->events, event); - - /* - * Event had to hold a reference to its event class as long as it wasn't - * part of the same trace hierarchy. From now on, the event and its - * class share the same lifetime guarantees and the reference is no - * longer needed. - */ - BT_LOGV_STR("Putting the event's class."); - bt_ctf_object_put_ref(event->common.class); - BT_LOGV("Appended event to stream: " - "stream-addr=%p, stream-name=\"%s\", event-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64, - stream, bt_ctf_stream_get_name(stream), event, - bt_ctf_event_class_common_get_name( - bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))), - bt_ctf_event_class_common_get_id( - bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)))); - -end: - return ret; - -error: - /* - * Orphan the event; we were not successful in associating it to - * a stream. - */ - bt_ctf_object_set_parent(&event->common.base, NULL); - return ret; -} - -struct bt_ctf_field *bt_ctf_stream_get_packet_context(struct bt_ctf_stream *stream) -{ - struct bt_ctf_field *packet_context = NULL; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - goto end; - } - - packet_context = stream->packet_context; - if (packet_context) { - bt_ctf_object_get_ref(packet_context); - } -end: - return packet_context; -} - -int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream, - struct bt_ctf_field *field) -{ - int ret = 0; - struct bt_ctf_field_type *field_type; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - ret = -1; - goto end; - } - - field_type = bt_ctf_field_get_type(field); - if (bt_ctf_field_type_common_compare((void *) field_type, - stream->common.stream_class->packet_context_field_type)) { - BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: " - "stream-addr=%p, stream-name=\"%s\", " - "packet-context-field-addr=%p, " - "packet-context-ft-addr=%p", - stream, bt_ctf_stream_get_name(stream), - field, field_type); - ret = -1; - goto end; - } - - bt_ctf_object_put_ref(field_type); - bt_ctf_object_put_ref(stream->packet_context); - stream->packet_context = bt_ctf_object_get_ref(field); - BT_LOGV("Set stream's packet context field: " - "stream-addr=%p, stream-name=\"%s\", " - "packet-context-field-addr=%p", - stream, bt_ctf_stream_get_name(stream), field); -end: - return ret; -} - -struct bt_ctf_field *bt_ctf_stream_get_packet_header(struct bt_ctf_stream *stream) -{ - struct bt_ctf_field *packet_header = NULL; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - goto end; - } - - packet_header = stream->packet_header; - if (packet_header) { - bt_ctf_object_get_ref(packet_header); - } -end: - return packet_header; -} - -int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream, - struct bt_ctf_field *field) -{ - int ret = 0; - struct bt_ctf_trace *trace = NULL; - struct bt_ctf_field_type *field_type = NULL; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - ret = -1; - goto end; - } - - trace = (struct bt_ctf_trace *) - bt_ctf_object_get_parent(&stream->common.base); - - if (!field) { - if (trace->common.packet_header_field_type) { - BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: " - "stream-addr=%p, stream-name=\"%s\", " - "packet-header-field-addr=%p, " - "expected-ft-addr=%p", - stream, bt_ctf_stream_get_name(stream), - field, trace->common.packet_header_field_type); - ret = -1; - goto end; - } - - goto skip_validation; - } - - field_type = bt_ctf_field_get_type(field); - BT_ASSERT(field_type); - - if (bt_ctf_field_type_common_compare((void *) field_type, - trace->common.packet_header_field_type)) { - BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: " - "stream-addr=%p, stream-name=\"%s\", " - "packet-header-field-addr=%p, " - "packet-header-ft-addr=%p", - stream, bt_ctf_stream_get_name(stream), - field, field_type); - ret = -1; - goto end; - } - -skip_validation: - bt_ctf_object_put_ref(stream->packet_header); - stream->packet_header = bt_ctf_object_get_ref(field); - BT_LOGV("Set stream's packet header field: " - "stream-addr=%p, stream-name=\"%s\", " - "packet-header-field-addr=%p", - stream, bt_ctf_stream_get_name(stream), field); -end: - BT_CTF_OBJECT_PUT_REF_AND_RESET(trace); - bt_ctf_object_put_ref(field_type); - return ret; -} - -static -void reset_structure_field(struct bt_ctf_field *structure, const char *name) -{ - struct bt_ctf_field *member; - - member = bt_ctf_field_structure_get_field_by_name(structure, name); - if (member) { - bt_ctf_field_common_reset_recursive((void *) member); - bt_ctf_object_put_ref(member); - } -} - -int bt_ctf_stream_flush(struct bt_ctf_stream *stream) -{ - int ret = 0; - size_t i; - uint64_t packet_context_offset_bits = 0; - struct bt_ctf_trace *trace; - enum bt_ctf_byte_order native_byte_order; - bool has_packet_size = false; - uint64_t packet_size_bits = 0; - uint64_t content_size_bits = 0; - - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - ret = -1; - goto end_no_stream; - } - - if (stream->packet_context) { - struct bt_ctf_field *packet_size_field; - - packet_size_field = bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "packet_size"); - has_packet_size = (packet_size_field != NULL); - bt_ctf_object_put_ref(packet_size_field); - } - - if (stream->flushed_packet_count == 1) { - if (!stream->packet_context) { - BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once."); - ret = -1; - goto end; - } - - if (!has_packet_size) { - BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once."); - ret = -1; - goto end; - } - } - - BT_LOGV("Flushing stream's current packet: stream-addr=%p, " - "stream-name=\"%s\", packet-index=%u", stream, - bt_ctf_stream_get_name(stream), stream->flushed_packet_count); - trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace( - stream->common.stream_class)); - BT_ASSERT(trace); - native_byte_order = bt_ctf_trace_get_native_byte_order(trace); - - ret = auto_populate_packet_header(stream); - if (ret) { - BT_LOGW_STR("Cannot automatically populate the stream's packet header field."); - ret = -1; - goto end; - } - - /* Initialize packet/content sizes to `0`; we will overwrite later */ - ret = auto_populate_packet_context(stream, true, 0, 0); - if (ret) { - BT_LOGW_STR("Cannot automatically populate the stream's packet context field."); - ret = -1; - goto end; - } - - ret = bt_ctfser_open_packet(&stream->ctfser); - if (ret) { - /* bt_ctfser_open_packet() logs errors */ - ret = -1; - goto end; - } - - if (stream->packet_header) { - BT_LOGV_STR("Serializing packet header field (initial)."); - ret = bt_ctf_field_serialize_recursive(stream->packet_header, - &stream->ctfser, native_byte_order); - if (ret) { - BT_LOGW("Cannot serialize stream's packet header field: " - "field-addr=%p", stream->packet_header); - goto end; - } - } - - if (stream->packet_context) { - /* Save packet context's position to overwrite it later */ - packet_context_offset_bits = - bt_ctfser_get_offset_in_current_packet_bits( - &stream->ctfser); - - /* Write packet context */ - BT_LOGV_STR("Serializing packet context field (initial)."); - ret = bt_ctf_field_serialize_recursive(stream->packet_context, - &stream->ctfser, native_byte_order); - if (ret) { - BT_LOGW("Cannot serialize stream's packet context field: " - "field-addr=%p", stream->packet_context); - goto end; - } - } - - BT_LOGV("Serializing events: count=%u", stream->events->len); - - for (i = 0; i < stream->events->len; i++) { - struct bt_ctf_event *event = g_ptr_array_index( - stream->events, i); - struct bt_ctf_event_class *event_class = - BT_CTF_FROM_COMMON(bt_ctf_event_common_borrow_class( - BT_CTF_TO_COMMON(event))); - - BT_LOGV("Serializing event: index=%zu, event-addr=%p, " - "event-class-name=\"%s\", event-class-id=%" PRId64 ", " - "ser-offset=%" PRIu64, - i, event, bt_ctf_event_class_get_name(event_class), - bt_ctf_event_class_get_id(event_class), - bt_ctfser_get_offset_in_current_packet_bits( - &stream->ctfser)); - - /* Write event header */ - if (event->common.header_field) { - BT_LOGV_STR("Serializing event's header field."); - ret = bt_ctf_field_serialize_recursive( - (void *) event->common.header_field->field, - &stream->ctfser, native_byte_order); - if (ret) { - BT_LOGW("Cannot serialize event's header field: " - "field-addr=%p", - event->common.header_field->field); - goto end; - } - } - - /* Write stream event context */ - if (event->common.stream_event_context_field) { - BT_LOGV_STR("Serializing event's stream event context field."); - ret = bt_ctf_field_serialize_recursive( - (void *) event->common.stream_event_context_field, - &stream->ctfser, native_byte_order); - if (ret) { - BT_LOGW("Cannot serialize event's stream event context field: " - "field-addr=%p", - event->common.stream_event_context_field); - goto end; - } - } - - /* Write event content */ - ret = bt_ctf_event_serialize(event, &stream->ctfser, - native_byte_order); - if (ret) { - /* bt_ctf_event_serialize() logs errors */ - goto end; - } - } - - content_size_bits = bt_ctfser_get_offset_in_current_packet_bits( - &stream->ctfser); - - if (!has_packet_size && content_size_bits % 8 != 0) { - BT_LOGW("Stream's packet context field type has no `packet_size` field, " - "but current content size is not a multiple of 8 bits: " - "content-size=%" PRIu64 ", " - "packet-size=%" PRIu64, - content_size_bits, - packet_size_bits); - ret = -1; - goto end; - } - - /* Set packet size; make it a multiple of 8 */ - packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7); - - if (stream->packet_context) { - /* - * The whole packet is serialized at this point. Make - * sure that, if `packet_size` is missing, the current - * content size is equal to the current packet size. - */ - struct bt_ctf_field *field = - bt_ctf_field_structure_get_field_by_name( - stream->packet_context, "content_size"); - - bt_ctf_object_put_ref(field); - if (!field) { - if (content_size_bits != packet_size_bits) { - BT_LOGW("Stream's packet context's `content_size` field is missing, " - "but current packet's content size is not equal to its packet size: " - "content-size=%" PRIu64 ", " - "packet-size=%" PRIu64, - bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser), - packet_size_bits); - ret = -1; - goto end; - } - } - - /* - * Overwrite the packet context now that the stream - * position's packet and content sizes have the correct - * values. - */ - bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser, - packet_context_offset_bits); - ret = auto_populate_packet_context(stream, false, - packet_size_bits, content_size_bits); - if (ret) { - BT_LOGW_STR("Cannot automatically populate the stream's packet context field."); - ret = -1; - goto end; - } - - BT_LOGV("Rewriting (serializing) packet context field."); - ret = bt_ctf_field_serialize_recursive(stream->packet_context, - &stream->ctfser, native_byte_order); - if (ret) { - BT_LOGW("Cannot serialize stream's packet context field: " - "field-addr=%p", stream->packet_context); - goto end; - } - } - - g_ptr_array_set_size(stream->events, 0); - stream->flushed_packet_count++; - bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8); - -end: - /* Reset automatically-set fields. */ - if (stream->packet_context) { - reset_structure_field(stream->packet_context, "timestamp_begin"); - reset_structure_field(stream->packet_context, "timestamp_end"); - reset_structure_field(stream->packet_context, "packet_size"); - reset_structure_field(stream->packet_context, "content_size"); - reset_structure_field(stream->packet_context, "events_discarded"); - } - - if (ret == 0) { - BT_LOGV("Flushed stream's current packet: " - "content-size=%" PRIu64 ", packet-size=%" PRIu64, - content_size_bits, packet_size_bits); - } - -end_no_stream: - return ret; -} - -static -void bt_ctf_stream_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_stream *stream = (void *) obj; - - BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"", - stream, bt_ctf_stream_get_name(stream)); - - bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream)); - bt_ctfser_fini(&stream->ctfser); - - if (stream->events) { - BT_LOGD_STR("Putting events."); - g_ptr_array_free(stream->events, TRUE); - } - - BT_LOGD_STR("Putting packet header field."); - bt_ctf_object_put_ref(stream->packet_header); - BT_LOGD_STR("Putting packet context field."); - bt_ctf_object_put_ref(stream->packet_context); - g_free(stream); -} - -static -int _set_structure_field_integer(struct bt_ctf_field *structure, char *name, - uint64_t value, bt_bool force) -{ - int ret = 0; - struct bt_ctf_field_type *field_type = NULL; - struct bt_ctf_field *integer; - - BT_ASSERT(structure); - BT_ASSERT(name); - - integer = bt_ctf_field_structure_get_field_by_name(structure, name); - if (!integer) { - /* Field not found, not an error. */ - BT_LOGV("Field not found: struct-field-addr=%p, " - "name=\"%s\", force=%d", structure, name, force); - goto end; - } - - /* Make sure the payload has not already been set. */ - if (!force && bt_ctf_field_is_set_recursive(integer)) { - /* Payload already set, not an error */ - BT_LOGV("Field's payload is already set: struct-field-addr=%p, " - "name=\"%s\", force=%d", structure, name, force); - goto end; - } - - field_type = bt_ctf_field_get_type(integer); - BT_ASSERT(field_type); - if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { - /* - * The user most likely meant for us to populate this field - * automatically. However, we can only do this if the field - * is an integer. Return an error. - */ - BT_LOGW("Invalid parameter: field's type is not an integer field type: " - "field-addr=%p, ft-addr=%p, ft-id=%s", - integer, field_type, - bt_ctf_field_type_id_string((int) - bt_ctf_field_type_get_type_id(field_type))); - ret = -1; - goto end; - } - - if (bt_ctf_field_type_integer_is_signed(field_type)) { - ret = bt_ctf_field_integer_signed_set_value(integer, - (int64_t) value); - } else { - ret = bt_ctf_field_integer_unsigned_set_value(integer, value); - } - ret = !ret ? 1 : ret; -end: - bt_ctf_object_put_ref(integer); - bt_ctf_object_put_ref(field_type); - return ret; -} - -/* - * Returns the following codes: - * 1 if the field was found and set, - * 0 if nothing was done (field not found, or was already set), - * <0 if an error was encoutered - */ -static -int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name, - uint64_t value) -{ - return _set_structure_field_integer(structure, name, value, BT_FALSE); -} - -struct bt_ctf_stream_class *bt_ctf_stream_get_class( - struct bt_ctf_stream *stream) -{ - return bt_ctf_object_get_ref(bt_ctf_stream_common_borrow_class(BT_CTF_TO_COMMON(stream))); -} - -const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream) -{ - return bt_ctf_stream_common_get_name(BT_CTF_TO_COMMON(stream)); -} - -int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream) -{ - return bt_ctf_stream_common_get_id(BT_CTF_TO_COMMON(stream)); -} diff --git a/lib/ctf-writer/trace.c b/lib/ctf-writer/trace.c deleted file mode 100644 index e9db29a3..00000000 --- a/lib/ctf-writer/trace.c +++ /dev/null @@ -1,1883 +0,0 @@ -/* - * Copyright 2013, 2014 Jérémie Galarneau - * Copyright 2017-2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-TRACE" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_IDENTIFIER_SIZE 128 -#define DEFAULT_METADATA_STRING_SIZE 4096 - -BT_HIDDEN -int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace, - bt_ctf_object_release_func release_func) -{ - int ret = 0; - - BT_LOGD_STR("Initializing common trace object."); - trace->native_byte_order = BT_CTF_BYTE_ORDER_UNSPECIFIED; - bt_ctf_object_init_shared_with_parent(&trace->base, release_func); - trace->clock_classes = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_ctf_object_put_ref); - if (!trace->clock_classes) { - BT_LOGE_STR("Failed to allocate one GPtrArray."); - goto error; - } - - trace->streams = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_ctf_object_try_spec_release); - if (!trace->streams) { - BT_LOGE_STR("Failed to allocate one GPtrArray."); - goto error; - } - - trace->stream_classes = g_ptr_array_new_with_free_func( - (GDestroyNotify) bt_ctf_object_try_spec_release); - if (!trace->stream_classes) { - BT_LOGE_STR("Failed to allocate one GPtrArray."); - goto error; - } - - /* Create the environment array object */ - trace->environment = bt_ctf_attributes_create(); - if (!trace->environment) { - BT_LOGE_STR("Cannot create empty attributes object."); - goto error; - } - - BT_LOGD("Initialized common trace object: addr=%p", trace); - goto end; - -error: - ret = -1; - -end: - return ret; -} - -BT_HIDDEN -void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace) -{ - BT_LOGD("Finalizing common trace object: addr=%p, name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace)); - - if (trace->environment) { - BT_LOGD_STR("Destroying environment attributes."); - bt_ctf_attributes_destroy(trace->environment); - } - - if (trace->name) { - g_string_free(trace->name, TRUE); - } - - if (trace->clock_classes) { - BT_LOGD_STR("Putting clock classes."); - g_ptr_array_free(trace->clock_classes, TRUE); - } - - if (trace->streams) { - BT_LOGD_STR("Destroying streams."); - g_ptr_array_free(trace->streams, TRUE); - } - - if (trace->stream_classes) { - BT_LOGD_STR("Destroying stream classes."); - g_ptr_array_free(trace->stream_classes, TRUE); - } - - BT_LOGD_STR("Putting packet header field type."); - bt_ctf_object_put_ref(trace->packet_header_field_type); -} - -BT_HIDDEN -int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *name) -{ - int ret = 0; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (!name) { - BT_LOGW_STR("Invalid parameter: name is NULL."); - ret = -1; - goto end; - } - - if (trace->frozen) { - BT_LOGW("Invalid parameter: trace is frozen: " - "addr=%p, name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace)); - ret = -1; - goto end; - } - - trace->name = trace->name ? g_string_assign(trace->name, name) : - g_string_new(name); - if (!trace->name) { - BT_LOGE_STR("Failed to allocate one GString."); - ret = -1; - goto end; - } - - BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace, - const unsigned char *uuid) -{ - int ret = 0; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (!uuid) { - BT_LOGW_STR("Invalid parameter: UUID is NULL."); - ret = -1; - goto end; - } - - if (trace->frozen) { - BT_LOGW("Invalid parameter: trace is frozen: " - "addr=%p, name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace)); - ret = -1; - goto end; - } - - memcpy(trace->uuid, uuid, BABELTRACE_UUID_LEN); - trace->uuid_set = BT_TRUE; - BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", " - "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", - trace, bt_ctf_trace_common_get_name(trace), - (unsigned int) uuid[0], - (unsigned int) uuid[1], - (unsigned int) uuid[2], - (unsigned int) uuid[3], - (unsigned int) uuid[4], - (unsigned int) uuid[5], - (unsigned int) uuid[6], - (unsigned int) uuid[7], - (unsigned int) uuid[8], - (unsigned int) uuid[9], - (unsigned int) uuid[10], - (unsigned int) uuid[11], - (unsigned int) uuid[12], - (unsigned int) uuid[13], - (unsigned int) uuid[14], - (unsigned int) uuid[15]); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace, - const char *name, struct bt_ctf_private_value *value) -{ - int ret = 0; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (!name) { - BT_LOGW_STR("Invalid parameter: name is NULL."); - ret = -1; - goto end; - } - - if (!value) { - BT_LOGW_STR("Invalid parameter: value is NULL."); - ret = -1; - goto end; - } - - if (!bt_ctf_identifier_is_valid(name)) { - BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: " - "trace-addr=%p, trace-name=\"%s\", " - "env-name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace), name); - ret = -1; - goto end; - } - - if (!bt_ctf_value_is_integer(bt_ctf_private_value_as_value(value)) && - !bt_ctf_value_is_string(bt_ctf_private_value_as_value(value))) { - BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: " - "trace-addr=%p, trace-name=\"%s\", " - "env-name=\"%s\", env-value-type=%s", - trace, bt_ctf_trace_common_get_name(trace), name, - bt_ctf_value_type_string( - bt_ctf_value_get_type( - bt_ctf_private_value_as_value(value)))); - ret = -1; - goto end; - } - - if (trace->frozen) { - /* - * New environment fields may be added to a frozen trace, - * but existing fields may not be changed. - * - * The object passed is frozen like all other attributes. - */ - struct bt_ctf_private_value *attribute = - bt_ctf_attributes_borrow_field_value_by_name( - trace->environment, name); - - if (attribute) { - BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: " - "trace-addr=%p, trace-name=\"%s\", " - "env-name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace), name); - ret = -1; - goto end; - } - - bt_ctf_value_freeze(bt_ctf_private_value_as_value(value)); - } - - ret = bt_ctf_attributes_set_field_value(trace->environment, name, - value); - if (ret) { - BT_LOGE("Cannot set environment field's value: " - "trace-addr=%p, trace-name=\"%s\", " - "env-name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace), name); - } else { - BT_LOGV("Set environment field's value: " - "trace-addr=%p, trace-name=\"%s\", " - "env-name=\"%s\", value-addr=%p", - trace, bt_ctf_trace_common_get_name(trace), name, value); - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace, - const char *name, const char *value) -{ - int ret = 0; - struct bt_ctf_private_value *env_value_string_obj = NULL; - - if (!value) { - BT_LOGW_STR("Invalid parameter: value is NULL."); - ret = -1; - goto end; - } - - env_value_string_obj = bt_ctf_private_value_string_create_init(value); - if (!env_value_string_obj) { - BT_LOGE_STR("Cannot create string value object."); - ret = -1; - goto end; - } - - /* bt_ctf_trace_common_set_environment_field() logs errors */ - ret = bt_ctf_trace_common_set_environment_field(trace, name, - env_value_string_obj); - -end: - bt_ctf_object_put_ref(env_value_string_obj); - return ret; -} - -BT_HIDDEN -int bt_ctf_trace_common_set_environment_field_integer( - struct bt_ctf_trace_common *trace, const char *name, int64_t value) -{ - int ret = 0; - struct bt_ctf_private_value *env_value_integer_obj = NULL; - - env_value_integer_obj = bt_ctf_private_value_integer_create_init(value); - if (!env_value_integer_obj) { - BT_LOGE_STR("Cannot create integer value object."); - ret = -1; - goto end; - } - - /* bt_ctf_trace_common_set_environment_field() logs errors */ - ret = bt_ctf_trace_common_set_environment_field(trace, name, - env_value_integer_obj); - -end: - bt_ctf_object_put_ref(env_value_integer_obj); - return ret; -} - -BT_HIDDEN -int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace, - struct bt_ctf_clock_class *clock_class) -{ - int ret = 0; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (!bt_ctf_clock_class_is_valid(clock_class)) { - BT_LOGW("Invalid parameter: clock class is invalid: " - "trace-addr=%p, trace-name=\"%s\", " - "clock-class-addr=%p, clock-class-name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace), - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - /* Check for duplicate clock classes */ - if (bt_ctf_trace_common_has_clock_class(trace, clock_class)) { - BT_LOGW("Invalid parameter: clock class already exists in trace: " - "trace-addr=%p, trace-name=\"%s\", " - "clock-class-addr=%p, clock-class-name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace), - clock_class, bt_ctf_clock_class_get_name(clock_class)); - ret = -1; - goto end; - } - - bt_ctf_object_get_ref(clock_class); - g_ptr_array_add(trace->clock_classes, clock_class); - - if (trace->frozen) { - BT_LOGV_STR("Freezing added clock class because trace is frozen."); - bt_ctf_clock_class_freeze(clock_class); - } - - BT_LOGV("Added clock class to trace: " - "trace-addr=%p, trace-name=\"%s\", " - "clock-class-addr=%p, clock-class-name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace), - clock_class, bt_ctf_clock_class_get_name(clock_class)); - -end: - return ret; -} - -static -bool packet_header_field_type_is_valid(struct bt_ctf_trace_common *trace, - struct bt_ctf_field_type_common *packet_header_type) -{ - int ret; - bool is_valid = true; - struct bt_ctf_field_type_common *field_type = NULL; - - if (!packet_header_type) { - /* - * No packet header field type: trace must have only - * one stream. At this point the stream class being - * added is not part of the trace yet, so we validate - * that the trace contains no stream classes yet. - */ - if (trace->stream_classes->len >= 1) { - BT_LOGW_STR("Invalid packet header field type: " - "packet header field type does not exist but there's more than one stream class in the trace."); - goto invalid; - } - - /* No packet header field type: valid at this point */ - goto end; - } - - /* Packet header field type, if it exists, must be a structure */ - if (packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { - BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: " - "ft-addr=%p, ft-id=%s", - packet_header_type, - bt_ctf_field_type_id_string(packet_header_type->id)); - goto invalid; - } - - /* - * If there's a `magic` field, it must be a 32-bit unsigned - * integer field type. Also it must be the first field of the - * packet header field type. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_header_type, "magic"); - if (field_type) { - const char *field_name; - - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: " - "magic-ft-addr=%p, magic-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: " - "magic-ft-addr=%p", field_type); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_get_size(field_type) != 32) { - BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: " - "magic-ft-addr=%p, magic-ft-size=%u", - field_type, - bt_ctf_field_type_common_integer_get_size(field_type)); - goto invalid; - } - - ret = bt_ctf_field_type_common_structure_borrow_field_by_index( - packet_header_type, &field_name, NULL, 0); - BT_ASSERT(ret == 0); - - if (strcmp(field_name, "magic") != 0) { - BT_LOGW("Invalid packet header field type: `magic` field must be the first field: " - "magic-ft-addr=%p, first-field-name=\"%s\"", - field_type, field_name); - goto invalid; - } - } - - /* - * If there's a `uuid` field, it must be an array field type of - * length 16 with an 8-bit unsigned integer element field type. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_header_type, "uuid"); - if (field_type) { - struct bt_ctf_field_type_common *elem_ft; - - if (field_type->id != BT_CTF_FIELD_TYPE_ID_ARRAY) { - BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: " - "uuid-ft-addr=%p, uuid-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_array_get_length(field_type) != 16) { - BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: " - "uuid-ft-addr=%p, uuid-ft-length=%" PRId64, - field_type, - bt_ctf_field_type_common_array_get_length(field_type)); - goto invalid; - } - - elem_ft = bt_ctf_field_type_common_array_borrow_element_field_type(field_type); - BT_ASSERT(elem_ft); - - if (elem_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: " - "elem-ft-addr=%p, elem-ft-id=%s", - elem_ft, - bt_ctf_field_type_id_string(elem_ft->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(elem_ft)) { - BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: " - "elem-ft-addr=%p", elem_ft); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_get_size(elem_ft) != 8) { - BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: " - "elem-ft-addr=%p, elem-ft-size=%u", - elem_ft, - bt_ctf_field_type_common_integer_get_size(elem_ft)); - goto invalid; - } - } - - /* - * The `stream_id` field must exist if there's more than one - * stream classes in the trace. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_header_type, "stream_id"); - - if (!field_type && trace->stream_classes->len >= 1) { - BT_LOGW_STR("Invalid packet header field type: " - "`stream_id` field does not exist but there's more than one stream class in the trace."); - goto invalid; - } - - /* - * If there's a `stream_id` field, it must be an unsigned - * integer field type. - */ - if (field_type) { - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: " - "stream-id-ft-addr=%p, stream-id-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: " - "stream-id-ft-addr=%p", field_type); - goto invalid; - } - } - - /* - * If there's a `packet_seq_num` field, it must be an unsigned - * integer field type. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_header_type, "packet_seq_num"); - if (field_type) { - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: " - "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: " - "packet-seq-num-ft-addr=%p", field_type); - goto invalid; - } - } - - goto end; - -invalid: - is_valid = false; - -end: - return is_valid; -} - -static -bool packet_context_field_type_is_valid(struct bt_ctf_trace_common *trace, - struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_field_type_common *packet_context_type, - bool check_ts_begin_end_mapped) -{ - bool is_valid = true; - struct bt_ctf_field_type_common *field_type = NULL; - - if (!packet_context_type) { - /* No packet context field type: valid at this point */ - goto end; - } - - /* Packet context field type, if it exists, must be a structure */ - if (packet_context_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { - BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: " - "ft-addr=%p, ft-id=%s", - packet_context_type, - bt_ctf_field_type_id_string(packet_context_type->id)); - goto invalid; - } - - /* - * If there's a `packet_size` field, it must be an unsigned - * integer field type. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_context_type, "packet_size"); - if (field_type) { - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: " - "packet-size-ft-addr=%p, packet-size-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: " - "packet-size-ft-addr=%p", field_type); - goto invalid; - } - } - - /* - * If there's a `content_size` field, it must be an unsigned - * integer field type. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_context_type, "content_size"); - if (field_type) { - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: " - "content-size-ft-addr=%p, content-size-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: " - "content-size-ft-addr=%p", field_type); - goto invalid; - } - } - - /* - * If there's a `events_discarded` field, it must be an unsigned - * integer field type. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_context_type, "events_discarded"); - if (field_type) { - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: " - "events-discarded-ft-addr=%p, events-discarded-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: " - "events-discarded-ft-addr=%p", field_type); - goto invalid; - } - } - - /* - * If there's a `timestamp_begin` field, it must be an unsigned - * integer field type. Also, if the trace is not a CTF writer's - * trace, then we cannot automatically set the mapped clock - * class of this field, so it must have a mapped clock class. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_context_type, "timestamp_begin"); - if (field_type) { - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: " - "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: " - "timestamp-begin-ft-addr=%p", field_type); - goto invalid; - } - - if (check_ts_begin_end_mapped) { - struct bt_ctf_clock_class *clock_class = - bt_ctf_field_type_common_integer_borrow_mapped_clock_class( - field_type); - - if (!clock_class) { - BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: " - "timestamp-begin-ft-addr=%p", field_type); - goto invalid; - } - } - } - - /* - * If there's a `timestamp_end` field, it must be an unsigned - * integer field type. Also, if the trace is not a CTF writer's - * trace, then we cannot automatically set the mapped clock - * class of this field, so it must have a mapped clock class. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - packet_context_type, "timestamp_end"); - if (field_type) { - if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) { - BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: " - "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - if (bt_ctf_field_type_common_integer_is_signed(field_type)) { - BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: " - "timestamp-end-ft-addr=%p", field_type); - goto invalid; - } - - if (check_ts_begin_end_mapped) { - struct bt_ctf_clock_class *clock_class = - bt_ctf_field_type_common_integer_borrow_mapped_clock_class( - field_type); - - if (!clock_class) { - BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: " - "timestamp-end-ft-addr=%p", field_type); - goto invalid; - } - } - } - - goto end; - -invalid: - is_valid = false; - -end: - return is_valid; -} - -static -bool event_header_field_type_is_valid(struct bt_ctf_trace_common *trace, - struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_field_type_common *event_header_type) -{ - bool is_valid = true; - struct bt_ctf_field_type_common *field_type = NULL; - - /* - * We do not validate that the `timestamp` field exists here - * because CTF does not require this exact name to be mapped to - * a clock class. - */ - - if (!event_header_type) { - /* - * No event header field type: stream class must have - * only one event class. - */ - if (bt_ctf_stream_class_common_get_event_class_count(stream_class) > 1) { - BT_LOGW_STR("Invalid event header field type: " - "event header field type does not exist but there's more than one event class in the stream class."); - goto invalid; - } - - /* No event header field type: valid at this point */ - goto end; - } - - /* Event header field type, if it exists, must be a structure */ - if (event_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { - BT_LOGW("Invalid event header field type: must be a structure field type if it exists: " - "ft-addr=%p, ft-id=%s", - event_header_type, - bt_ctf_field_type_id_string(event_header_type->id)); - goto invalid; - } - - /* - * If there's an `id` field, it must be an unsigned integer - * field type or an enumeration field type with an unsigned - * integer container field type. - */ - field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name( - event_header_type, "id"); - if (field_type) { - struct bt_ctf_field_type_common *int_ft; - - if (field_type->id == BT_CTF_FIELD_TYPE_ID_INTEGER) { - int_ft = field_type; - } else if (field_type->id == BT_CTF_FIELD_TYPE_ID_ENUM) { - int_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type( - field_type); - } else { - BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: " - "id-ft-addr=%p, id-ft-id=%s", - field_type, - bt_ctf_field_type_id_string(field_type->id)); - goto invalid; - } - - BT_ASSERT(int_ft); - if (bt_ctf_field_type_common_integer_is_signed(int_ft)) { - BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: " - "id-ft-addr=%p", int_ft); - goto invalid; - } - } - - goto end; - -invalid: - is_valid = false; - -end: - return is_valid; -} - -static -int check_packet_header_type_has_no_clock_class(struct bt_ctf_trace_common *trace) -{ - int ret = 0; - - if (trace->packet_header_field_type) { - struct bt_ctf_clock_class *clock_class = NULL; - - ret = bt_ctf_field_type_common_validate_single_clock_class( - trace->packet_header_field_type, - &clock_class); - bt_ctf_object_put_ref(clock_class); - if (ret || clock_class) { - BT_LOGW("Trace's packet header field type cannot " - "contain a field type which is mapped to " - "a clock class: " - "trace-addr=%p, trace-name=\"%s\", " - "clock-class-name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace), - clock_class ? - bt_ctf_clock_class_get_name(clock_class) : - NULL); - ret = -1; - } - } - - return ret; -} - -BT_HIDDEN -int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace, - struct bt_ctf_stream_class_common *stream_class, - bt_ctf_validation_flag_copy_field_type_func copy_field_type_func, - struct bt_ctf_clock_class *init_expected_clock_class, - int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_field_type_common *packet_context_field_type, - struct bt_ctf_field_type_common *event_header_field_type), - bool check_ts_begin_end_mapped) -{ - int ret; - int64_t i; - int64_t stream_id; - struct bt_ctf_validation_output trace_sc_validation_output = { 0 }; - struct bt_ctf_validation_output *ec_validation_outputs = NULL; - const enum bt_ctf_validation_flag trace_sc_validation_flags = - BT_CTF_VALIDATION_FLAG_TRACE | - BT_CTF_VALIDATION_FLAG_STREAM; - const enum bt_ctf_validation_flag ec_validation_flags = - BT_CTF_VALIDATION_FLAG_EVENT; - struct bt_ctf_field_type_common *packet_header_type = NULL; - struct bt_ctf_field_type_common *packet_context_type = NULL; - struct bt_ctf_field_type_common *event_header_type = NULL; - struct bt_ctf_field_type_common *stream_event_ctx_type = NULL; - int64_t event_class_count; - struct bt_ctf_trace_common *current_parent_trace = NULL; - struct bt_ctf_clock_class *expected_clock_class = - bt_ctf_object_get_ref(init_expected_clock_class); - - BT_ASSERT(copy_field_type_func); - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (!stream_class) { - BT_LOGW_STR("Invalid parameter: stream class is NULL."); - ret = -1; - goto end; - } - - BT_LOGD("Adding stream class to trace: " - "trace-addr=%p, trace-name=\"%s\", " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64, - trace, bt_ctf_trace_common_get_name(trace), - stream_class, bt_ctf_stream_class_common_get_name(stream_class), - bt_ctf_stream_class_common_get_id(stream_class)); - - current_parent_trace = bt_ctf_stream_class_common_borrow_trace(stream_class); - if (current_parent_trace) { - /* Stream class is already associated to a trace, abort. */ - BT_LOGW("Invalid parameter: stream class is already part of a trace: " - "stream-class-trace-addr=%p, " - "stream-class-trace-name=\"%s\"", - current_parent_trace, - bt_ctf_trace_common_get_name(current_parent_trace)); - ret = -1; - goto end; - } - - event_class_count = - bt_ctf_stream_class_common_get_event_class_count(stream_class); - BT_ASSERT(event_class_count >= 0); - - if (!stream_class->frozen) { - /* - * Stream class is not frozen yet. Validate that the - * stream class contains at most a single clock class - * because the previous - * bt_ctf_stream_class_common_add_event_class() calls did - * not make this validation since the stream class's - * direct field types (packet context, event header, - * event context) could change afterwards. This stream - * class is about to be frozen and those field types - * won't be changed if this function succeeds. - * - * At this point we're also sure that the stream class's - * clock, if any, has the same class as the stream - * class's expected clock class, if any. This is why, if - * bt_ctf_stream_class_common_validate_single_clock_class() - * succeeds below, the call to - * bt_ctf_stream_class_map_clock_class() at the end of this - * function is safe because it maps to the same, single - * clock class. - */ - ret = bt_ctf_stream_class_common_validate_single_clock_class( - stream_class, &expected_clock_class); - if (ret) { - BT_LOGW("Invalid parameter: stream class or one of its " - "event classes contains a field type which is " - "not recursively mapped to the expected " - "clock class: " - "stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", " - "stream-class-name=\"%s\", " - "expected-clock-class-addr=%p, " - "expected-clock-class-name=\"%s\"", - stream_class, bt_ctf_stream_class_common_get_id(stream_class), - bt_ctf_stream_class_common_get_name(stream_class), - expected_clock_class, - expected_clock_class ? - bt_ctf_clock_class_get_name(expected_clock_class) : - NULL); - goto end; - } - } - - ret = check_packet_header_type_has_no_clock_class(trace); - if (ret) { - /* check_packet_header_type_has_no_clock_class() logs errors */ - goto end; - } - - /* - * We're about to freeze both the trace and the stream class. - * Also, each event class contained in this stream class are - * already frozen. - * - * This trace, this stream class, and all its event classes - * should be valid at this point. - * - * Validate trace and stream class first, then each event - * class of this stream class can be validated individually. - */ - packet_header_type = - bt_ctf_trace_common_borrow_packet_header_field_type(trace); - packet_context_type = - bt_ctf_stream_class_common_borrow_packet_context_field_type(stream_class); - event_header_type = - bt_ctf_stream_class_common_borrow_event_header_field_type(stream_class); - stream_event_ctx_type = - bt_ctf_stream_class_common_borrow_event_context_field_type(stream_class); - - BT_LOGD("Validating trace and stream class field types."); - ret = bt_ctf_validate_class_types(trace->environment, - packet_header_type, packet_context_type, event_header_type, - stream_event_ctx_type, NULL, NULL, trace->valid, - stream_class->valid, 1, &trace_sc_validation_output, - trace_sc_validation_flags, copy_field_type_func); - - if (ret) { - /* - * This means something went wrong during the validation - * process, not that the objects are invalid. - */ - BT_LOGE("Failed to validate trace and stream class field types: " - "ret=%d", ret); - goto end; - } - - if ((trace_sc_validation_output.valid_flags & - trace_sc_validation_flags) != - trace_sc_validation_flags) { - /* Invalid trace/stream class */ - BT_LOGW("Invalid trace or stream class field types: " - "valid-flags=0x%x", - trace_sc_validation_output.valid_flags); - ret = -1; - goto end; - } - - if (event_class_count > 0) { - ec_validation_outputs = g_new0(struct bt_ctf_validation_output, - event_class_count); - if (!ec_validation_outputs) { - BT_LOGE_STR("Failed to allocate one validation output structure."); - ret = -1; - goto end; - } - } - - /* Validate each event class individually */ - for (i = 0; i < event_class_count; i++) { - struct bt_ctf_event_class_common *event_class = - bt_ctf_stream_class_common_borrow_event_class_by_index( - stream_class, i); - struct bt_ctf_field_type_common *event_context_type = NULL; - struct bt_ctf_field_type_common *event_payload_type = NULL; - - event_context_type = - bt_ctf_event_class_common_borrow_context_field_type( - event_class); - event_payload_type = - bt_ctf_event_class_common_borrow_payload_field_type( - event_class); - - /* - * It is important to use the field types returned by - * the previous trace and stream class validation here - * because copies could have been made. - */ - BT_LOGD("Validating event class's field types: " - "addr=%p, name=\"%s\", id=%" PRId64, - event_class, bt_ctf_event_class_common_get_name(event_class), - bt_ctf_event_class_common_get_id(event_class)); - ret = bt_ctf_validate_class_types(trace->environment, - trace_sc_validation_output.packet_header_type, - trace_sc_validation_output.packet_context_type, - trace_sc_validation_output.event_header_type, - trace_sc_validation_output.stream_event_ctx_type, - event_context_type, event_payload_type, - 1, 1, event_class->valid, &ec_validation_outputs[i], - ec_validation_flags, copy_field_type_func); - - if (ret) { - BT_LOGE("Failed to validate event class field types: " - "ret=%d", ret); - goto end; - } - - if ((ec_validation_outputs[i].valid_flags & - ec_validation_flags) != ec_validation_flags) { - /* Invalid event class */ - BT_LOGW("Invalid event class field types: " - "valid-flags=0x%x", - ec_validation_outputs[i].valid_flags); - ret = -1; - goto end; - } - } - - stream_id = bt_ctf_stream_class_common_get_id(stream_class); - if (stream_id < 0) { - stream_id = trace->next_stream_id++; - if (stream_id < 0) { - BT_LOGE_STR("No more stream class IDs available."); - ret = -1; - goto end; - } - - /* Try to assign a new stream id */ - for (i = 0; i < trace->stream_classes->len; i++) { - if (stream_id == bt_ctf_stream_class_common_get_id( - trace->stream_classes->pdata[i])) { - /* Duplicate stream id found */ - BT_LOGW("Duplicate stream class ID: " - "id=%" PRId64, (int64_t) stream_id); - ret = -1; - goto end; - } - } - - if (bt_ctf_stream_class_common_set_id_no_check(stream_class, - stream_id)) { - /* TODO Should retry with a different stream id */ - BT_LOGE("Cannot set stream class's ID: " - "id=%" PRId64, (int64_t) stream_id); - ret = -1; - goto end; - } - } - - /* - * At this point all the field types in the validation output - * are valid. Validate the semantics of some scopes according to - * the CTF specification. - */ - if (!packet_header_field_type_is_valid(trace, - trace_sc_validation_output.packet_header_type)) { - BT_LOGW_STR("Invalid trace's packet header field type."); - ret = -1; - goto end; - } - - if (!packet_context_field_type_is_valid(trace, - stream_class, - trace_sc_validation_output.packet_context_type, - check_ts_begin_end_mapped)) { - BT_LOGW_STR("Invalid stream class's packet context field type."); - ret = -1; - goto end; - } - - if (!event_header_field_type_is_valid(trace, - stream_class, - trace_sc_validation_output.event_header_type)) { - BT_LOGW_STR("Invalid steam class's event header field type."); - ret = -1; - goto end; - } - - /* - * Now is the time to automatically map specific field types of - * the stream class's packet context and event header field - * types to the stream class's clock's class if they are not - * mapped to a clock class yet. We do it here because we know - * that after this point, everything is frozen so it won't be - * possible for the user to modify the stream class's clock, or - * to map those field types to other clock classes. - */ - if (map_clock_classes_func) { - if (map_clock_classes_func(stream_class, - trace_sc_validation_output.packet_context_type, - trace_sc_validation_output.event_header_type)) { - /* map_clock_classes_func() logs errors */ - ret = -1; - goto end; - } - } - - bt_ctf_object_set_parent(&stream_class->base, &trace->base); - g_ptr_array_add(trace->stream_classes, stream_class); - - /* - * At this point we know that the function will be successful. - * Therefore we can replace the trace and stream class field - * types with what's in their validation output structure and - * mark them as valid. We can also replace the field types of - * all the event classes of the stream class and mark them as - * valid. - */ - bt_ctf_validation_replace_types(trace, stream_class, NULL, - &trace_sc_validation_output, trace_sc_validation_flags); - trace->valid = 1; - stream_class->valid = 1; - - /* - * Put what was not moved in bt_ctf_validation_replace_types(). - */ - bt_ctf_validation_output_put_types(&trace_sc_validation_output); - - for (i = 0; i < event_class_count; i++) { - struct bt_ctf_event_class_common *event_class = - bt_ctf_stream_class_common_borrow_event_class_by_index( - stream_class, i); - - bt_ctf_validation_replace_types(NULL, NULL, event_class, - &ec_validation_outputs[i], ec_validation_flags); - event_class->valid = 1; - - /* - * Put what was not moved in - * bt_ctf_validation_replace_types(). - */ - bt_ctf_validation_output_put_types(&ec_validation_outputs[i]); - } - - /* - * Freeze the trace and the stream class. - */ - bt_ctf_stream_class_common_freeze(stream_class); - bt_ctf_trace_common_freeze(trace); - - /* - * It is safe to set the stream class's unique clock class - * now because the stream class is frozen. - */ - if (expected_clock_class) { - BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class); - } - - BT_LOGD("Added stream class to trace: " - "trace-addr=%p, trace-name=\"%s\", " - "stream-class-addr=%p, stream-class-name=\"%s\", " - "stream-class-id=%" PRId64, - trace, bt_ctf_trace_common_get_name(trace), - stream_class, bt_ctf_stream_class_common_get_name(stream_class), - bt_ctf_stream_class_common_get_id(stream_class)); - -end: - if (ret) { - bt_ctf_object_set_parent(&stream_class->base, NULL); - - if (ec_validation_outputs) { - for (i = 0; i < event_class_count; i++) { - bt_ctf_validation_output_put_types( - &ec_validation_outputs[i]); - } - } - } - - g_free(ec_validation_outputs); - bt_ctf_validation_output_put_types(&trace_sc_validation_output); - bt_ctf_object_put_ref(expected_clock_class); - return ret; -} - -BT_HIDDEN -bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace, - struct bt_ctf_clock_class *clock_class) -{ - struct bt_ctf_search_query query = { .value = clock_class, .found = 0 }; - - BT_ASSERT(trace); - BT_ASSERT(clock_class); - - g_ptr_array_foreach(trace->clock_classes, value_exists, &query); - return query.found; -} - -BT_HIDDEN -int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace, - enum bt_ctf_byte_order byte_order, bool allow_unspecified) -{ - int ret = 0; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (trace->frozen) { - BT_LOGW("Invalid parameter: trace is frozen: " - "addr=%p, name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace)); - ret = -1; - goto end; - } - - if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) { - BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: " - "addr=%p, name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace)); - ret = -1; - goto end; - } - - if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN && - byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN && - byte_order != BT_CTF_BYTE_ORDER_NETWORK) { - BT_LOGW("Invalid parameter: invalid byte order: " - "addr=%p, name=\"%s\", bo=%s", - trace, bt_ctf_trace_common_get_name(trace), - bt_ctf_byte_order_string(byte_order)); - ret = -1; - goto end; - } - - trace->native_byte_order = byte_order; - BT_LOGV("Set trace's native byte order: " - "addr=%p, name=\"%s\", bo=%s", - trace, bt_ctf_trace_common_get_name(trace), - bt_ctf_byte_order_string(byte_order)); - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace, - struct bt_ctf_field_type_common *packet_header_type) -{ - int ret = 0; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (trace->frozen) { - BT_LOGW("Invalid parameter: trace is frozen: " - "addr=%p, name=\"%s\"", - trace, bt_ctf_trace_common_get_name(trace)); - ret = -1; - goto end; - } - - /* packet_header_type must be a structure. */ - if (packet_header_type && - packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) { - BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: " - "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s", - trace, bt_ctf_trace_common_get_name(trace), - packet_header_type, - bt_ctf_field_type_id_string(packet_header_type->id)); - ret = -1; - goto end; - } - - bt_ctf_object_put_ref(trace->packet_header_field_type); - trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type); - BT_LOGV("Set trace's packet header field type: " - "addr=%p, name=\"%s\", packet-context-ft-addr=%p", - trace, bt_ctf_trace_common_get_name(trace), packet_header_type); -end: - return ret; -} - -static -int64_t get_stream_class_count(void *element) -{ - return bt_ctf_trace_get_stream_class_count( - (struct bt_ctf_trace *) element); -} - -static -void *get_stream_class(void *element, int i) -{ - return bt_ctf_trace_get_stream_class_by_index( - (struct bt_ctf_trace *) element, i); -} - -static -int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data) -{ - return bt_ctf_stream_class_visit(object, visitor, data); -} - -int bt_ctf_trace_visit(struct bt_ctf_trace *trace, - bt_ctf_visitor visitor, void *data) -{ - int ret; - struct bt_ctf_visitor_object obj = { - .object = trace, - .type = BT_CTF_VISITOR_OBJECT_TYPE_TRACE - }; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (!visitor) { - BT_LOGW_STR("Invalid parameter: visitor is NULL."); - ret = -1; - goto end; - } - - BT_LOGV("Visiting trace: addr=%p, name=\"%s\"", - trace, bt_ctf_trace_get_name(trace)); - ret = bt_ctf_visitor_helper(&obj, get_stream_class_count, - get_stream_class, visit_stream_class, visitor, data); -end: - return ret; -} - -static -void bt_ctf_trace_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_trace *trace = (void *) obj; - - BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"", - trace, bt_ctf_trace_get_name(trace)); - bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace)); - g_free(trace); -} - -BT_HIDDEN -struct bt_ctf_trace *bt_ctf_trace_create(void) -{ - struct bt_ctf_trace *trace = NULL; - int ret; - - BT_LOGD_STR("Creating CTF writer trace object."); - trace = g_new0(struct bt_ctf_trace, 1); - if (!trace) { - BT_LOGE_STR("Failed to allocate one CTF writer trace."); - goto error; - } - - ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace), - bt_ctf_trace_destroy); - if (ret) { - /* bt_ctf_trace_common_initialize() logs errors */ - goto error; - } - - BT_LOGD("Created CTF writer trace object: addr=%p", trace); - return trace; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(trace); - return trace; -} - -const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace) -{ - return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace)); -} - -int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace, - const unsigned char *uuid) -{ - return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid); -} - -int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace, - const char *name, const char *value) -{ - return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace), - name, value); -} - -int bt_ctf_trace_set_environment_field_integer( - struct bt_ctf_trace *trace, const char *name, int64_t value) -{ - return bt_ctf_trace_common_set_environment_field_integer( - BT_CTF_TO_COMMON(trace), name, value); -} - -int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace) -{ - return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace)); -} - -const char * -bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace, - uint64_t index) -{ - return bt_ctf_trace_common_get_environment_field_name_by_index( - BT_CTF_TO_COMMON(trace), index); -} - -struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index( - struct bt_ctf_trace *trace, uint64_t index) -{ - return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index( - BT_CTF_TO_COMMON(trace), index)); -} - -struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name( - struct bt_ctf_trace *trace, const char *name) -{ - return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name( - BT_CTF_TO_COMMON(trace), name)); -} - -BT_HIDDEN -int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace, - struct bt_ctf_clock_class *clock_class) -{ - return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace), - (void *) clock_class); -} - -BT_HIDDEN -int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace) -{ - return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace)); -} - -BT_HIDDEN -struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index( - struct bt_ctf_trace *trace, uint64_t index) -{ - return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index( - BT_CTF_TO_COMMON(trace), index)); -} - -static -int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_field_type_common *packet_context_type, - struct bt_ctf_field_type_common *event_header_type) -{ - int ret = bt_ctf_stream_class_map_clock_class( - BT_CTF_FROM_COMMON(stream_class), - BT_CTF_FROM_COMMON(packet_context_type), - BT_CTF_FROM_COMMON(event_header_type)); - - if (ret) { - BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class."); - } - - return ret; -} - -int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace, - struct bt_ctf_stream_class *stream_class) -{ - int ret = 0; - struct bt_ctf_clock_class *expected_clock_class = NULL; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - ret = -1; - goto end; - } - - if (!stream_class) { - BT_LOGW_STR("Invalid parameter: stream class is NULL."); - ret = -1; - goto end; - } - - if (stream_class->clock) { - struct bt_ctf_clock_class *stream_clock_class = - stream_class->clock->clock_class; - - /* - * Make sure this clock was also added to the - * trace (potentially through its CTF writer - * owner). - */ - size_t i; - - for (i = 0; i < trace->common.clock_classes->len; i++) { - if (trace->common.clock_classes->pdata[i] == - stream_clock_class) { - /* Found! */ - break; - } - } - - if (i == trace->common.clock_classes->len) { - /* Not found */ - BT_LOGW("Stream class's clock's class is not part of the trace: " - "clock-class-addr=%p, clock-class-name=\"%s\"", - stream_clock_class, - bt_ctf_clock_class_get_name(stream_clock_class)); - ret = -1; - goto end; - } - - if (stream_class->common.clock_class && - stream_class->common.clock_class != - stream_class->clock->clock_class) { - /* - * Stream class already has an expected clock - * class, but it does not match its clock's - * class. - */ - BT_LOGW("Invalid parameter: stream class's clock's " - "class does not match stream class's " - "expected clock class: " - "stream-class-addr=%p, " - "stream-class-id=%" PRId64 ", " - "stream-class-name=\"%s\", " - "expected-clock-class-addr=%p, " - "expected-clock-class-name=\"%s\"", - stream_class, - bt_ctf_stream_class_get_id(stream_class), - bt_ctf_stream_class_get_name(stream_class), - stream_class->common.clock_class, - bt_ctf_clock_class_get_name(stream_class->common.clock_class)); - } else if (!stream_class->common.clock_class) { - /* - * Set expected clock class to stream class's - * clock's class. - */ - expected_clock_class = stream_class->clock->clock_class; - } - } - - - ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace), - BT_CTF_TO_COMMON(stream_class), - (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy, - expected_clock_class, map_clock_classes_func, - false); - -end: - return ret; -} - -int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace) -{ - return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace)); -} - -struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index( - struct bt_ctf_trace *trace, uint64_t index) -{ - return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index( - BT_CTF_TO_COMMON(trace), index)); -} - -int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace) -{ - return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace)); -} - -struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index( - struct bt_ctf_trace *trace, uint64_t index) -{ - return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index( - BT_CTF_TO_COMMON(trace), index)); -} - -struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id( - struct bt_ctf_trace *trace, uint64_t id) -{ - return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id( - BT_CTF_TO_COMMON(trace), id)); -} - -BT_HIDDEN -struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name( - struct bt_ctf_trace *trace, const char *name) -{ - return bt_ctf_object_get_ref( - bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace), - name)); -} - -static -int append_trace_metadata(struct bt_ctf_trace *trace, - struct metadata_context *context) -{ - unsigned char *uuid = trace->common.uuid; - int ret = 0; - - if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE || - trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) { - BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; " - "set it with bt_ctf_trace_set_native_byte_order(): " - "addr=%p, name=\"%s\"", - trace, bt_ctf_trace_get_name(trace)); - ret = -1; - goto end; - } - - g_string_append(context->string, "trace {\n"); - g_string_append(context->string, "\tmajor = 1;\n"); - g_string_append(context->string, "\tminor = 8;\n"); - BT_ASSERT(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN || - trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN || - trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK); - - if (trace->common.uuid_set) { - g_string_append_printf(context->string, - "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - } - - g_string_append_printf(context->string, "\tbyte_order = %s;\n", - bt_ctf_get_byte_order_string(trace->common.native_byte_order)); - - if (trace->common.packet_header_field_type) { - g_string_append(context->string, "\tpacket.header := "); - context->current_indentation_level++; - g_string_assign(context->field_name, ""); - BT_LOGD_STR("Serializing trace's packet header field type's metadata."); - ret = bt_ctf_field_type_serialize_recursive( - (void *) trace->common.packet_header_field_type, - context); - if (ret) { - goto end; - } - context->current_indentation_level--; - } - - g_string_append(context->string, ";\n};\n\n"); -end: - return ret; -} - -static -void append_env_metadata(struct bt_ctf_trace *trace, - struct metadata_context *context) -{ - int64_t i; - int64_t env_size; - - env_size = bt_ctf_attributes_get_count(trace->common.environment); - if (env_size <= 0) { - return; - } - - g_string_append(context->string, "env {\n"); - - for (i = 0; i < env_size; i++) { - struct bt_ctf_private_value *env_field_value_obj = NULL; - const char *entry_name; - - entry_name = bt_ctf_attributes_get_field_name( - trace->common.environment, i); - env_field_value_obj = bt_ctf_attributes_borrow_field_value( - trace->common.environment, i); - - BT_ASSERT(entry_name); - BT_ASSERT(env_field_value_obj); - - switch (bt_ctf_value_get_type( - bt_ctf_private_value_as_value(env_field_value_obj))) { - case BT_CTF_VALUE_TYPE_INTEGER: - { - int64_t int_value; - - int_value = bt_ctf_value_integer_get( - bt_ctf_private_value_as_value( - env_field_value_obj)); - g_string_append_printf(context->string, - "\t%s = %" PRId64 ";\n", entry_name, - int_value); - break; - } - case BT_CTF_VALUE_TYPE_STRING: - { - const char *str_value; - char *escaped_str = NULL; - - str_value = bt_ctf_value_string_get( - bt_ctf_private_value_as_value( - env_field_value_obj)); - escaped_str = g_strescape(str_value, NULL); - if (!escaped_str) { - BT_LOGE("Cannot escape string: string=\"%s\"", - str_value); - continue; - } - - g_string_append_printf(context->string, - "\t%s = \"%s\";\n", entry_name, escaped_str); - free(escaped_str); - break; - } - default: - continue; - } - } - - g_string_append(context->string, "};\n\n"); -} - -char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace) -{ - char *metadata = NULL; - struct metadata_context *context = NULL; - int err = 0; - size_t i; - - if (!trace) { - BT_LOGW_STR("Invalid parameter: trace is NULL."); - goto end; - } - - context = g_new0(struct metadata_context, 1); - if (!context) { - BT_LOGE_STR("Failed to allocate one metadata context."); - goto end; - } - - context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE); - context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE); - g_string_append(context->string, "/* CTF 1.8 */\n\n"); - if (append_trace_metadata(trace, context)) { - /* append_trace_metadata() logs errors */ - goto error; - } - append_env_metadata(trace, context); - g_ptr_array_foreach(trace->common.clock_classes, - (GFunc) bt_ctf_clock_class_serialize, context); - - for (i = 0; i < trace->common.stream_classes->len; i++) { - /* bt_ctf_stream_class_serialize() logs details */ - err = bt_ctf_stream_class_serialize( - trace->common.stream_classes->pdata[i], context); - if (err) { - /* bt_ctf_stream_class_serialize() logs errors */ - goto error; - } - } - - metadata = context->string->str; - -error: - g_string_free(context->string, err ? TRUE : FALSE); - g_string_free(context->field_name, TRUE); - g_free(context); - -end: - return metadata; -} - -enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order( - struct bt_ctf_trace *trace) -{ - return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace)); -} - -int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace, - enum bt_ctf_byte_order byte_order) -{ - return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace), - (int) byte_order, false); -} - -struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type( - struct bt_ctf_trace *trace) -{ - return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type( - BT_CTF_TO_COMMON(trace))); -} - -int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace, - struct bt_ctf_field_type *packet_header_type) -{ - return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace), - (void *) packet_header_type); -} - -const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace) -{ - return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace)); -} diff --git a/lib/ctf-writer/utils.c b/lib/ctf-writer/utils.c deleted file mode 100644 index fbf515b0..00000000 --- a/lib/ctf-writer/utils.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * utils.c - * - * Babeltrace CTF writer - Utilities - * - * Copyright 2015 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-UTILS" -#include - -#include -#include -#include -#include -#include -#include -#include - -static -const char * const reserved_keywords_str[] = {"align", "callsite", - "const", "char", "clock", "double", "enum", "env", "event", - "floating_point", "float", "integer", "int", "long", "short", "signed", - "stream", "string", "struct", "trace", "typealias", "typedef", - "unsigned", "variant", "void" "_Bool", "_Complex", "_Imaginary"}; - -static GHashTable *reserved_keywords_set; -static int init_done; - -static -void try_init_reserved_keywords(void) -{ - size_t i; - const size_t reserved_keywords_count = - sizeof(reserved_keywords_str) / sizeof(char *); - - if (reserved_keywords_set) { - return; - } - - reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal); - BT_ASSERT(reserved_keywords_set); - - for (i = 0; i < reserved_keywords_count; 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; -} - -static __attribute__((destructor)) -void trace_finalize(void) -{ - if (reserved_keywords_set) { - g_hash_table_destroy(reserved_keywords_set); - } -} - -bt_bool bt_ctf_identifier_is_valid(const char *identifier) -{ - bt_bool is_valid = BT_TRUE; - char *string = NULL; - char *save_ptr, *token; - - if (!identifier) { - BT_LOGV_STR("Invalid parameter: input string is NULL."); - is_valid = BT_FALSE; - goto end; - } - - try_init_reserved_keywords(); - - if (identifier[0] == '\0') { - is_valid = BT_FALSE; - goto end; - } - - string = strdup(identifier); - if (!string) { - BT_LOGE("strdup() failed."); - is_valid = BT_FALSE; - goto end; - } - - token = strtok_r(string, " ", &save_ptr); - while (token) { - if (g_hash_table_lookup_extended(reserved_keywords_set, - GINT_TO_POINTER(g_quark_from_string(token)), - NULL, NULL)) { - is_valid = BT_FALSE; - goto end; - } - - token = strtok_r(NULL, " ", &save_ptr); - } -end: - free(string); - return is_valid; -} diff --git a/lib/ctf-writer/validation.c b/lib/ctf-writer/validation.c deleted file mode 100644 index 97a279aa..00000000 --- a/lib/ctf-writer/validation.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * validation.c - * - * Babeltrace - CTF writer: Validation of trace, stream class, and event class - * - * Copyright 2016-2018 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-VALIDATION" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This function resolves and validates the field types of an event - * class. Only `event_context_type` and `event_payload_type` are - * resolved and validated; the other field types are used as eventual - * resolving targets. - * - * All parameters are owned by the caller. - */ -static -int validate_event_class_types(struct bt_ctf_private_value *environment, - struct bt_ctf_field_type_common *packet_header_type, - struct bt_ctf_field_type_common *packet_context_type, - struct bt_ctf_field_type_common *event_header_type, - struct bt_ctf_field_type_common *stream_event_ctx_type, - struct bt_ctf_field_type_common *event_context_type, - struct bt_ctf_field_type_common *event_payload_type) -{ - int ret = 0; - - BT_LOGV("Validating event class field types: " - "packet-header-ft-addr=%p, " - "packet-context-ft-addr=%p, " - "event-header-ft-addr=%p, " - "stream-event-context-ft-addr=%p, " - "event-context-ft-addr=%p, " - "event-payload-ft-addr=%p", - packet_header_type, packet_context_type, event_header_type, - stream_event_ctx_type, event_context_type, event_payload_type); - - /* Resolve sequence type lengths and variant type tags first */ - ret = bt_ctf_resolve_types(environment, packet_header_type, - packet_context_type, event_header_type, stream_event_ctx_type, - event_context_type, event_payload_type, - BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT | - BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD); - if (ret) { - BT_LOGW("Cannot resolve event class field types: ret=%d", - ret); - goto end; - } - - /* Validate field types individually */ - if (event_context_type) { - ret = bt_ctf_field_type_common_validate(event_context_type); - if (ret) { - BT_LOGW("Invalid event class's context field type: " - "ret=%d", ret); - goto end; - } - } - - if (event_payload_type) { - ret = bt_ctf_field_type_common_validate(event_payload_type); - if (ret) { - BT_LOGW("Invalid event class's payload field type: " - "ret=%d", ret); - goto end; - } - } - -end: - return ret; -} - -/* - * This function resolves and validates the field types of a stream - * class. Only `packet_context_type`, `event_header_type`, and - * `stream_event_ctx_type` are resolved and validated; the other field - * type is used as an eventual resolving target. - * - * All parameters are owned by the caller. - */ -static -int validate_stream_class_types(struct bt_ctf_private_value *environment, - struct bt_ctf_field_type_common *packet_header_type, - struct bt_ctf_field_type_common *packet_context_type, - struct bt_ctf_field_type_common *event_header_type, - struct bt_ctf_field_type_common *stream_event_ctx_type) -{ - int ret = 0; - - BT_LOGV("Validating stream class field types: " - "packet-header-ft-addr=%p, " - "packet-context-ft-addr=%p, " - "event-header-ft-addr=%p, " - "stream-event-context-ft-addr=%p", - packet_header_type, packet_context_type, event_header_type, - stream_event_ctx_type); - - /* Resolve sequence type lengths and variant type tags first */ - ret = bt_ctf_resolve_types(environment, packet_header_type, - packet_context_type, event_header_type, stream_event_ctx_type, - NULL, NULL, - BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT | - BT_CTF_RESOLVE_FLAG_EVENT_HEADER | - BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX); - if (ret) { - BT_LOGW("Cannot resolve stream class field types: ret=%d", - ret); - goto end; - } - - /* Validate field types individually */ - if (packet_context_type) { - ret = bt_ctf_field_type_common_validate(packet_context_type); - if (ret) { - BT_LOGW("Invalid stream class's packet context field type: " - "ret=%d", ret); - goto end; - } - } - - if (event_header_type) { - ret = bt_ctf_field_type_common_validate(event_header_type); - if (ret) { - BT_LOGW("Invalid stream class's event header field type: " - "ret=%d", ret); - goto end; - } - } - - if (stream_event_ctx_type) { - ret = bt_ctf_field_type_common_validate( - stream_event_ctx_type); - if (ret) { - BT_LOGW("Invalid stream class's event context field type: " - "ret=%d", ret); - goto end; - } - } - -end: - return ret; -} - -/* - * This function resolves and validates the field types of a trace. - * - * All parameters are owned by the caller. - */ -static -int validate_trace_types(struct bt_ctf_private_value *environment, - struct bt_ctf_field_type_common *packet_header_type) -{ - int ret = 0; - - BT_LOGV("Validating event class field types: " - "packet-header-ft-addr=%p", packet_header_type); - - /* Resolve sequence type lengths and variant type tags first */ - ret = bt_ctf_resolve_types(environment, packet_header_type, - NULL, NULL, NULL, NULL, NULL, - BT_CTF_RESOLVE_FLAG_PACKET_HEADER); - if (ret) { - BT_LOGW("Cannot resolve trace field types: ret=%d", - ret); - goto end; - } - - /* Validate field types individually */ - if (packet_header_type) { - ret = bt_ctf_field_type_common_validate(packet_header_type); - if (ret) { - BT_LOGW("Invalid trace's packet header field type: " - "ret=%d", ret); - goto end; - } - } - -end: - return ret; -} - -/* - * Checks whether or not `field_type` contains a variant or a sequence - * field type, recursively. Returns 1 if it's the case. - * - * `field_type` is owned by the caller. - */ -static -int field_type_contains_sequence_or_variant_ft(struct bt_ctf_field_type_common *type) -{ - int ret = 0; - enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type); - - switch (type_id) { - case BT_CTF_FIELD_TYPE_ID_SEQUENCE: - case BT_CTF_FIELD_TYPE_ID_VARIANT: - ret = 1; - goto end; - case BT_CTF_FIELD_TYPE_ID_ARRAY: - case BT_CTF_FIELD_TYPE_ID_STRUCT: - { - int i; - int field_count = bt_ctf_field_type_common_get_field_count(type); - - if (field_count < 0) { - ret = -1; - goto end; - } - - for (i = 0; i < field_count; ++i) { - struct bt_ctf_field_type_common *child_type = - bt_ctf_field_type_common_borrow_field_at_index( - type, i); - - ret = field_type_contains_sequence_or_variant_ft( - child_type); - if (ret != 0) { - goto end; - } - } - break; - } - default: - break; - } - -end: - return ret; -} - -BT_HIDDEN -int bt_ctf_validate_class_types(struct bt_ctf_private_value *environment, - struct bt_ctf_field_type_common *packet_header_type, - struct bt_ctf_field_type_common *packet_context_type, - struct bt_ctf_field_type_common *event_header_type, - struct bt_ctf_field_type_common *stream_event_ctx_type, - struct bt_ctf_field_type_common *event_context_type, - struct bt_ctf_field_type_common *event_payload_type, - int trace_valid, int stream_class_valid, int event_class_valid, - struct bt_ctf_validation_output *output, - enum bt_ctf_validation_flag validate_flags, - bt_ctf_validation_flag_copy_field_type_func copy_field_type_func) -{ - int ret = 0; - int contains_seq_var; - int valid_ret; - - BT_LOGV("Validating field types: " - "packet-header-ft-addr=%p, " - "packet-context-ft-addr=%p, " - "event-header-ft-addr=%p, " - "stream-event-context-ft-addr=%p, " - "event-context-ft-addr=%p, " - "event-payload-ft-addr=%p, " - "trace-is-valid=%d, stream-class-is-valid=%d, " - "event-class-is-valid=%d, validation-flags=%x", - packet_header_type, packet_context_type, event_header_type, - stream_event_ctx_type, event_context_type, event_payload_type, - trace_valid, stream_class_valid, event_class_valid, - (unsigned int) validate_flags); - - /* Clean output values */ - memset(output, 0, sizeof(*output)); - - /* Set initial valid flags according to valid parameters */ - if (trace_valid) { - output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE; - } - - if (stream_class_valid) { - output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM; - } - - if (event_class_valid) { - output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT; - } - - /* Own the type parameters */ - bt_ctf_object_get_ref(packet_header_type); - bt_ctf_object_get_ref(packet_context_type); - bt_ctf_object_get_ref(event_header_type); - bt_ctf_object_get_ref(stream_event_ctx_type); - bt_ctf_object_get_ref(event_context_type); - bt_ctf_object_get_ref(event_payload_type); - - /* Validate trace */ - if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) { - struct bt_ctf_field_type_common *packet_header_type_copy = NULL; - - /* Create field type copies */ - if (packet_header_type) { - contains_seq_var = - field_type_contains_sequence_or_variant_ft( - packet_header_type); - if (contains_seq_var < 0) { - ret = contains_seq_var; - goto error; - } else if (!contains_seq_var) { - /* No copy is needed */ - packet_header_type_copy = packet_header_type; - bt_ctf_object_get_ref(packet_header_type_copy); - goto skip_packet_header_type_copy; - } - - BT_LOGV_STR("Copying packet header field type because it contains at least one sequence or variant field type."); - packet_header_type_copy = - copy_field_type_func(packet_header_type); - if (!packet_header_type_copy) { - ret = -1; - BT_LOGE_STR("Cannot copy packet header field type."); - goto error; - } - - /* - * Freeze this copy: if it's returned to the - * caller, it cannot be modified any way since - * it will be resolved. - */ - bt_ctf_field_type_common_freeze(packet_header_type_copy); - } - -skip_packet_header_type_copy: - /* Put original reference and move copy */ - BT_CTF_OBJECT_MOVE_REF(packet_header_type, packet_header_type_copy); - - /* Validate trace field types */ - valid_ret = validate_trace_types(environment, - packet_header_type); - if (valid_ret == 0) { - /* Trace is valid */ - output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE; - } - } - - /* Validate stream class */ - if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) && - !stream_class_valid) { - struct bt_ctf_field_type_common *packet_context_type_copy = NULL; - struct bt_ctf_field_type_common *event_header_type_copy = NULL; - struct bt_ctf_field_type_common *stream_event_ctx_type_copy = NULL; - - if (packet_context_type) { - contains_seq_var = - field_type_contains_sequence_or_variant_ft( - packet_context_type); - if (contains_seq_var < 0) { - ret = contains_seq_var; - goto error; - } else if (!contains_seq_var) { - /* No copy is needed */ - packet_context_type_copy = packet_context_type; - bt_ctf_object_get_ref(packet_context_type_copy); - goto skip_packet_context_type_copy; - } - - BT_LOGV_STR("Copying packet context field type because it contains at least one sequence or variant field type."); - packet_context_type_copy = - copy_field_type_func(packet_context_type); - if (!packet_context_type_copy) { - BT_LOGE_STR("Cannot copy packet context field type."); - goto sc_validation_error; - } - - /* - * Freeze this copy: if it's returned to the - * caller, it cannot be modified any way since - * it will be resolved. - */ - bt_ctf_field_type_common_freeze(packet_context_type_copy); - } - -skip_packet_context_type_copy: - if (event_header_type) { - contains_seq_var = - field_type_contains_sequence_or_variant_ft( - event_header_type); - if (contains_seq_var < 0) { - ret = contains_seq_var; - goto error; - } else if (!contains_seq_var) { - /* No copy is needed */ - event_header_type_copy = event_header_type; - bt_ctf_object_get_ref(event_header_type_copy); - goto skip_event_header_type_copy; - } - - BT_LOGV_STR("Copying event header field type because it contains at least one sequence or variant field type."); - event_header_type_copy = - copy_field_type_func(event_header_type); - if (!event_header_type_copy) { - BT_LOGE_STR("Cannot copy event header field type."); - goto sc_validation_error; - } - - /* - * Freeze this copy: if it's returned to the - * caller, it cannot be modified any way since - * it will be resolved. - */ - bt_ctf_field_type_common_freeze(event_header_type_copy); - } - -skip_event_header_type_copy: - if (stream_event_ctx_type) { - contains_seq_var = - field_type_contains_sequence_or_variant_ft( - stream_event_ctx_type); - if (contains_seq_var < 0) { - ret = contains_seq_var; - goto error; - } else if (!contains_seq_var) { - /* No copy is needed */ - stream_event_ctx_type_copy = - stream_event_ctx_type; - bt_ctf_object_get_ref(stream_event_ctx_type_copy); - goto skip_stream_event_ctx_type_copy; - } - - BT_LOGV_STR("Copying stream event context field type because it contains at least one sequence or variant field type."); - stream_event_ctx_type_copy = - copy_field_type_func(stream_event_ctx_type); - if (!stream_event_ctx_type_copy) { - BT_LOGE_STR("Cannot copy stream event context field type."); - goto sc_validation_error; - } - - /* - * Freeze this copy: if it's returned to the - * caller, it cannot be modified any way since - * it will be resolved. - */ - bt_ctf_field_type_common_freeze(stream_event_ctx_type_copy); - } - -skip_stream_event_ctx_type_copy: - /* Put original references and move copies */ - BT_CTF_OBJECT_MOVE_REF(packet_context_type, packet_context_type_copy); - BT_CTF_OBJECT_MOVE_REF(event_header_type, event_header_type_copy); - BT_CTF_OBJECT_MOVE_REF(stream_event_ctx_type, stream_event_ctx_type_copy); - - /* Validate stream class field types */ - valid_ret = validate_stream_class_types(environment, - packet_header_type, packet_context_type, - event_header_type, stream_event_ctx_type); - if (valid_ret == 0) { - /* Stream class is valid */ - output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM; - } - - goto sc_validation_done; - -sc_validation_error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type_copy); - BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type_copy); - BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type_copy); - ret = -1; - goto error; - } - -sc_validation_done: - /* Validate event class */ - if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) && - !event_class_valid) { - struct bt_ctf_field_type_common *event_context_type_copy = NULL; - struct bt_ctf_field_type_common *event_payload_type_copy = NULL; - - if (event_context_type) { - contains_seq_var = - field_type_contains_sequence_or_variant_ft( - event_context_type); - if (contains_seq_var < 0) { - ret = contains_seq_var; - goto error; - } else if (!contains_seq_var) { - /* No copy is needed */ - event_context_type_copy = event_context_type; - bt_ctf_object_get_ref(event_context_type_copy); - goto skip_event_context_type_copy; - } - - BT_LOGV_STR("Copying event context field type because it contains at least one sequence or variant field type."); - event_context_type_copy = - copy_field_type_func(event_context_type); - if (!event_context_type_copy) { - BT_LOGE_STR("Cannot copy event context field type."); - goto ec_validation_error; - } - - /* - * Freeze this copy: if it's returned to the - * caller, it cannot be modified any way since - * it will be resolved. - */ - bt_ctf_field_type_common_freeze(event_context_type_copy); - } - -skip_event_context_type_copy: - if (event_payload_type) { - contains_seq_var = - field_type_contains_sequence_or_variant_ft( - event_payload_type); - if (contains_seq_var < 0) { - ret = contains_seq_var; - goto error; - } else if (!contains_seq_var) { - /* No copy is needed */ - event_payload_type_copy = event_payload_type; - bt_ctf_object_get_ref(event_payload_type_copy); - goto skip_event_payload_type_copy; - } - - BT_LOGV_STR("Copying event payload field type because it contains at least one sequence or variant field type."); - event_payload_type_copy = - copy_field_type_func(event_payload_type); - if (!event_payload_type_copy) { - BT_LOGE_STR("Cannot copy event payload field type."); - goto ec_validation_error; - } - - /* - * Freeze this copy: if it's returned to the - * caller, it cannot be modified any way since - * it will be resolved. - */ - bt_ctf_field_type_common_freeze(event_payload_type_copy); - } - -skip_event_payload_type_copy: - /* Put original references and move copies */ - BT_CTF_OBJECT_MOVE_REF(event_context_type, event_context_type_copy); - BT_CTF_OBJECT_MOVE_REF(event_payload_type, event_payload_type_copy); - - /* Validate event class field types */ - valid_ret = validate_event_class_types(environment, - packet_header_type, packet_context_type, - event_header_type, stream_event_ctx_type, - event_context_type, event_payload_type); - if (valid_ret == 0) { - /* Event class is valid */ - output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT; - } - - goto ec_validation_done; - -ec_validation_error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type_copy); - BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type_copy); - ret = -1; - goto error; - } - -ec_validation_done: - /* - * Validation is complete. Move the field types that were used - * to validate (and that were possibly altered by the validation - * process) to the output values. - */ - BT_CTF_OBJECT_MOVE_REF(output->packet_header_type, packet_header_type); - BT_CTF_OBJECT_MOVE_REF(output->packet_context_type, packet_context_type); - BT_CTF_OBJECT_MOVE_REF(output->event_header_type, event_header_type); - BT_CTF_OBJECT_MOVE_REF(output->stream_event_ctx_type, stream_event_ctx_type); - BT_CTF_OBJECT_MOVE_REF(output->event_context_type, event_context_type); - BT_CTF_OBJECT_MOVE_REF(output->event_payload_type, event_payload_type); - return ret; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_header_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type); - return ret; -} - -BT_HIDDEN -void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace, - struct bt_ctf_stream_class_common *stream_class, - struct bt_ctf_event_class_common *event_class, - struct bt_ctf_validation_output *output, - enum bt_ctf_validation_flag replace_flags) -{ - if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) { - bt_ctf_field_type_common_freeze(trace->packet_header_field_type); - BT_CTF_OBJECT_MOVE_REF(trace->packet_header_field_type, - output->packet_header_type); - } - - if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) { - bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type); - bt_ctf_field_type_common_freeze(stream_class->event_header_field_type); - bt_ctf_field_type_common_freeze(stream_class->event_context_field_type); - BT_CTF_OBJECT_MOVE_REF(stream_class->packet_context_field_type, - output->packet_context_type); - BT_CTF_OBJECT_MOVE_REF(stream_class->event_header_field_type, - output->event_header_type); - BT_CTF_OBJECT_MOVE_REF(stream_class->event_context_field_type, - output->stream_event_ctx_type); - } - - if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) { - bt_ctf_field_type_common_freeze(event_class->context_field_type); - bt_ctf_field_type_common_freeze(event_class->payload_field_type); - BT_CTF_OBJECT_MOVE_REF(event_class->context_field_type, output->event_context_type); - BT_CTF_OBJECT_MOVE_REF(event_class->payload_field_type, output->event_payload_type); - } -} - -BT_HIDDEN -void bt_ctf_validation_output_put_types( - struct bt_ctf_validation_output *output) -{ - BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_header_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_context_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_header_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(output->stream_event_ctx_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_context_type); - BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_payload_type); -} diff --git a/lib/ctf-writer/values.c b/lib/ctf-writer/values.c deleted file mode 100644 index 7c45dafa..00000000 --- a/lib/ctf-writer/values.c +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation - * Copyright (c) 2015 Philippe Proulx - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER-VALUES" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BT_CTF_VALUE_FROM_CONCRETE(_concrete) ((struct bt_ctf_value *) (_concrete)) -#define BT_CTF_VALUE_TO_BOOL(_base) ((struct bt_ctf_value_bool *) (_base)) -#define BT_CTF_VALUE_TO_INTEGER(_base) ((struct bt_ctf_value_integer *) (_base)) -#define BT_CTF_VALUE_TO_REAL(_base) ((struct bt_ctf_value_real *) (_base)) -#define BT_CTF_VALUE_TO_STRING(_base) ((struct bt_ctf_value_string *) (_base)) -#define BT_CTF_VALUE_TO_ARRAY(_base) ((struct bt_ctf_value_array *) (_base)) -#define BT_CTF_VALUE_TO_MAP(_base) ((struct bt_ctf_value_map *) (_base)) - -#define BT_ASSERT_PRE_VALUE_IS_TYPE(_value, _type) \ - BT_ASSERT_PRE(((struct bt_ctf_value *) (_value))->type == (_type), \ - "Value has the wrong type ID: expected-type=%d, " \ - "%![value-]+v", (_type), \ - (_value)) - -#define BT_ASSERT_PRE_VALUE_HOT(_value, _name) \ - BT_ASSERT_PRE_HOT(((struct bt_ctf_value *) (_value)), (_name), \ - ": %!+v", (_value)) - -#define BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count) \ - BT_ASSERT_PRE((_index) < (_count), \ - "Index is out of bound: " \ - "index=%" PRIu64 ", count=%u", (_index), (_count)); - -struct bt_ctf_value { - struct bt_ctf_object base; - enum bt_ctf_value_type type; - bt_bool frozen; -}; - -static -void bt_ctf_value_null_instance_release_func(struct bt_ctf_object *obj) -{ - BT_LOGW("Releasing the null value singleton: addr=%p", obj); -} - -static -struct bt_ctf_value bt_ctf_value_null_instance = { - .base = { - .is_shared = true, - .ref_count = 1, - .release_func = bt_ctf_value_null_instance_release_func, - .spec_release_func = NULL, - .parent_is_owner_listener_func = NULL, - .parent = NULL, - }, - .type = BT_CTF_VALUE_TYPE_NULL, - .frozen = BT_TRUE, -}; - -struct bt_ctf_value *const bt_ctf_value_null = &bt_ctf_value_null_instance; -struct bt_ctf_private_value *const bt_ctf_private_value_null = - (void *) &bt_ctf_value_null_instance; - -struct bt_ctf_value_bool { - struct bt_ctf_value base; - bt_bool value; -}; - -struct bt_ctf_value_integer { - struct bt_ctf_value base; - int64_t value; -}; - -struct bt_ctf_value_real { - struct bt_ctf_value base; - double value; -}; - -struct bt_ctf_value_string { - struct bt_ctf_value base; - GString *gstr; -}; - -struct bt_ctf_value_array { - struct bt_ctf_value base; - GPtrArray *garray; -}; - -struct bt_ctf_value_map { - struct bt_ctf_value base; - GHashTable *ght; -}; - -static -void bt_ctf_value_destroy(struct bt_ctf_object *obj); - -static -void bt_ctf_value_string_destroy(struct bt_ctf_value *object) -{ - g_string_free(BT_CTF_VALUE_TO_STRING(object)->gstr, TRUE); - BT_CTF_VALUE_TO_STRING(object)->gstr = NULL; -} - -static -void bt_ctf_value_array_destroy(struct bt_ctf_value *object) -{ - /* - * Pointer array's registered value destructor will take care - * of putting each contained object. - */ - g_ptr_array_free(BT_CTF_VALUE_TO_ARRAY(object)->garray, TRUE); - BT_CTF_VALUE_TO_ARRAY(object)->garray = NULL; -} - -static -void bt_ctf_value_map_destroy(struct bt_ctf_value *object) -{ - /* - * Hash table's registered value destructor will take care of - * putting each contained object. Keys are GQuarks and cannot - * be destroyed anyway. - */ - g_hash_table_destroy(BT_CTF_VALUE_TO_MAP(object)->ght); - BT_CTF_VALUE_TO_MAP(object)->ght = NULL; -} - -static -void (* const destroy_funcs[])(struct bt_ctf_value *) = { - [BT_CTF_VALUE_TYPE_NULL] = NULL, - [BT_CTF_VALUE_TYPE_BOOL] = NULL, - [BT_CTF_VALUE_TYPE_INTEGER] = NULL, - [BT_CTF_VALUE_TYPE_REAL] = NULL, - [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_string_destroy, - [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_destroy, - [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_destroy, -}; - -static -struct bt_ctf_private_value *bt_ctf_value_null_copy(const struct bt_ctf_value *null_obj) -{ - return (void *) bt_ctf_value_null; -} - -static -struct bt_ctf_private_value *bt_ctf_value_bool_copy(const struct bt_ctf_value *bool_obj) -{ - return bt_ctf_private_value_bool_create_init( - BT_CTF_VALUE_TO_BOOL(bool_obj)->value); -} - -static -struct bt_ctf_private_value *bt_ctf_value_integer_copy( - const struct bt_ctf_value *integer_obj) -{ - return bt_ctf_private_value_integer_create_init( - BT_CTF_VALUE_TO_INTEGER(integer_obj)->value); -} - -static -struct bt_ctf_private_value *bt_ctf_value_real_copy(const struct bt_ctf_value *real_obj) -{ - return bt_ctf_private_value_real_create_init( - BT_CTF_VALUE_TO_REAL(real_obj)->value); -} - -static -struct bt_ctf_private_value *bt_ctf_value_string_copy(const struct bt_ctf_value *string_obj) -{ - return bt_ctf_private_value_string_create_init( - BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str); -} - -static -struct bt_ctf_private_value *bt_ctf_value_array_copy(const struct bt_ctf_value *array_obj) -{ - int i; - int ret; - struct bt_ctf_private_value *copy_obj; - struct bt_ctf_value_array *typed_array_obj; - - BT_LOGD("Copying array value: addr=%p", array_obj); - typed_array_obj = BT_CTF_VALUE_TO_ARRAY(array_obj); - copy_obj = bt_ctf_private_value_array_create(); - if (!copy_obj) { - BT_LOGE_STR("Cannot create empty array value."); - goto end; - } - - for (i = 0; i < typed_array_obj->garray->len; ++i) { - struct bt_ctf_private_value *element_obj_copy = NULL; - struct bt_ctf_value *element_obj = - bt_ctf_value_array_borrow_element_by_index( - array_obj, i); - - BT_ASSERT(element_obj); - BT_LOGD("Copying array value's element: element-addr=%p, " - "index=%d", element_obj, i); - ret = bt_ctf_value_copy(&element_obj_copy, element_obj); - if (ret) { - BT_LOGE("Cannot copy array value's element: " - "array-addr=%p, index=%d", - array_obj, i); - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); - goto end; - } - - BT_ASSERT(element_obj_copy); - ret = bt_ctf_private_value_array_append_element(copy_obj, - (void *) element_obj_copy); - BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy); - if (ret) { - BT_LOGE("Cannot append to array value: addr=%p", - array_obj); - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); - goto end; - } - } - - BT_LOGD("Copied array value: original-addr=%p, copy-addr=%p", - array_obj, copy_obj); - -end: - return copy_obj; -} - -static -struct bt_ctf_private_value *bt_ctf_value_map_copy(const struct bt_ctf_value *map_obj) -{ - int ret; - GHashTableIter iter; - gpointer key, element_obj; - struct bt_ctf_private_value *copy_obj; - struct bt_ctf_private_value *element_obj_copy = NULL; - struct bt_ctf_value_map *typed_map_obj; - - BT_LOGD("Copying map value: addr=%p", map_obj); - typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj); - copy_obj = bt_ctf_private_value_map_create(); - if (!copy_obj) { - goto end; - } - - g_hash_table_iter_init(&iter, typed_map_obj->ght); - - while (g_hash_table_iter_next(&iter, &key, &element_obj)) { - const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key)); - - BT_ASSERT(key_str); - BT_LOGD("Copying map value's element: element-addr=%p, " - "key=\"%s\"", element_obj, key_str); - ret = bt_ctf_value_copy(&element_obj_copy, element_obj); - if (ret) { - BT_LOGE("Cannot copy map value's element: " - "map-addr=%p, key=\"%s\"", - map_obj, key_str); - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); - goto end; - } - - BT_ASSERT(element_obj_copy); - ret = bt_ctf_private_value_map_insert_entry(copy_obj, key_str, - (void *) element_obj_copy); - BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy); - if (ret) { - BT_LOGE("Cannot insert into map value: addr=%p, key=\"%s\"", - map_obj, key_str); - BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj); - goto end; - } - } - - BT_LOGD("Copied map value: addr=%p", map_obj); - -end: - return copy_obj; -} - -static -struct bt_ctf_private_value *(* const copy_funcs[])(const struct bt_ctf_value *) = { - [BT_CTF_VALUE_TYPE_NULL] = bt_ctf_value_null_copy, - [BT_CTF_VALUE_TYPE_BOOL] = bt_ctf_value_bool_copy, - [BT_CTF_VALUE_TYPE_INTEGER] = bt_ctf_value_integer_copy, - [BT_CTF_VALUE_TYPE_REAL] = bt_ctf_value_real_copy, - [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_string_copy, - [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_copy, - [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_copy, -}; - -static -bt_bool bt_ctf_value_null_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - /* - * Always BT_TRUE since bt_ctf_value_compare() already checks if both - * object_a and object_b have the same type, and in the case of - * null value objects, they're always the same if it is so. - */ - return BT_TRUE; -} - -static -bt_bool bt_ctf_value_bool_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - if (BT_CTF_VALUE_TO_BOOL(object_a)->value != - BT_CTF_VALUE_TO_BOOL(object_b)->value) { - BT_LOGV("Boolean value objects are different: " - "bool-a-val=%d, bool-b-val=%d", - BT_CTF_VALUE_TO_BOOL(object_a)->value, - BT_CTF_VALUE_TO_BOOL(object_b)->value); - return BT_FALSE; - } - - return BT_TRUE; -} - -static -bt_bool bt_ctf_value_integer_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - if (BT_CTF_VALUE_TO_INTEGER(object_a)->value != - BT_CTF_VALUE_TO_INTEGER(object_b)->value) { - BT_LOGV("Integer value objects are different: " - "int-a-val=%" PRId64 ", int-b-val=%" PRId64, - BT_CTF_VALUE_TO_INTEGER(object_a)->value, - BT_CTF_VALUE_TO_INTEGER(object_b)->value); - return BT_FALSE; - } - - return BT_TRUE; -} - -static -bt_bool bt_ctf_value_real_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - if (BT_CTF_VALUE_TO_REAL(object_a)->value != - BT_CTF_VALUE_TO_REAL(object_b)->value) { - BT_LOGV("Real number value objects are different: " - "real-a-val=%f, real-b-val=%f", - BT_CTF_VALUE_TO_REAL(object_a)->value, - BT_CTF_VALUE_TO_REAL(object_b)->value); - return BT_FALSE; - } - - return BT_TRUE; -} - -static -bt_bool bt_ctf_value_string_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - if (strcmp(BT_CTF_VALUE_TO_STRING(object_a)->gstr->str, - BT_CTF_VALUE_TO_STRING(object_b)->gstr->str) != 0) { - BT_LOGV("String value objects are different: " - "string-a-val=\"%s\", string-b-val=\"%s\"", - BT_CTF_VALUE_TO_STRING(object_a)->gstr->str, - BT_CTF_VALUE_TO_STRING(object_b)->gstr->str); - return BT_FALSE; - } - - return BT_TRUE; -} - -static -bt_bool bt_ctf_value_array_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - int i; - bt_bool ret = BT_TRUE; - const struct bt_ctf_value_array *array_obj_a = - BT_CTF_VALUE_TO_ARRAY(object_a); - - if (bt_ctf_value_array_get_size(object_a) != - bt_ctf_value_array_get_size(object_b)) { - BT_LOGV("Array values are different: size mismatch " - "value-a-addr=%p, value-b-addr=%p, " - "value-a-size=%" PRId64 ", value-b-size=%" PRId64, - object_a, object_b, - bt_ctf_value_array_get_size(object_a), - bt_ctf_value_array_get_size(object_b)); - ret = BT_FALSE; - goto end; - } - - for (i = 0; i < array_obj_a->garray->len; ++i) { - struct bt_ctf_value *element_obj_a; - struct bt_ctf_value *element_obj_b; - - element_obj_a = bt_ctf_value_array_borrow_element_by_index( - object_a, i); - element_obj_b = bt_ctf_value_array_borrow_element_by_index( - object_b, i); - - if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) { - BT_LOGV("Array values's elements are different: " - "value-a-addr=%p, value-b-addr=%p, index=%d", - element_obj_a, element_obj_b, i); - ret = BT_FALSE; - goto end; - } - } - -end: - return ret; -} - -static -bt_bool bt_ctf_value_map_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - bt_bool ret = BT_TRUE; - GHashTableIter iter; - gpointer key, element_obj_a; - const struct bt_ctf_value_map *map_obj_a = BT_CTF_VALUE_TO_MAP(object_a); - - if (bt_ctf_value_map_get_size(object_a) != - bt_ctf_value_map_get_size(object_b)) { - BT_LOGV("Map values are different: size mismatch " - "value-a-addr=%p, value-b-addr=%p, " - "value-a-size=%" PRId64 ", value-b-size=%" PRId64, - object_a, object_b, - bt_ctf_value_map_get_size(object_a), - bt_ctf_value_map_get_size(object_b)); - ret = BT_FALSE; - goto end; - } - - g_hash_table_iter_init(&iter, map_obj_a->ght); - - while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) { - struct bt_ctf_value *element_obj_b; - const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key)); - - element_obj_b = bt_ctf_value_map_borrow_entry_value(object_b, - key_str); - - if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) { - BT_LOGV("Map values's elements are different: " - "value-a-addr=%p, value-b-addr=%p, key=\"%s\"", - element_obj_a, element_obj_b, key_str); - ret = BT_FALSE; - goto end; - } - } - -end: - return ret; -} - -static -bt_bool (* const compare_funcs[])(const struct bt_ctf_value *, - const struct bt_ctf_value *) = { - [BT_CTF_VALUE_TYPE_NULL] = bt_ctf_value_null_compare, - [BT_CTF_VALUE_TYPE_BOOL] = bt_ctf_value_bool_compare, - [BT_CTF_VALUE_TYPE_INTEGER] = bt_ctf_value_integer_compare, - [BT_CTF_VALUE_TYPE_REAL] = bt_ctf_value_real_compare, - [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_string_compare, - [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_compare, - [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_compare, -}; - -static -void bt_ctf_value_null_freeze(struct bt_ctf_value *object) -{ -} - -static -void bt_ctf_value_generic_freeze(struct bt_ctf_value *object) -{ - object->frozen = BT_TRUE; -} - -static -void bt_ctf_value_array_freeze(struct bt_ctf_value *object) -{ - int i; - struct bt_ctf_value_array *typed_array_obj = - BT_CTF_VALUE_TO_ARRAY(object); - - for (i = 0; i < typed_array_obj->garray->len; ++i) { - bt_ctf_value_freeze(g_ptr_array_index(typed_array_obj->garray, i)); - } - - bt_ctf_value_generic_freeze(object); -} - -static -void bt_ctf_value_map_freeze(struct bt_ctf_value *object) -{ - GHashTableIter iter; - gpointer key, element_obj; - const struct bt_ctf_value_map *map_obj = BT_CTF_VALUE_TO_MAP(object); - - g_hash_table_iter_init(&iter, map_obj->ght); - - while (g_hash_table_iter_next(&iter, &key, &element_obj)) { - bt_ctf_value_freeze(element_obj); - } - - bt_ctf_value_generic_freeze(object); -} - -static -void (* const freeze_funcs[])(struct bt_ctf_value *) = { - [BT_CTF_VALUE_TYPE_NULL] = bt_ctf_value_null_freeze, - [BT_CTF_VALUE_TYPE_BOOL] = bt_ctf_value_generic_freeze, - [BT_CTF_VALUE_TYPE_INTEGER] = bt_ctf_value_generic_freeze, - [BT_CTF_VALUE_TYPE_REAL] = bt_ctf_value_generic_freeze, - [BT_CTF_VALUE_TYPE_STRING] = bt_ctf_value_generic_freeze, - [BT_CTF_VALUE_TYPE_ARRAY] = bt_ctf_value_array_freeze, - [BT_CTF_VALUE_TYPE_MAP] = bt_ctf_value_map_freeze, -}; - -static -void bt_ctf_value_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_value *value; - - value = container_of(obj, struct bt_ctf_value, base); - BT_LOGD("Destroying value: addr=%p", value); - - if (bt_ctf_value_is_null(value)) { - BT_LOGD_STR("Not destroying the null value singleton."); - return; - } - - if (destroy_funcs[value->type]) { - destroy_funcs[value->type](value); - } - - g_free(value); -} - -BT_HIDDEN -enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object) -{ - enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK; - - BT_ASSERT(object); - - if (object->frozen) { - goto end; - } - - BT_LOGD("Freezing value: addr=%p", object); - freeze_funcs[object->type](object); - -end: - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object) -{ - BT_ASSERT_PRE_NON_NULL(object, "Value object"); - return object->type; -} - -static -struct bt_ctf_value bt_ctf_value_create_base(enum bt_ctf_value_type type) -{ - struct bt_ctf_value value; - - value.type = type; - value.frozen = BT_FALSE; - bt_ctf_object_init_shared(&value.base, bt_ctf_value_destroy); - return value; -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val) -{ - struct bt_ctf_value_bool *bool_obj; - - BT_LOGD("Creating boolean value object: val=%d", val); - bool_obj = g_new0(struct bt_ctf_value_bool, 1); - if (!bool_obj) { - BT_LOGE_STR("Failed to allocate one boolean value object."); - goto end; - } - - bool_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_BOOL); - bool_obj->value = val; - BT_LOGD("Created boolean value object: addr=%p", bool_obj); - -end: - return (void *) BT_CTF_VALUE_FROM_CONCRETE(bool_obj); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void) -{ - return bt_ctf_private_value_bool_create_init(BT_FALSE); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(int64_t val) -{ - struct bt_ctf_value_integer *integer_obj; - - BT_LOGD("Creating integer value object: val=%" PRId64, val); - integer_obj = g_new0(struct bt_ctf_value_integer, 1); - if (!integer_obj) { - BT_LOGE_STR("Failed to allocate one integer value object."); - goto end; - } - - integer_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_INTEGER); - integer_obj->value = val; - BT_LOGD("Created integer value object: addr=%p", - integer_obj); - -end: - return (void *) BT_CTF_VALUE_FROM_CONCRETE(integer_obj); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void) -{ - return bt_ctf_private_value_integer_create_init(0); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val) -{ - struct bt_ctf_value_real *real_obj; - - BT_LOGD("Creating real number value object: val=%f", val); - real_obj = g_new0(struct bt_ctf_value_real, 1); - if (!real_obj) { - BT_LOGE_STR("Failed to allocate one real number value object."); - goto end; - } - - real_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_REAL); - real_obj->value = val; - BT_LOGD("Created real number value object: addr=%p", - real_obj); - -end: - return (void *) BT_CTF_VALUE_FROM_CONCRETE(real_obj); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_real_create(void) -{ - return bt_ctf_private_value_real_create_init(0.); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(const char *val) -{ - struct bt_ctf_value_string *string_obj = NULL; - - if (!val) { - BT_LOGW_STR("Invalid parameter: value is NULL."); - goto end; - } - - BT_LOGD("Creating string value object: val-len=%zu", strlen(val)); - string_obj = g_new0(struct bt_ctf_value_string, 1); - if (!string_obj) { - BT_LOGE_STR("Failed to allocate one string object."); - goto end; - } - - string_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_STRING); - string_obj->gstr = g_string_new(val); - if (!string_obj->gstr) { - BT_LOGE_STR("Failed to allocate a GString."); - g_free(string_obj); - string_obj = NULL; - goto end; - } - - BT_LOGD("Created string value object: addr=%p", - string_obj); - -end: - return (void *) BT_CTF_VALUE_FROM_CONCRETE(string_obj); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_string_create(void) -{ - return bt_ctf_private_value_string_create_init(""); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_array_create(void) -{ - struct bt_ctf_value_array *array_obj; - - BT_LOGD_STR("Creating empty array value object."); - array_obj = g_new0(struct bt_ctf_value_array, 1); - if (!array_obj) { - BT_LOGE_STR("Failed to allocate one array object."); - goto end; - } - - array_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_ARRAY); - array_obj->garray = bt_g_ptr_array_new_full(0, - (GDestroyNotify) bt_ctf_object_put_ref); - if (!array_obj->garray) { - BT_LOGE_STR("Failed to allocate a GPtrArray."); - g_free(array_obj); - array_obj = NULL; - goto end; - } - - BT_LOGD("Created array value object: addr=%p", - array_obj); - -end: - return (void *) BT_CTF_VALUE_FROM_CONCRETE(array_obj); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_map_create(void) -{ - struct bt_ctf_value_map *map_obj; - - BT_LOGD_STR("Creating empty map value object."); - map_obj = g_new0(struct bt_ctf_value_map, 1); - if (!map_obj) { - BT_LOGE_STR("Failed to allocate one map object."); - goto end; - } - - map_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_MAP); - map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) bt_ctf_object_put_ref); - if (!map_obj->ght) { - BT_LOGE_STR("Failed to allocate a GHashTable."); - g_free(map_obj); - map_obj = NULL; - goto end; - } - - BT_LOGD("Created map value object: addr=%p", - map_obj); - -end: - return (void *) BT_CTF_VALUE_FROM_CONCRETE(map_obj); -} - -BT_HIDDEN -bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj) -{ - BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL); - return BT_CTF_VALUE_TO_BOOL(bool_obj)->value; -} - -BT_HIDDEN -void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj, bt_bool val) -{ - BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL); - BT_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object"); - BT_CTF_VALUE_TO_BOOL(bool_obj)->value = val; - BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d", - bool_obj, val); -} - -BT_HIDDEN -int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj) -{ - BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER); - return BT_CTF_VALUE_TO_INTEGER(integer_obj)->value; -} - -BT_HIDDEN -void bt_ctf_private_value_integer_set(struct bt_ctf_private_value *integer_obj, - int64_t val) -{ - BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER); - BT_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object"); - BT_CTF_VALUE_TO_INTEGER(integer_obj)->value = val; - BT_LOGV("Set integer value's raw value: value-addr=%p, value=%" PRId64, - integer_obj, val); -} - -BT_HIDDEN -double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj) -{ - BT_ASSERT_PRE_NON_NULL(real_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL); - return BT_CTF_VALUE_TO_REAL(real_obj)->value; -} - -BT_HIDDEN -void bt_ctf_private_value_real_set(struct bt_ctf_private_value *real_obj, double val) -{ - BT_ASSERT_PRE_NON_NULL(real_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL); - BT_ASSERT_PRE_VALUE_HOT(real_obj, "Value object"); - BT_CTF_VALUE_TO_REAL(real_obj)->value = val; - BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f", - real_obj, val); -} - -BT_HIDDEN -const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj) -{ - BT_ASSERT_PRE_NON_NULL(string_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING); - return BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_string_set( - struct bt_ctf_private_value *string_obj, const char *val) -{ - BT_ASSERT_PRE_NON_NULL(string_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING); - BT_ASSERT_PRE_VALUE_HOT(string_obj, "Value object"); - g_string_assign(BT_CTF_VALUE_TO_STRING(string_obj)->gstr, val); - BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p", - string_obj, val); - return BT_CTF_VALUE_STATUS_OK; -} - -BT_HIDDEN -uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj) -{ - BT_ASSERT_PRE_NON_NULL(array_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); - return (uint64_t) BT_CTF_VALUE_TO_ARRAY(array_obj)->garray->len; -} - -BT_HIDDEN -struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index( - const struct bt_ctf_value *array_obj, - uint64_t index) -{ - struct bt_ctf_value_array *typed_array_obj = - BT_CTF_VALUE_TO_ARRAY(array_obj); - - BT_ASSERT_PRE_NON_NULL(array_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); - BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index, - typed_array_obj->garray->len); - return g_ptr_array_index(typed_array_obj->garray, index); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index( - const struct bt_ctf_private_value *array_obj, - uint64_t index) -{ - return (void *) bt_ctf_value_array_borrow_element_by_index( - (void *) array_obj, index); -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_append_element( - struct bt_ctf_private_value *array_obj, - struct bt_ctf_value *element_obj) -{ - struct bt_ctf_value_array *typed_array_obj = - BT_CTF_VALUE_TO_ARRAY(array_obj); - - BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object"); - BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); - BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object"); - g_ptr_array_add(typed_array_obj->garray, element_obj); - bt_ctf_object_get_ref(element_obj); - BT_LOGV("Appended element to array value: array-value-addr=%p, " - "element-value-addr=%p, new-size=%u", - array_obj, element_obj, typed_array_obj->garray->len); - return BT_CTF_VALUE_STATUS_OK; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element( - struct bt_ctf_private_value *array_obj, bt_bool val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *bool_obj = NULL; - - bool_obj = bt_ctf_private_value_bool_create_init(val); - ret = bt_ctf_private_value_array_append_element(array_obj, - (void *) bool_obj); - bt_ctf_object_put_ref(bool_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element( - struct bt_ctf_private_value *array_obj, int64_t val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *integer_obj = NULL; - - integer_obj = bt_ctf_private_value_integer_create_init(val); - ret = bt_ctf_private_value_array_append_element(array_obj, - (void *) integer_obj); - bt_ctf_object_put_ref(integer_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element( - struct bt_ctf_private_value *array_obj, double val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *real_obj = NULL; - - real_obj = bt_ctf_private_value_real_create_init(val); - ret = bt_ctf_private_value_array_append_element(array_obj, - (void *) real_obj); - bt_ctf_object_put_ref(real_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element( - struct bt_ctf_private_value *array_obj, const char *val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *string_obj = NULL; - - string_obj = bt_ctf_private_value_string_create_init(val); - ret = bt_ctf_private_value_array_append_element(array_obj, - (void *) string_obj); - bt_ctf_object_put_ref(string_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element( - struct bt_ctf_private_value *array_obj) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *empty_array_obj = NULL; - - empty_array_obj = bt_ctf_private_value_array_create(); - ret = bt_ctf_private_value_array_append_element(array_obj, - (void *) empty_array_obj); - bt_ctf_object_put_ref(empty_array_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element( - struct bt_ctf_private_value *array_obj) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *map_obj = NULL; - - map_obj = bt_ctf_private_value_map_create(); - ret = bt_ctf_private_value_array_append_element(array_obj, - (void *) map_obj); - bt_ctf_object_put_ref(map_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index( - struct bt_ctf_private_value *array_obj, uint64_t index, - struct bt_ctf_value *element_obj) -{ - struct bt_ctf_value_array *typed_array_obj = - BT_CTF_VALUE_TO_ARRAY(array_obj); - - BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object"); - BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY); - BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object"); - BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index, - typed_array_obj->garray->len); - bt_ctf_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index)); - g_ptr_array_index(typed_array_obj->garray, index) = element_obj; - bt_ctf_object_get_ref(element_obj); - BT_LOGV("Set array value's element: array-value-addr=%p, " - "index=%" PRIu64 ", element-value-addr=%p", - array_obj, index, element_obj); - return BT_CTF_VALUE_STATUS_OK; -} - -BT_HIDDEN -uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj) -{ - BT_ASSERT_PRE_NON_NULL(map_obj, "Value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); - return (uint64_t) g_hash_table_size(BT_CTF_VALUE_TO_MAP(map_obj)->ght); -} - -BT_HIDDEN -struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(const struct bt_ctf_value *map_obj, - const char *key) -{ - BT_ASSERT_PRE_NON_NULL(map_obj, "Value object"); - BT_ASSERT_PRE_NON_NULL(key, "Key"); - BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); - return g_hash_table_lookup(BT_CTF_VALUE_TO_MAP(map_obj)->ght, - GUINT_TO_POINTER(g_quark_from_string(key))); -} - -BT_HIDDEN -struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value( - const struct bt_ctf_private_value *map_obj, const char *key) -{ - return (void *) bt_ctf_value_map_borrow_entry_value((void *) map_obj, key); -} - -BT_HIDDEN -bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj, const char *key) -{ - BT_ASSERT_PRE_NON_NULL(map_obj, "Value object"); - BT_ASSERT_PRE_NON_NULL(key, "Key"); - BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); - return bt_g_hash_table_contains(BT_CTF_VALUE_TO_MAP(map_obj)->ght, - GUINT_TO_POINTER(g_quark_from_string(key))); -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry( - struct bt_ctf_private_value *map_obj, - const char *key, struct bt_ctf_value *element_obj) -{ - BT_ASSERT_PRE_NON_NULL(map_obj, "Map value object"); - BT_ASSERT_PRE_NON_NULL(key, "Key"); - BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object"); - BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); - BT_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object"); - g_hash_table_insert(BT_CTF_VALUE_TO_MAP(map_obj)->ght, - GUINT_TO_POINTER(g_quark_from_string(key)), element_obj); - bt_ctf_object_get_ref(element_obj); - BT_LOGV("Inserted value into map value: map-value-addr=%p, " - "key=\"%s\", element-value-addr=%p", - map_obj, key, element_obj); - return BT_CTF_VALUE_STATUS_OK; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry( - struct bt_ctf_private_value *map_obj, const char *key, bt_bool val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *bool_obj = NULL; - - bool_obj = bt_ctf_private_value_bool_create_init(val); - ret = bt_ctf_private_value_map_insert_entry(map_obj, key, - (void *) bool_obj); - bt_ctf_object_put_ref(bool_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry( - struct bt_ctf_private_value *map_obj, const char *key, int64_t val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *integer_obj = NULL; - - integer_obj = bt_ctf_private_value_integer_create_init(val); - ret = bt_ctf_private_value_map_insert_entry(map_obj, key, - (void *) integer_obj); - bt_ctf_object_put_ref(integer_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry( - struct bt_ctf_private_value *map_obj, const char *key, double val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *real_obj = NULL; - - real_obj = bt_ctf_private_value_real_create_init(val); - ret = bt_ctf_private_value_map_insert_entry(map_obj, key, - (void *) real_obj); - bt_ctf_object_put_ref(real_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry( - struct bt_ctf_private_value *map_obj, const char *key, - const char *val) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *string_obj = NULL; - - string_obj = bt_ctf_private_value_string_create_init(val); - ret = bt_ctf_private_value_map_insert_entry(map_obj, key, - (void *) string_obj); - bt_ctf_object_put_ref(string_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry( - struct bt_ctf_private_value *map_obj, const char *key) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *array_obj = NULL; - - array_obj = bt_ctf_private_value_array_create(); - ret = bt_ctf_private_value_map_insert_entry(map_obj, key, - (void *) array_obj); - bt_ctf_object_put_ref(array_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry( - struct bt_ctf_private_value *map_obj, const char *key) -{ - enum bt_ctf_value_status ret; - struct bt_ctf_private_value *empty_map_obj = NULL; - - empty_map_obj = bt_ctf_private_value_map_create(); - ret = bt_ctf_private_value_map_insert_entry(map_obj, key, - (void *) empty_map_obj); - bt_ctf_object_put_ref(empty_map_obj); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(const struct bt_ctf_value *map_obj, - bt_ctf_value_map_foreach_entry_cb cb, void *data) -{ - enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK; - gpointer key, element_obj; - GHashTableIter iter; - struct bt_ctf_value_map *typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj); - - BT_ASSERT_PRE_NON_NULL(map_obj, "Value object"); - BT_ASSERT_PRE_NON_NULL(cb, "Callback"); - BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP); - g_hash_table_iter_init(&iter, typed_map_obj->ght); - - while (g_hash_table_iter_next(&iter, &key, &element_obj)) { - const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key)); - - if (!cb(key_str, element_obj, data)) { - BT_LOGV("User canceled the loop: key=\"%s\", " - "value-addr=%p, data=%p", - key_str, element_obj, data); - ret = BT_CTF_VALUE_STATUS_CANCELED; - break; - } - } - - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry( - const struct bt_ctf_private_value *map_obj, - bt_ctf_private_value_map_foreach_entry_cb cb, void *data) -{ - return bt_ctf_value_map_foreach_entry((void *) map_obj, - (bt_ctf_value_map_foreach_entry_cb) cb, data); -} - -struct extend_map_element_data { - struct bt_ctf_private_value *extended_obj; - enum bt_ctf_value_status status; -}; - -static -bt_bool extend_map_element(const char *key, - struct bt_ctf_value *extension_obj_elem, void *data) -{ - bt_bool ret = BT_TRUE; - struct extend_map_element_data *extend_data = data; - struct bt_ctf_private_value *extension_obj_elem_copy = NULL; - - /* Copy object which is to replace the current one */ - extend_data->status = bt_ctf_value_copy(&extension_obj_elem_copy, - extension_obj_elem); - if (extend_data->status) { - BT_LOGE("Cannot copy map element: addr=%p", - extension_obj_elem); - goto error; - } - - BT_ASSERT(extension_obj_elem_copy); - - /* Replace in extended object */ - extend_data->status = bt_ctf_private_value_map_insert_entry( - extend_data->extended_obj, key, - (void *) extension_obj_elem_copy); - if (extend_data->status) { - BT_LOGE("Cannot replace value in extended value: key=\"%s\", " - "extended-value-addr=%p, element-value-addr=%p", - key, extend_data->extended_obj, - extension_obj_elem_copy); - goto error; - } - - goto end; - -error: - BT_ASSERT(extend_data->status != BT_CTF_VALUE_STATUS_OK); - ret = BT_FALSE; - -end: - BT_CTF_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy); - return ret; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_value_map_extend( - struct bt_ctf_private_value **extended_map_obj, - const struct bt_ctf_value *base_map_obj, - const struct bt_ctf_value *extension_obj) -{ - struct extend_map_element_data extend_data = { - .extended_obj = NULL, - .status = BT_CTF_VALUE_STATUS_OK, - }; - - BT_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object"); - BT_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object"); - BT_ASSERT_PRE_NON_NULL(extended_map_obj, - "Extended value object (output)"); - BT_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_CTF_VALUE_TYPE_MAP); - BT_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_CTF_VALUE_TYPE_MAP); - BT_LOGD("Extending map value: base-value-addr=%p, extension-value-addr=%p", - base_map_obj, extension_obj); - *extended_map_obj = NULL; - - /* Create copy of base map object to start with */ - extend_data.status = bt_ctf_value_copy(extended_map_obj, base_map_obj); - if (extend_data.status) { - BT_LOGE("Cannot copy base value: base-value-addr=%p", - base_map_obj); - goto error; - } - - BT_ASSERT(extended_map_obj); - - /* - * For each key in the extension map object, replace this key - * in the copied map object. - */ - extend_data.extended_obj = *extended_map_obj; - - if (bt_ctf_value_map_foreach_entry(extension_obj, extend_map_element, - &extend_data)) { - BT_LOGE("Cannot iterate on the extension object's elements: " - "extension-value-addr=%p", extension_obj); - goto error; - } - - if (extend_data.status) { - BT_LOGE("Failed to successfully iterate on the extension object's elements: " - "extension-value-addr=%p", extension_obj); - goto error; - } - - BT_LOGD("Extended map value: extended-value-addr=%p", - *extended_map_obj); - goto end; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(*extended_map_obj); - *extended_map_obj = NULL; - -end: - return extend_data.status; -} - -BT_HIDDEN -enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy_obj, - const struct bt_ctf_value *object) -{ - enum bt_ctf_value_status status = BT_CTF_VALUE_STATUS_OK; - - BT_ASSERT_PRE_NON_NULL(object, "Value object"); - BT_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)"); - BT_LOGD("Copying value object: addr=%p", object); - *copy_obj = copy_funcs[object->type](object); - if (*copy_obj) { - BT_LOGD("Copied value object: copy-value-addr=%p", - copy_obj); - } else { - status = BT_CTF_VALUE_STATUS_NOMEM; - *copy_obj = NULL; - BT_LOGE_STR("Failed to copy value object."); - } - - return status; -} - -BT_HIDDEN -bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a, - const struct bt_ctf_value *object_b) -{ - bt_bool ret = BT_FALSE; - - BT_ASSERT_PRE_NON_NULL(object_a, "Value object A"); - BT_ASSERT_PRE_NON_NULL(object_b, "Value object B"); - - if (object_a->type != object_b->type) { - BT_LOGV("Values are different: type mismatch: " - "value-a-addr=%p, value-b-addr=%p, " - "value-a-type=%d, value-b-type=%d", - object_a, object_b, object_a->type, object_b->type); - goto end; - } - - ret = compare_funcs[object_a->type](object_a, object_b); - -end: - return ret; -} diff --git a/lib/ctf-writer/visitor.c b/lib/ctf-writer/visitor.c deleted file mode 100644 index 707cc7a8..00000000 --- a/lib/ctf-writer/visitor.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * visitor.c - * - * Babeltrace CTF writer - Visitor - * - * Copyright 2016 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * 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 - -BT_HIDDEN -int bt_ctf_visitor_helper(struct bt_ctf_visitor_object *root, - bt_ctf_child_count_accessor child_counter, - bt_ctf_child_accessor child_accessor, - bt_ctf_child_visitor child_visitor, - bt_ctf_visitor visitor, - void *data) -{ - int ret, child_count, i; - - ret = visitor(root, data); - if (ret) { - goto end; - } - - child_count = child_counter(root->object); - if (child_count < 0) { - ret = child_count; - goto end; - } - - for (i = 0; i < child_count; i++) { - void *child; - - child = child_accessor(root->object, i); - if (!child) { - ret = -1; - goto end; - } - ret = child_visitor(child, visitor, data); - BT_CTF_OBJECT_PUT_REF_AND_RESET(child); - if (ret) { - goto end; - } - } -end: - return ret; -} - -enum bt_ctf_visitor_object_type bt_ctf_visitor_object_get_type( - struct bt_ctf_visitor_object *object) -{ - enum bt_ctf_visitor_object_type ret = BT_CTF_VISITOR_OBJECT_TYPE_UNKNOWN; - - if (!object) { - goto end; - } - - ret = object->type; -end: - return ret; -} - -void *bt_ctf_visitor_object_get_object(struct bt_ctf_visitor_object *object) -{ - void *ret = NULL; - - if (!object) { - goto end; - } - - ret = object->object; -end: - return ret; -} diff --git a/lib/ctf-writer/writer.c b/lib/ctf-writer/writer.c deleted file mode 100644 index e0215d33..00000000 --- a/lib/ctf-writer/writer.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * writer.c - * - * Babeltrace CTF Writer - * - * Copyright 2013, 2014 Jérémie Galarneau - * - * Author: Jérémie Galarneau - * - * 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. - */ - -#define BT_LOG_TAG "CTF-WRITER" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static -void bt_ctf_writer_destroy(struct bt_ctf_object *obj); - -static -int init_trace_packet_header(struct bt_ctf_trace *trace) -{ - int ret = 0; - struct bt_ctf_field_type *_uint32_t = - get_field_type(FIELD_TYPE_ALIAS_UINT32_T); - struct bt_ctf_field_type *_uint8_t = - get_field_type(FIELD_TYPE_ALIAS_UINT8_T); - struct bt_ctf_field_type *trace_packet_header_type = - bt_ctf_field_type_structure_create(); - struct bt_ctf_field_type *uuid_array_type = - bt_ctf_field_type_array_create(_uint8_t, 16); - - if (!trace_packet_header_type || !uuid_array_type) { - ret = -1; - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, - _uint32_t, "magic"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, - uuid_array_type, "uuid"); - if (ret) { - goto end; - } - - ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, - _uint32_t, "stream_id"); - if (ret) { - goto end; - } - - ret = bt_ctf_trace_set_packet_header_field_type(trace, - trace_packet_header_type); - if (ret) { - goto end; - } -end: - bt_ctf_object_put_ref(uuid_array_type); - bt_ctf_object_put_ref(_uint32_t); - bt_ctf_object_put_ref(_uint8_t); - bt_ctf_object_put_ref(trace_packet_header_type); - return ret; -} - -struct bt_ctf_writer *bt_ctf_writer_create(const char *path) -{ - int ret; - struct bt_ctf_writer *writer = NULL; - unsigned char uuid[16]; - char *metadata_path = NULL; - - if (!path) { - goto error; - } - - writer = g_new0(struct bt_ctf_writer, 1); - if (!writer) { - goto error; - } - - metadata_path = g_build_filename(path, "metadata", NULL); - - bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy); - writer->path = g_string_new(path); - if (!writer->path) { - goto error_destroy; - } - - writer->trace = bt_ctf_trace_create(); - if (!writer->trace) { - goto error_destroy; - } - - ret = init_trace_packet_header(writer->trace); - if (ret) { - goto error_destroy; - } - - /* Generate a UUID for this writer's trace */ - ret = bt_uuid_generate(uuid); - if (ret) { - BT_LOGE_STR("Cannot generate UUID for CTF writer's trace."); - goto error_destroy; - } - - ret = bt_ctf_trace_set_uuid(writer->trace, uuid); - if (ret) { - goto error_destroy; - } - - bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base); - bt_ctf_object_put_ref(writer->trace); - - /* Default to little-endian */ - ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE); - BT_ASSERT(ret == 0); - - /* Create trace directory if necessary and open a metadata file */ - if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) { - perror("g_mkdir_with_parents"); - goto error_destroy; - } - - writer->metadata_fd = open(metadata_path, - O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (writer->metadata_fd < 0) { - perror("open"); - goto error_destroy; - } - - g_free(metadata_path); - return writer; - -error_destroy: - BT_CTF_OBJECT_PUT_REF_AND_RESET(writer); -error: - g_free(metadata_path); - return writer; -} - -void bt_ctf_writer_destroy(struct bt_ctf_object *obj) -{ - struct bt_ctf_writer *writer; - - writer = container_of(obj, struct bt_ctf_writer, base); - bt_ctf_writer_flush_metadata(writer); - if (writer->path) { - g_string_free(writer->path, TRUE); - } - - if (writer->metadata_fd > 0) { - if (close(writer->metadata_fd)) { - perror("close"); - } - } - - bt_ctf_object_try_spec_release(&writer->trace->common.base); - g_free(writer); -} - -struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer) -{ - struct bt_ctf_trace *trace = NULL; - - if (!writer) { - goto end; - } - - trace = writer->trace; - bt_ctf_object_get_ref(trace); -end: - return trace; -} - -struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, - struct bt_ctf_stream_class *stream_class) -{ - struct bt_ctf_stream *stream = NULL; - int stream_class_count; - bt_bool stream_class_found = BT_FALSE; - int i; - - if (!writer || !stream_class) { - goto error; - } - - /* Make sure the stream class is part of the writer's trace */ - stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace); - if (stream_class_count < 0) { - goto error; - } - - for (i = 0; i < stream_class_count; i++) { - struct bt_ctf_stream_class *existing_stream_class = - bt_ctf_trace_get_stream_class_by_index( - writer->trace, i); - - if (existing_stream_class == stream_class) { - stream_class_found = BT_TRUE; - } - - BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class); - - if (stream_class_found) { - break; - } - } - - if (!stream_class_found) { - int ret = bt_ctf_trace_add_stream_class(writer->trace, - stream_class); - - if (ret) { - goto error; - } - } - - stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL); - if (!stream) { - goto error; - } - - return stream; - -error: - BT_CTF_OBJECT_PUT_REF_AND_RESET(stream); - return stream; -} - -int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer, - const char *name, - const char *value) -{ - int ret = -1; - - if (!writer || !name || !value) { - goto end; - } - - ret = bt_ctf_trace_set_environment_field_string(writer->trace, - name, value); -end: - return ret; -} - -int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer, - const char *name, int64_t value) -{ - int ret = -1; - - if (!writer || !name) { - goto end; - } - - ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name, - value); -end: - return ret; -} - -int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer, - struct bt_ctf_clock *clock) -{ - int ret = -1; - - if (!writer || !clock) { - goto end; - } - - ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class); -end: - return ret; -} - -char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer) -{ - char *metadata_string = NULL; - - if (!writer) { - goto end; - } - - metadata_string = bt_ctf_trace_get_metadata_string( - writer->trace); -end: - return metadata_string; -} - -void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer) -{ - int ret; - char *metadata_string = NULL; - - if (!writer) { - goto end; - } - - metadata_string = bt_ctf_trace_get_metadata_string( - writer->trace); - if (!metadata_string) { - goto end; - } - - if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) { - perror("lseek"); - goto end; - } - - if (ftruncate(writer->metadata_fd, 0)) { - perror("ftruncate"); - goto end; - } - - ret = write(writer->metadata_fd, metadata_string, - strlen(metadata_string)); - if (ret < 0) { - perror("write"); - goto end; - } -end: - g_free(metadata_string); -} - -int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, - enum bt_ctf_byte_order byte_order) -{ - int ret = 0; - - if (!writer || writer->frozen) { - ret = -1; - goto end; - } - - if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { - if (BYTE_ORDER == LITTLE_ENDIAN) { - byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN; - } else { - byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN; - } - } - - ret = bt_ctf_trace_set_native_byte_order(writer->trace, - byte_order); -end: - return ret; -} - -BT_HIDDEN -void bt_ctf_writer_freeze(struct bt_ctf_writer *writer) -{ - writer->frozen = 1; -} - -static -const unsigned int field_type_aliases_alignments[] = { - [FIELD_TYPE_ALIAS_UINT5_T] = 1, - [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8, - [FIELD_TYPE_ALIAS_UINT27_T] = 1, - [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8, -}; - -static -const unsigned int field_type_aliases_sizes[] = { - [FIELD_TYPE_ALIAS_UINT5_T] = 5, - [FIELD_TYPE_ALIAS_UINT8_T] = 8, - [FIELD_TYPE_ALIAS_UINT16_T] = 16, - [FIELD_TYPE_ALIAS_UINT27_T] = 27, - [FIELD_TYPE_ALIAS_UINT32_T] = 32, - [FIELD_TYPE_ALIAS_UINT64_T] = 64, -}; - -BT_HIDDEN -struct bt_ctf_field_type *get_field_type(enum field_type_alias alias) -{ - int ret; - unsigned int alignment, size; - struct bt_ctf_field_type *field_type = NULL; - - if (alias >= NR_FIELD_TYPE_ALIAS) { - goto end; - } - - alignment = field_type_aliases_alignments[alias]; - size = field_type_aliases_sizes[alias]; - field_type = bt_ctf_field_type_integer_create(size); - ret = bt_ctf_field_type_set_alignment(field_type, alignment); - if (ret) { - BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type); - } -end: - return field_type; -} - -BT_HIDDEN -const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order) -{ - const char *string; - - switch (byte_order) { - case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: - string = "le"; - break; - case BT_CTF_BYTE_ORDER_BIG_ENDIAN: - string = "be"; - break; - case BT_CTF_BYTE_ORDER_NATIVE: - string = "native"; - break; - default: - abort(); - } - - return string; -} diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index 4ef581b2..9cb75b00 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -7,21 +7,23 @@ LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la libtestcommon_la_SOURCES = common.c common.h noinst_LTLIBRARIES = libtestcommon.la -# -Wl,--no-as-needed is needed for recent gold linker who seems to think -# it knows better and considers libraries with constructors having -# side-effects as dead code. -COMMON_TEST_LDADD = $(LIBTAP) $(builddir)/libtestcommon.la \ - $(top_builddir)/lib/libbabeltrace2.la +COMMON_TEST_LDADD = $(LIBTAP) $(builddir)/libtestcommon.la test_bitfield_LDADD = $(LIBTAP) $(builddir)/libtestcommon.la -test_ctf_writer_LDADD = $(COMMON_TEST_LDADD) +test_ctf_writer_LDADD = \ + $(COMMON_TEST_LDADD) \ + $(top_builddir)/ctf-writer/libbabeltrace2-ctf-writer.la -test_bt_values_LDADD = $(COMMON_TEST_LDADD) +test_bt_values_LDADD = $(COMMON_TEST_LDADD) \ + $(top_builddir)/lib/libbabeltrace2.la -test_trace_ir_ref_LDADD = $(COMMON_TEST_LDADD) +test_trace_ir_ref_LDADD = $(COMMON_TEST_LDADD) \ + $(top_builddir)/lib/libbabeltrace2.la \ + $(top_builddir)/ctf-writer/libbabeltrace2-ctf-writer.la -test_graph_topo_LDADD = $(COMMON_TEST_LDADD) +test_graph_topo_LDADD = $(COMMON_TEST_LDADD) \ + $(top_builddir)/lib/libbabeltrace2.la noinst_PROGRAMS = test_bitfield test_ctf_writer test_bt_values \ test_trace_ir_ref test_graph_topo @@ -34,7 +36,8 @@ test_graph_topo_SOURCES = test_graph_topo.c if !ENABLE_BUILT_IN_PLUGINS noinst_PROGRAMS += test_plugin -test_plugin_LDADD = $(COMMON_TEST_LDADD) +test_plugin_LDADD = $(COMMON_TEST_LDADD) \ + $(top_builddir)/lib/libbabeltrace2.la test_plugin_SOURCES = test_plugin.c SUBDIRS += test-plugin-plugins endif diff --git a/tests/lib/test_trace_ir_ref.c b/tests/lib/test_trace_ir_ref.c index f4837c90..99a1d374 100644 --- a/tests/lib/test_trace_ir_ref.c +++ b/tests/lib/test_trace_ir_ref.c @@ -24,6 +24,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "common.h" #define NR_TESTS 37