* SOFTWARE.
*/
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRANSLATE-TRACE-IR-TO-CTF-IR"
-#include "logging.h"
+#define BT_COMP_LOG_SELF_COMP (ctx->self_comp)
+#define BT_LOG_OUTPUT_LEVEL (ctx->log_level)
+#define BT_LOG_TAG "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"
+#include "logging/comp-logging.h"
#include <babeltrace2/babeltrace.h>
#include "common/macros.h"
#include <string.h>
#include <glib.h>
+#include "fs-sink.h"
#include "fs-sink-ctf-meta.h"
struct field_path_elem {
};
struct ctx {
+ bt_logging_level log_level;
+ bt_self_component *self_comp;
+
/* Weak */
struct fs_sink_ctf_stream_class *cur_sc;
/* Weak */
struct fs_sink_ctf_event_class *cur_ec;
- bt_scope cur_scope;
+ bt_field_path_scope cur_scope;
/*
* Array of `struct field_path_elem` */
return is_reserved;
}
+static const char *reserved_tsdl_keywords[] = {
+ "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 inline
+bool ist_valid_identifier(const char *name)
+{
+ const char *at;
+ uint64_t i;
+ bool ist_valid = true;
+
+ /* Make sure the name is not a reserved keyword */
+ for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords);
+ i++) {
+ if (strcmp(name, reserved_tsdl_keywords[i]) == 0) {
+ ist_valid = false;
+ goto end;
+ }
+ }
+
+ /* Make sure the name is not an empty string */
+ if (strlen(name) == 0) {
+ ist_valid = false;
+ goto end;
+ }
+
+ /* Make sure the name starts with a letter or `_` */
+ if (!isalpha(name[0]) && name[0] != '_') {
+ ist_valid = false;
+ goto end;
+ }
+
+ /* Make sure the name only contains letters, digits, and `_` */
+ for (at = name; *at != '\0'; at++) {
+ if (!isalnum(*at) && *at != '_') {
+ ist_valid = false;
+ goto end;
+ }
+ }
+
+end:
+ return ist_valid;
+}
+
+static inline
+bool must_protect_identifier(const char *name)
+{
+ uint64_t i;
+ bool must_protect = false;
+
+ /* Protect a reserved keyword */
+ for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords);
+ i++) {
+ if (strcmp(name, reserved_tsdl_keywords[i]) == 0) {
+ must_protect = true;
+ goto end;
+ }
+ }
+
+ /* Protect an identifier which already starts with `_` */
+ if (name[0] == '_') {
+ must_protect = true;
+ goto end;
+ }
+
+end:
+ return must_protect;
+}
+
static inline
int cur_path_stack_push(struct ctx *ctx,
- uint64_t index_in_parent, const char *ir_name,
- const bt_field_class *ir_fc,
+ uint64_t index_in_parent, const char *name,
+ bool force_protect_name, const bt_field_class *ir_fc,
struct fs_sink_ctf_field_class *parent_fc)
{
int ret = 0;
g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1);
field_path_elem = cur_path_stack_top(ctx);
field_path_elem->index_in_parent = index_in_parent;
- field_path_elem->name = g_string_new(ir_name);
-
- if (ir_name) {
- if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) {
- if (is_reserved_member_name(ir_name, "packet_size") ||
- is_reserved_member_name(ir_name, "content_size") ||
- is_reserved_member_name(ir_name, "timestamp_begin") ||
- is_reserved_member_name(ir_name, "timestamp_end") ||
- is_reserved_member_name(ir_name, "events_discarded") ||
- is_reserved_member_name(ir_name, "packet_seq_num")) {
- BT_LOGE("Unsupported reserved TSDL structure field class member "
+ field_path_elem->name = g_string_new(NULL);
+
+ if (name) {
+ if (force_protect_name) {
+ g_string_assign(field_path_elem->name, "_");
+ }
+
+ g_string_append(field_path_elem->name, name);
+
+ if (ctx->cur_scope == BT_FIELD_PATH_SCOPE_PACKET_CONTEXT) {
+ if (is_reserved_member_name(name, "packet_size") ||
+ is_reserved_member_name(name, "content_size") ||
+ is_reserved_member_name(name, "timestamp_begin") ||
+ is_reserved_member_name(name, "timestamp_end") ||
+ is_reserved_member_name(name, "events_discarded") ||
+ is_reserved_member_name(name, "packet_seq_num")) {
+ BT_COMP_LOGE("Unsupported reserved TSDL structure field class member "
"or variant field class option name: name=\"%s\"",
- ir_name);
+ name);
ret = -1;
goto end;
}
}
- ret = fs_sink_ctf_protect_name(field_path_elem->name);
- if (ret) {
- BT_LOGE("Unsupported non-TSDL structure field class member "
+ if (!ist_valid_identifier(field_path_elem->name->str)) {
+ ret = -1;
+ BT_COMP_LOGE("Unsupported non-TSDL structure field class member "
"or variant field class option name: name=\"%s\"",
- ir_name);
+ field_path_elem->name->str);
goto end;
}
}
*/
static
int create_relative_field_ref(struct ctx *ctx,
- const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
+ const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
+ struct fs_sink_ctf_field_class **user_tgt_fc)
{
int ret = 0;
struct fs_sink_ctf_field_class *tgt_fc = NULL;
/* Get target field class's name */
switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
- case BT_SCOPE_PACKET_CONTEXT:
+ case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
BT_ASSERT(ctx->cur_sc);
tgt_fc = ctx->cur_sc->packet_context_fc;
break;
- case BT_SCOPE_EVENT_COMMON_CONTEXT:
+ case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
BT_ASSERT(ctx->cur_sc);
tgt_fc = ctx->cur_sc->event_common_context_fc;
break;
- case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+ case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
BT_ASSERT(ctx->cur_ec);
tgt_fc = ctx->cur_ec->spec_context_fc;
break;
- case BT_SCOPE_EVENT_PAYLOAD:
+ case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
BT_ASSERT(ctx->cur_ec);
tgt_fc = ctx->cur_ec->payload_fc;
break;
BT_ASSERT(tgt_fc);
BT_ASSERT(fp_item);
+ if (bt_field_path_item_get_type(fp_item) ==
+ BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT) {
+ /* Not supported by CTF 1.8 */
+ ret = -1;
+ goto end;
+ }
+
switch (tgt_fc->type) {
case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
/* Find target field class having this name in current context */
for (si = ctx->cur_path->len - 1; si >= 0; si--) {
struct fs_sink_ctf_field_class *fc;
- struct fs_sink_ctf_field_class_struct *struct_fc;
- struct fs_sink_ctf_field_class_variant *var_fc;
+ struct fs_sink_ctf_field_class_struct *struct_fc = NULL;
+ struct fs_sink_ctf_field_class_variant *var_fc = NULL;
struct fs_sink_ctf_named_field_class *named_fc;
uint64_t len;
if (named_fc->fc == tgt_fc) {
g_string_assign(tgt_field_ref,
tgt_fc_name);
+
+ if (user_tgt_fc) {
+ *user_tgt_fc = tgt_fc;
+ }
} else {
/*
* Using only the target field
*/
static
int create_absolute_field_ref(struct ctx *ctx,
- const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
+ const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
+ struct fs_sink_ctf_field_class **user_tgt_fc)
{
int ret = 0;
struct fs_sink_ctf_field_class *fc = NULL;
uint64_t i;
switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
- case BT_SCOPE_PACKET_CONTEXT:
+ case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT:
BT_ASSERT(ctx->cur_sc);
fc = ctx->cur_sc->packet_context_fc;
g_string_assign(tgt_field_ref, "stream.packet.context");
break;
- case BT_SCOPE_EVENT_COMMON_CONTEXT:
+ case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT:
BT_ASSERT(ctx->cur_sc);
fc = ctx->cur_sc->event_common_context_fc;
g_string_assign(tgt_field_ref, "stream.event.context");
break;
- case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+ case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT:
BT_ASSERT(ctx->cur_ec);
fc = ctx->cur_ec->spec_context_fc;
g_string_assign(tgt_field_ref, "event.context");
break;
- case BT_SCOPE_EVENT_PAYLOAD:
+ case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD:
BT_ASSERT(ctx->cur_ec);
fc = ctx->cur_ec->payload_fc;
g_string_assign(tgt_field_ref, "event.fields");
fc = named_fc->fc;
}
+ if (user_tgt_fc) {
+ *user_tgt_fc = fc;
+ }
+
end:
return ret;
}
static
void resolve_field_class(struct ctx *ctx,
const bt_field_path *tgt_ir_field_path,
- GString *tgt_field_ref, bool *create_before)
+ GString *tgt_field_ref, bool *create_before,
+ struct fs_sink_ctf_field_class **user_tgt_fc)
{
int ret;
- bt_scope tgt_scope;
+ bt_field_path_scope tgt_scope;
*create_before = false;
* requesting field class (fallback).
*/
ret = create_relative_field_ref(ctx, tgt_ir_field_path,
- tgt_field_ref);
+ tgt_field_ref, user_tgt_fc);
if (ret) {
ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
- tgt_field_ref);
+ tgt_field_ref, user_tgt_fc);
if (ret) {
*create_before = true;
ret = 0;
}
} else {
ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
- tgt_field_ref);
+ tgt_field_ref, user_tgt_fc);
/* It must always work in previous scopes */
BT_ASSERT(ret == 0);
fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
cur_path_stack_top(ctx)->name->str, fc);
break;
+ case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
+ {
+ struct fs_sink_ctf_field_class_option *opt_fc =
+ (void *) parent_fc;
+
+ BT_ASSERT(!opt_fc->content_fc);
+ opt_fc->content_fc = fc;
+ opt_fc->base.alignment = fc->alignment;
+ break;
+ }
case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
cur_path_stack_top(ctx)->name->str, fc);
name = bt_field_class_structure_member_get_name(member);
memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
member);
- ret = cur_path_stack_push(ctx, i, name, memb_ir_fc,
+ ret = cur_path_stack_push(ctx, i, name, true, memb_ir_fc,
(void *) struct_fc);
if (ret) {
- BT_LOGE("Cannot translate structure field class member: "
+ BT_COMP_LOGE("Cannot translate structure field class member: "
"name=\"%s\"", name);
goto end;
}
ret = translate_field_class(ctx);
if (ret) {
- BT_LOGE("Cannot translate structure field class member: "
+ BT_COMP_LOGE("Cannot translate structure field class member: "
"name=\"%s\"", name);
goto end;
}
return ret;
}
+/*
+ * This function protects a given variant FC option name (with the `_`
+ * prefix) if required. On success, `name_buf->str` contains the variant
+ * FC option name to use (original option name or protected if
+ * required).
+ *
+ * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as
+ * close as possible to an original CTF trace as decoded by
+ * `src.ctf.fs`.
+ *
+ * This scenario is valid in CTF 1.8:
+ *
+ * enum {
+ * HELLO,
+ * MEOW
+ * } tag;
+ *
+ * variant <tag> {
+ * int HELLO;
+ * string MEOW;
+ * };
+ *
+ * Once in trace IR, the enumeration FC mapping names and variant FC
+ * option names are kept as is. For this reason, we don't want to
+ * protect the variant FC option names here (by prepending `_`): this
+ * would make the variant FC option name and the enumeration FC mapping
+ * name not match.
+ *
+ * This scenario is also valid in CTF 1.8:
+ *
+ * enum {
+ * _HELLO,
+ * MEOW
+ * } tag;
+ *
+ * variant <tag> {
+ * int _HELLO;
+ * string MEOW;
+ * };
+ *
+ * Once in trace IR, the enumeration FC mapping names are kept as is,
+ * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected
+ * for presentation, as recommended by CTF 1.8). When going back to
+ * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match
+ * the corresponding enumeration FC mapping name.
+ *
+ * This scenario is also valid in CTF 1.8:
+ *
+ * enum {
+ * __HELLO,
+ * MEOW
+ * } tag;
+ *
+ * variant <tag> {
+ * int __HELLO;
+ * string MEOW;
+ * };
+ *
+ * Once in trace IR, the enumeration FC mapping names are kept as is,
+ * but the `__HELLO` variant FC option name becomes `_HELLO`
+ * (unprotected). When going back to TSDL, we need to protect `_HELLO`
+ * so that it becomes `__HELLO` to match the corresponding enumeration
+ * FC mapping name.
+ *
+ * `src.ctf.fs` always uses the _same_ integer range sets for a selector
+ * FC mapping and a corresponding variant FC option. We can use that
+ * fact to find the original variant FC option names by matching variant
+ * FC options and enumeration FC mappings by range set.
+ */
+static
+int maybe_protect_variant_option_name(const bt_field_class *ir_var_fc,
+ const bt_field_class *ir_tag_fc, uint64_t opt_i,
+ GString *name_buf)
+{
+ int ret = 0;
+ uint64_t i;
+ bt_field_class_type ir_var_fc_type;
+ const void *opt_ranges = NULL;
+ const char *mapping_label = NULL;
+ const char *ir_opt_name;
+ const bt_field_class_variant_option *base_var_opt;
+ bool force_protect = false;
+
+ ir_var_fc_type = bt_field_class_get_type(ir_var_fc);
+ base_var_opt = bt_field_class_variant_borrow_option_by_index_const(
+ ir_var_fc, opt_i);
+ BT_ASSERT(base_var_opt);
+ ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt);
+ BT_ASSERT(ir_opt_name);
+
+ /*
+ * Check if the variant FC option name is required to be
+ * protected (reserved TSDL keyword or starts with `_`). In that
+ * case, the name of the selector FC mapping we find must match
+ * exactly the protected name.
+ */
+ force_protect = must_protect_identifier(ir_opt_name);
+ if (force_protect) {
+ g_string_assign(name_buf, "_");
+ g_string_append(name_buf, ir_opt_name);
+ } else {
+ g_string_assign(name_buf, ir_opt_name);
+ }
+
+ /* Borrow option's ranges */
+ if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR) {
+ /* No ranges: we're done */
+ goto end;
+ } if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR) {
+ const bt_field_class_variant_with_selector_integer_unsigned_option *var_opt =
+ bt_field_class_variant_with_selector_integer_unsigned_borrow_option_by_index_const(
+ ir_var_fc, opt_i);
+ opt_ranges =
+ bt_field_class_variant_with_selector_integer_unsigned_option_borrow_ranges_const(
+ var_opt);
+ } else {
+ const bt_field_class_variant_with_selector_integer_signed_option *var_opt =
+ bt_field_class_variant_with_selector_integer_signed_borrow_option_by_index_const(
+ ir_var_fc, opt_i);
+ opt_ranges =
+ bt_field_class_variant_with_selector_integer_signed_option_borrow_ranges_const(
+ var_opt);
+ }
+
+ /* Find corresponding mapping by range set in selector FC */
+ for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_tag_fc);
+ i++) {
+ if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR) {
+ const bt_field_class_enumeration_mapping *mapping_base;
+ const bt_field_class_enumeration_unsigned_mapping *mapping;
+ const bt_integer_range_set_unsigned *mapping_ranges;
+
+ mapping = bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(
+ ir_tag_fc, i);
+ mapping_ranges = bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(
+ mapping);
+
+ if (bt_integer_range_set_unsigned_is_equal(opt_ranges,
+ mapping_ranges)) {
+ /* We have a winner */
+ mapping_base =
+ bt_field_class_enumeration_unsigned_mapping_as_mapping_const(
+ mapping);
+ mapping_label =
+ bt_field_class_enumeration_mapping_get_label(
+ mapping_base);
+ break;
+ }
+ } else {
+ const bt_field_class_enumeration_mapping *mapping_base;
+ const bt_field_class_enumeration_signed_mapping *mapping;
+ const bt_integer_range_set_signed *mapping_ranges;
+
+ mapping = bt_field_class_enumeration_signed_borrow_mapping_by_index_const(
+ ir_tag_fc, i);
+ mapping_ranges = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(
+ mapping);
+
+ if (bt_integer_range_set_signed_is_equal(opt_ranges,
+ mapping_ranges)) {
+ /* We have a winner */
+ mapping_base =
+ bt_field_class_enumeration_signed_mapping_as_mapping_const(
+ mapping);
+ mapping_label =
+ bt_field_class_enumeration_mapping_get_label(
+ mapping_base);
+ break;
+ }
+ }
+ }
+
+ if (!mapping_label) {
+ /* Range set not found: invalid selector for CTF 1.8 */
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * If the enumeration FC mapping name is not the same as the
+ * variant FC option name and we didn't protect already, try
+ * protecting the option name and check again.
+ */
+ if (strcmp(mapping_label, name_buf->str) != 0) {
+ if (force_protect) {
+ ret = -1;
+ goto end;
+ }
+
+ if (mapping_label[0] == '\0') {
+ ret = -1;
+ goto end;
+ }
+
+ g_string_assign(name_buf, "_");
+ g_string_append(name_buf, ir_opt_name);
+
+ if (strcmp(mapping_label, name_buf->str) != 0) {
+ ret = -1;
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+static inline
+int translate_option_field_class(struct ctx *ctx)
+{
+ struct fs_sink_ctf_field_class_option *fc =
+ fs_sink_ctf_field_class_option_create_empty(
+ cur_path_stack_top(ctx)->ir_fc,
+ cur_path_stack_top(ctx)->index_in_parent);
+ const bt_field_class *content_ir_fc =
+ bt_field_class_option_borrow_field_class_const(fc->base.ir_fc);
+ int ret;
+
+ BT_ASSERT(fc);
+
+ /*
+ * CTF 1.8 does not support the option field class type. To
+ * write something anyway, this component translates this type
+ * to a variant field class where the options are:
+ *
+ * * An empty structure field class.
+ * * The optional field class itself.
+ *
+ * The "tag" is always generated/before in that case (an 8-bit
+ * unsigned enumeration field class).
+ */
+ append_to_parent_field_class(ctx, (void *) fc);
+ ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, content_ir_fc,
+ (void *) fc);
+ if (ret) {
+ BT_COMP_LOGE_STR("Cannot translate option field class content.");
+ goto end;
+ }
+
+ ret = translate_field_class(ctx);
+ if (ret) {
+ BT_COMP_LOGE_STR("Cannot translate option field class content.");
+ goto end;
+ }
+
+ cur_path_stack_pop(ctx);
+ update_parent_field_class_alignment(ctx, fc->base.alignment);
+
+end:
+ return ret;
+}
+
static inline
int translate_variant_field_class(struct ctx *ctx)
{
fs_sink_ctf_field_class_variant_create_empty(
cur_path_stack_top(ctx)->ir_fc,
cur_path_stack_top(ctx)->index_in_parent);
+ bt_field_class_type ir_fc_type;
+ const bt_field_path *ir_selector_field_path = NULL;
+ struct fs_sink_ctf_field_class *tgt_fc = NULL;
+ GString *name_buf = g_string_new(NULL);
+ bt_value *prot_opt_names = bt_value_array_create();
+ uint64_t opt_count;
BT_ASSERT(fc);
+ BT_ASSERT(name_buf);
+ BT_ASSERT(prot_opt_names);
+ ir_fc_type = bt_field_class_get_type(fc->base.ir_fc);
+ opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc);
+
+ if (ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR ||
+ ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR) {
+ ir_selector_field_path = bt_field_class_variant_with_selector_borrow_selector_field_path_const(
+ fc->base.ir_fc);
+ BT_ASSERT(ir_selector_field_path);
+ }
/* Resolve tag field class before appending to parent */
- resolve_field_class(ctx,
- bt_field_class_variant_borrow_selector_field_path_const(
- fc->base.ir_fc), fc->tag_ref, &fc->tag_is_before);
+ resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref,
+ &fc->tag_is_before, &tgt_fc);
+
+ if (ir_selector_field_path && tgt_fc) {
+ uint64_t mapping_count;
+ uint64_t option_count;
+
+ /* CTF 1.8: selector FC must be an enumeration FC */
+ bt_field_class_type type = bt_field_class_get_type(
+ tgt_fc->ir_fc);
+
+ if (type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION &&
+ type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
+ fc->tag_is_before = true;
+ goto validate_opts;
+ }
+
+ /*
+ * Call maybe_protect_variant_option_name() for each
+ * option below. In that case we also want selector FC
+ * to contain as many mappings as the variant FC has
+ * options.
+ */
+ mapping_count = bt_field_class_enumeration_get_mapping_count(
+ tgt_fc->ir_fc);
+ option_count = bt_field_class_variant_get_option_count(
+ fc->base.ir_fc);
+
+ if (mapping_count != option_count) {
+ fc->tag_is_before = true;
+ goto validate_opts;
+ }
+ } else {
+ /*
+ * No compatible selector field class for CTF 1.8:
+ * create the appropriate selector field class.
+ */
+ fc->tag_is_before = true;
+ goto validate_opts;
+ }
+
+validate_opts:
+ /*
+ * First pass: detect any option name clash with option name
+ * protection. In that case, we don't fail: just create the
+ * selector field class before the variant field class.
+ *
+ * After this, `prot_opt_names` contains the final option names,
+ * potentially protected if needed. They can still be invalid
+ * TSDL identifiers however; this will be checked by
+ * cur_path_stack_push().
+ */
+ for (i = 0; i < opt_count; i++) {
+ if (!fc->tag_is_before) {
+ BT_ASSERT(tgt_fc->ir_fc);
+ ret = maybe_protect_variant_option_name(fc->base.ir_fc,
+ tgt_fc->ir_fc, i, name_buf);
+ if (ret) {
+ fc->tag_is_before = true;
+ }
+ }
+
+ ret = bt_value_array_append_string_element(prot_opt_names,
+ name_buf->str);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ for (i = 0; i < opt_count; i++) {
+ uint64_t j;
+ const bt_value *opt_name_a =
+ bt_value_array_borrow_element_by_index_const(
+ prot_opt_names, i);
+
+ for (j = 0; j < opt_count; j++) {
+ const bt_value *opt_name_b;
+
+ if (i == j) {
+ continue;
+ }
+
+ opt_name_b =
+ bt_value_array_borrow_element_by_index_const(
+ prot_opt_names, j);
+ if (bt_value_is_equal(opt_name_a, opt_name_b)) {
+ /*
+ * Variant FC option names are not
+ * unique when protected.
+ */
+ fc->tag_is_before = true;
+ goto append_to_parent;
+ }
+ }
+ }
+append_to_parent:
append_to_parent_field_class(ctx, (void *) fc);
- for (i = 0; i < bt_field_class_variant_get_option_count(fc->base.ir_fc);
- i++) {
+ for (i = 0; i < opt_count; i++) {
const bt_field_class_variant_option *opt;
- const char *name;
const bt_field_class *opt_ir_fc;
+ const bt_value *prot_opt_name_val =
+ bt_value_array_borrow_element_by_index_const(
+ prot_opt_names, i);
+ const char *prot_opt_name = bt_value_string_get(
+ prot_opt_name_val);
+ BT_ASSERT(prot_opt_name);
opt = bt_field_class_variant_borrow_option_by_index_const(
fc->base.ir_fc, i);
- name = bt_field_class_variant_option_get_name(opt);
opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
opt);
- ret = cur_path_stack_push(ctx, i, name, opt_ir_fc, (void *) fc);
+
+ /*
+ * We don't ask cur_path_stack_push() to protect the
+ * option name because it's already protected at this
+ * point.
+ */
+ ret = cur_path_stack_push(ctx, i, prot_opt_name, false,
+ opt_ir_fc, (void *) fc);
if (ret) {
- BT_LOGE("Cannot translate variant field class option: "
- "name=\"%s\"", name);
+ BT_COMP_LOGE("Cannot translate variant field class option: "
+ "name=\"%s\"", prot_opt_name);
goto end;
}
ret = translate_field_class(ctx);
if (ret) {
- BT_LOGE("Cannot translate variant field class option: "
- "name=\"%s\"", name);
+ BT_COMP_LOGE("Cannot translate variant field class option: "
+ "name=\"%s\"", prot_opt_name);
goto end;
}
}
end:
+ if (name_buf) {
+ g_string_free(name_buf, TRUE);
+ }
+
+ bt_value_put_ref(prot_opt_names);
return ret;
}
BT_ASSERT(fc);
append_to_parent_field_class(ctx, (void *) fc);
- ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
+ ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
(void *) fc);
if (ret) {
- BT_LOGE_STR("Cannot translate static array field class element.");
+ BT_COMP_LOGE_STR("Cannot translate static array field class element.");
goto end;
}
ret = translate_field_class(ctx);
if (ret) {
- BT_LOGE_STR("Cannot translate static array field class element.");
+ BT_COMP_LOGE_STR("Cannot translate static array field class element.");
goto end;
}
BT_ASSERT(fc);
/* Resolve length field class before appending to parent */
- resolve_field_class(ctx,
- bt_field_class_dynamic_array_borrow_length_field_path_const(
- fc->base.base.ir_fc),
- fc->length_ref, &fc->length_is_before);
+ if (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc) ==
+ BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) {
+ resolve_field_class(ctx,
+ bt_field_class_array_dynamic_with_length_field_borrow_length_field_path_const(
+ fc->base.base.ir_fc),
+ fc->length_ref, &fc->length_is_before, NULL);
+ }
append_to_parent_field_class(ctx, (void *) fc);
- ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
+ ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc,
(void *) fc);
if (ret) {
- BT_LOGE_STR("Cannot translate dynamic array field class element.");
+ BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
goto end;
}
ret = translate_field_class(ctx);
if (ret) {
- BT_LOGE_STR("Cannot translate dynamic array field class element.");
+ BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
goto end;
}
return ret;
}
+static inline
+int translate_bool_field_class(struct ctx *ctx)
+{
+ struct fs_sink_ctf_field_class_bool *fc =
+ fs_sink_ctf_field_class_bool_create(
+ cur_path_stack_top(ctx)->ir_fc,
+ cur_path_stack_top(ctx)->index_in_parent);
+
+ BT_ASSERT(fc);
+ append_to_parent_field_class(ctx, (void *) fc);
+ return 0;
+}
+
+static inline
+int translate_bit_array_field_class(struct ctx *ctx)
+{
+ struct fs_sink_ctf_field_class_bit_array *fc =
+ fs_sink_ctf_field_class_bit_array_create(
+ cur_path_stack_top(ctx)->ir_fc,
+ cur_path_stack_top(ctx)->index_in_parent);
+
+ BT_ASSERT(fc);
+ append_to_parent_field_class(ctx, (void *) fc);
+ return 0;
+}
+
static inline
int translate_integer_field_class(struct ctx *ctx)
{
int ret;
switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
+ case BT_FIELD_CLASS_TYPE_BOOL:
+ ret = translate_bool_field_class(ctx);
+ break;
+ case BT_FIELD_CLASS_TYPE_BIT_ARRAY:
+ ret = translate_bit_array_field_class(ctx);
+ break;
case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
ret = translate_integer_field_class(ctx);
break;
- case BT_FIELD_CLASS_TYPE_REAL:
+ case BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL:
+ case BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL:
ret = translate_real_field_class(ctx);
break;
case BT_FIELD_CLASS_TYPE_STRING:
case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
ret = translate_static_array_field_class(ctx);
break;
- case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+ case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD:
+ case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD:
ret = translate_dynamic_array_field_class(ctx);
break;
- case BT_FIELD_CLASS_TYPE_VARIANT:
+ case BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR:
+ case BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR:
+ case BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR:
+ case BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR:
+ ret = translate_option_field_class(ctx);
+ break;
+ case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
+ case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR:
+ case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR:
ret = translate_variant_field_class(ctx);
break;
default:
}
switch (fc->type) {
+ case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
+ {
+ /*
+ * CTF 1.8 does not support the option field class type.
+ * To write something anyway, this component translates
+ * this type to a variant field class where the options
+ * are:
+ *
+ * * An empty structure field class.
+ * * The optional field class itself.
+ *
+ * Because the option field class becomes a CTF variant
+ * field class, we use the term "tag" too here.
+ *
+ * The "tag" is always generated/before in that case (an
+ * 8-bit unsigned enumeration field class).
+ */
+ struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc;
+
+ field_ref = opt_fc->tag_ref;
+ is_before = true;
+ tgt_type = "tag";
+ break;
+ }
case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
{
struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
fc_type = fc->type;
switch (fc_type) {
+ case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION:
+ {
+ struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc;
+
+ ret = set_field_ref(fc, fc_name, parent_fc);
+ if (ret) {
+ goto end;
+ }
+
+ ret = set_field_refs(opt_fc->content_fc, NULL, fc);
+ if (ret) {
+ goto end;
+ }
+
+ break;
+ }
case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
{
uint64_t i;
uint64_t len;
- struct fs_sink_ctf_field_class_struct *struct_fc;
+ struct fs_sink_ctf_field_class_struct *struct_fc = NULL;
struct fs_sink_ctf_field_class_variant *var_fc = NULL;
struct fs_sink_ctf_named_field_class *named_fc;
* fill it.
*/
static
-int translate_scope_field_class(struct ctx *ctx, bt_scope scope,
+int translate_scope_field_class(struct ctx *ctx, bt_field_path_scope scope,
struct fs_sink_ctf_field_class **fc,
const bt_field_class *ir_fc)
{
BT_ASSERT(*fc);
ctx->cur_scope = scope;
BT_ASSERT(ctx->cur_path->len == 0);
- ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, ir_fc, NULL);
+ ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
if (ret) {
- BT_LOGE("Cannot translate scope structure field class: "
+ BT_COMP_LOGE("Cannot translate scope structure field class: "
"scope=%d", scope);
goto end;
}
ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
if (ret) {
- BT_LOGE("Cannot translate scope structure field class: "
+ BT_COMP_LOGE("Cannot translate scope structure field class: "
"scope=%d", scope);
goto end;
}
}
static inline
-void ctx_init(struct ctx *ctx)
+void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
{
memset(ctx, 0, sizeof(struct ctx));
ctx->cur_path = g_array_new(FALSE, TRUE,
sizeof(struct field_path_elem));
BT_ASSERT(ctx->cur_path);
+ ctx->log_level = fs_sink->log_level;
+ ctx->self_comp = fs_sink->self_comp;
}
static inline
}
static
-int translate_event_class(struct fs_sink_ctf_stream_class *sc,
+int translate_event_class(struct fs_sink_comp *fs_sink,
+ struct fs_sink_ctf_stream_class *sc,
const bt_event_class *ir_ec,
struct fs_sink_ctf_event_class **out_ec)
{
BT_ASSERT(sc);
BT_ASSERT(ir_ec);
- ctx_init(&ctx);
+ ctx_init(&ctx, fs_sink);
ec = fs_sink_ctf_event_class_create(sc, ir_ec);
BT_ASSERT(ec);
ctx.cur_sc = sc;
ctx.cur_ec = ec;
- ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
+ ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT,
&ec->spec_context_fc,
bt_event_class_borrow_specific_context_field_class_const(
ir_ec));
goto end;
}
- ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_PAYLOAD,
+ ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD,
&ec->payload_fc,
bt_event_class_borrow_payload_field_class_const(ir_ec));
if (ret) {
BT_HIDDEN
int try_translate_event_class_trace_ir_to_ctf_ir(
+ struct fs_sink_comp *fs_sink,
struct fs_sink_ctf_stream_class *sc,
const bt_event_class *ir_ec,
struct fs_sink_ctf_event_class **out_ec)
goto end;
}
- ret = translate_event_class(sc, ir_ec, out_ec);
+ ret = translate_event_class(fs_sink, sc, ir_ec, out_ec);
end:
return ret;
}
-bool default_clock_class_name_exists(struct fs_sink_ctf_trace_class *tc,
+bool default_clock_class_name_exists(struct fs_sink_ctf_trace *trace,
const char *name)
{
bool exists = false;
uint64_t i;
- for (i = 0; i < tc->stream_classes->len; i++) {
+ for (i = 0; i < trace->stream_classes->len; i++) {
struct fs_sink_ctf_stream_class *sc =
- tc->stream_classes->pdata[i];
+ trace->stream_classes->pdata[i];
if (sc->default_clock_class_name->len == 0) {
/* No default clock class */
g_string_assign(sc->default_clock_class_name, "");
sprintf(buf, "default");
- while (default_clock_class_name_exists(sc->tc, buf)) {
+ while (default_clock_class_name_exists(sc->trace, buf)) {
sprintf(buf, "default%u", suffix);
suffix++;
}
}
static
-int translate_stream_class(struct fs_sink_ctf_trace_class *tc,
+int translate_stream_class(struct fs_sink_comp *fs_sink,
+ struct fs_sink_ctf_trace *trace,
const bt_stream_class *ir_sc,
struct fs_sink_ctf_stream_class **out_sc)
{
int ret = 0;
struct ctx ctx;
- BT_ASSERT(tc);
+ BT_ASSERT(trace);
BT_ASSERT(ir_sc);
- ctx_init(&ctx);
- *out_sc = fs_sink_ctf_stream_class_create(tc, ir_sc);
+ ctx_init(&ctx, fs_sink);
+ *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
BT_ASSERT(*out_sc);
/* Set default clock class's protected name, if any */
if (name) {
/* Try original name, protected */
+ g_string_assign((*out_sc)->default_clock_class_name,
+ "");
+
+ if (must_protect_identifier(name)) {
+ g_string_assign(
+ (*out_sc)->default_clock_class_name,
+ "_");
+ }
+
g_string_assign((*out_sc)->default_clock_class_name,
name);
- ret = fs_sink_ctf_protect_name(
- (*out_sc)->default_clock_class_name);
- if (ret) {
+ if (!ist_valid_identifier(
+ (*out_sc)->default_clock_class_name->str)) {
/* Invalid: create a new name */
make_unique_default_clock_class_name(*out_sc);
ret = 0;
}
ctx.cur_sc = *out_sc;
- ret = translate_scope_field_class(&ctx, BT_SCOPE_PACKET_CONTEXT,
+ ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT,
&(*out_sc)->packet_context_fc,
bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
if (ret) {
(void *) (*out_sc)->packet_context_fc, 8);
}
- ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_COMMON_CONTEXT,
+ ret = translate_scope_field_class(&ctx, BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT,
&(*out_sc)->event_common_context_fc,
bt_stream_class_borrow_event_common_context_field_class_const(
ir_sc));
BT_HIDDEN
int try_translate_stream_class_trace_ir_to_ctf_ir(
- struct fs_sink_ctf_trace_class *tc,
+ struct fs_sink_comp *fs_sink,
+ struct fs_sink_ctf_trace *trace,
const bt_stream_class *ir_sc,
struct fs_sink_ctf_stream_class **out_sc)
{
int ret = 0;
uint64_t i;
- BT_ASSERT(tc);
+ BT_ASSERT(trace);
BT_ASSERT(ir_sc);
- for (i = 0; i < tc->stream_classes->len; i++) {
- *out_sc = tc->stream_classes->pdata[i];
+ for (i = 0; i < trace->stream_classes->len; i++) {
+ *out_sc = trace->stream_classes->pdata[i];
if ((*out_sc)->ir_sc == ir_sc) {
goto end;
}
}
- ret = translate_stream_class(tc, ir_sc, out_sc);
+ ret = translate_stream_class(fs_sink, trace, ir_sc, out_sc);
end:
return ret;
}
BT_HIDDEN
-struct fs_sink_ctf_trace_class *translate_trace_class_trace_ir_to_ctf_ir(
- const bt_trace_class *ir_tc)
+struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(
+ struct fs_sink_comp *fs_sink, const bt_trace *ir_trace)
{
uint64_t count;
uint64_t i;
- struct fs_sink_ctf_trace_class *tc = NULL;
+ struct fs_sink_ctf_trace *trace = NULL;
- /* Check that trace class's environment is TSDL-compatible */
- count = bt_trace_class_get_environment_entry_count(ir_tc);
+ /* Check that trace's environment is TSDL-compatible */
+ count = bt_trace_get_environment_entry_count(ir_trace);
for (i = 0; i < count; i++) {
const char *name;
const bt_value *val;
- bt_trace_class_borrow_environment_entry_by_index_const(
- ir_tc, i, &name, &val);
+ bt_trace_borrow_environment_entry_by_index_const(
+ ir_trace, i, &name, &val);
- if (!fs_sink_ctf_ist_valid_identifier(name)) {
- BT_LOGE("Unsupported trace class's environment entry name: "
+ if (!ist_valid_identifier(name)) {
+ BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
+ fs_sink->self_comp,
+ "Unsupported trace class's environment entry name: "
"name=\"%s\"", name);
goto end;
}
case BT_VALUE_TYPE_STRING:
break;
default:
- BT_LOGE("Unsupported trace class's environment entry value type: "
+ BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level,
+ fs_sink->self_comp,
+ "Unsupported trace class's environment entry value type: "
"type=%s",
bt_common_value_type_string(
bt_value_get_type(val)));
}
}
- tc = fs_sink_ctf_trace_class_create(ir_tc);
- BT_ASSERT(tc);
+ trace = fs_sink_ctf_trace_create(ir_trace);
+ BT_ASSERT(trace);
end:
- return tc;
+ return trace;
}