#include <stdio.h>
#include <unistd.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
/* Offset (ns) to apply to clock classes on creation */
uint64_t clock_class_offset_ns;
+ /* Eventual name suffix of the trace to set */
+ char *trace_name_suffix;
+
/* Trace attributes */
enum bt_ctf_byte_order trace_bo;
uint64_t trace_major;
while (cur_scope && cur_levels < levels) {
decl = g_hash_table_lookup(cur_scope->decl_map,
- (gconstpointer) (unsigned long) qname);
+ (gconstpointer) GUINT_TO_POINTER(qname));
if (decl) {
/* Caller's reference */
bt_get(decl);
}
g_hash_table_insert(scope->decl_map,
- (gpointer) (unsigned long) qname, decl);
+ GUINT_TO_POINTER(qname), decl);
/* Hash table's reference */
bt_get(decl);
name, decl);
}
+/**
+ * Destroys a visitor context.
+ *
+ * @param ctx Visitor context to destroy
+ */
+static
+void ctx_destroy(struct ctx *ctx)
+{
+ struct ctx_decl_scope *scope;
+ /*
+ * Destroy all scopes, from current one to the root scope.
+ */
+
+ if (!ctx) {
+ goto end;
+ }
+
+ scope = ctx->current_scope;
+
+ while (scope) {
+ struct ctx_decl_scope *parent_scope = scope->parent_scope;
+
+ ctx_decl_scope_destroy(scope);
+ scope = parent_scope;
+ }
+
+ bt_put(ctx->trace);
+
+ if (ctx->stream_classes) {
+ g_hash_table_destroy(ctx->stream_classes);
+ }
+
+ free(ctx->trace_name_suffix);
+ g_free(ctx);
+
+end:
+ return;
+}
+
/**
* Creates a new visitor context.
*
*/
static
struct ctx *ctx_create(struct bt_ctf_trace *trace, FILE *efd,
- uint64_t clock_class_offset_ns)
+ uint64_t clock_class_offset_ns, const char *trace_name_suffix)
{
struct ctx *ctx = NULL;
struct ctx_decl_scope *scope = NULL;
goto error;
}
+ if (trace_name_suffix) {
+ ctx->trace_name_suffix = strdup(trace_name_suffix);
+ if (!ctx->trace_name_suffix) {
+ goto error;
+ }
+ }
+
ctx->trace = trace;
ctx->efd = efd;
ctx->current_scope = scope;
+ scope = NULL;
ctx->trace_bo = BT_CTF_BYTE_ORDER_NATIVE;
ctx->clock_class_offset_ns = clock_class_offset_ns;
return ctx;
error:
- g_free(ctx);
+ ctx_destroy(ctx);
ctx_decl_scope_destroy(scope);
return NULL;
}
-/**
- * Destroys a visitor context.
- *
- * @param ctx Visitor context to destroy
- */
-static
-void ctx_destroy(struct ctx *ctx)
-{
- struct ctx_decl_scope *scope;
- /*
- * Destroy all scopes, from current one to the root scope.
- */
-
- if (!ctx) {
- goto end;
- }
-
- scope = ctx->current_scope;
-
- while (scope) {
- struct ctx_decl_scope *parent_scope = scope->parent_scope;
-
- ctx_decl_scope_destroy(scope);
- scope = parent_scope;
- }
-
- bt_put(ctx->trace);
- g_hash_table_destroy(ctx->stream_classes);
- g_free(ctx);
-
-end:
- return;
-}
-
/**
* Pushes a new declaration scope on top of a visitor context's
* declaration scope stack.
int ret = 0;
struct ctf_node *node;
+ if (bt_list_empty(head)) {
+ ret = -1;
+ goto end;
+ }
+
bt_list_for_each_entry(node, head, siblings) {
int uexpr_type = node->u.unary_expression.type;
int uexpr_link = node->u.unary_expression.link;
enum bt_ctf_byte_order bo = byte_order_from_unary_expr(ctx->efd, uexpr);
if (bo == BT_CTF_BYTE_ORDER_NATIVE) {
- bo = bt_ctf_trace_get_byte_order(ctx->trace);
+ bo = bt_ctf_trace_get_native_byte_order(ctx->trace);
}
return bo;
int get_type_specifier_list_name(struct ctx *ctx,
struct ctf_node *type_specifier_list, GString *str)
{
- int ret;
+ int ret = 0;
struct ctf_node *iter;
int alias_item_nr = 0;
struct bt_list_head *head =
nested_decl_copy = bt_ctf_field_type_copy(nested_decl);
BT_PUT(nested_decl);
if (!nested_decl_copy) {
- _PERROR("%s", "cannot copy nested declaration");
+ _PERROR("%s", "cannot copy nested field type");
ret = -EINVAL;
goto error;
}
BT_PUT(nested_decl);
if (!array_decl) {
_PERROR("%s",
- "cannot create array declaration");
+ "cannot create array field type");
ret = -ENOMEM;
goto error;
}
BT_PUT(nested_decl);
if (!seq_decl) {
_PERROR("%s",
- "cannot create sequence declaration");
+ "cannot create sequence field type");
ret = -ENOMEM;
goto error;
}
&qfield_name, iter, &field_decl, NULL);
if (ret) {
assert(!field_decl);
- _PERROR("%s", "unable to find structure field declaration type");
+ _PERROR("%s", "cannot visit type declarator");
goto error;
}
if (ret) {
assert(!field_decl);
_PERROR("%s",
- "unable to find variant field declaration type");
+ "cannot visit type declarator");
goto error;
}
ret = visit_type_declarator(ctx, type_specifier_list,
&qidentifier, iter, &type_decl, NULL);
if (ret) {
- _PERROR("%s", "problem creating type declaration");
+ _PERROR("%s", "cannot visit type declarator");
ret = -EINVAL;
goto end;
}
&qdummy_field_name, node, &type_decl, NULL);
if (ret) {
assert(!type_decl);
- _PERROR("%s", "problem creating type declaration");
+ _PERROR("%s", "cannot visit type declarator");
goto end;
}
struct_decl_copy = bt_ctf_field_type_copy(*struct_decl);
if (!struct_decl_copy) {
_PERROR("%s",
- "cannot create copy of structure declaration");
+ "cannot create copy of structure field type");
ret = -EINVAL;
goto error;
}
*struct_decl = bt_ctf_field_type_structure_create();
if (!*struct_decl) {
- _PERROR("%s", "cannot create structure declaration");
+ _PERROR("%s", "cannot create structure field type");
ret = -ENOMEM;
goto error;
}
untagged_variant_decl);
if (!variant_decl_copy) {
_PERROR("%s",
- "cannot create copy of structure declaration");
+ "cannot create copy of variant field type");
ret = -EINVAL;
goto error;
}
untagged_variant_decl = bt_ctf_field_type_variant_create(NULL,
NULL);
if (!untagged_variant_decl) {
- _PERROR("%s", "cannot create variant declaration");
+ _PERROR("%s", "cannot create variant field type");
ret = -ENOMEM;
goto error;
}
enum_decl_copy = bt_ctf_field_type_copy(*enum_decl);
if (!enum_decl_copy) {
_PERROR("%s",
- "cannot create copy of enumeration declaration");
+ "cannot create copy of enumeration field type");
ret = -EINVAL;
goto error;
}
*enum_decl = bt_ctf_field_type_enumeration_create(integer_decl);
if (!*enum_decl) {
- _PERROR("%s", "cannot create enumeration declaration");
+ _PERROR("%s", "cannot create enumeration field type");
ret = -ENOMEM;
goto error;
}
/* Make a copy of the type declaration */
decl_copy = bt_ctf_field_type_copy(*decl);
if (!decl_copy) {
- _PERROR("%s", "cannot create copy of type declaration");
+ _PERROR("%s", "cannot create field type copy");
ret = -EINVAL;
goto error;
}
enum bt_ctf_string_encoding encoding = BT_CTF_STRING_ENCODING_NONE;
enum bt_ctf_integer_base base = BT_CTF_INTEGER_BASE_DECIMAL;
enum bt_ctf_byte_order byte_order =
- bt_ctf_trace_get_byte_order(ctx->trace);
+ bt_ctf_trace_get_native_byte_order(ctx->trace);
*integer_decl = NULL;
*integer_decl = bt_ctf_field_type_integer_create((unsigned int) size);
if (!*integer_decl) {
- _PERROR("%s", "cannot create integer declaration");
+ _PERROR("%s", "cannot create integer field type");
ret = -ENOMEM;
goto error;
}
}
if (ret) {
- _PERROR("%s", "cannot configure integer declaration");
+ _PERROR("%s", "cannot configure integer field type");
ret = -EINVAL;
goto error;
}
struct ctf_node *expression;
uint64_t alignment = 1, exp_dig = 0, mant_dig = 0;
enum bt_ctf_byte_order byte_order =
- bt_ctf_trace_get_byte_order(ctx->trace);
+ bt_ctf_trace_get_native_byte_order(ctx->trace);
*float_decl = NULL;
*float_decl = bt_ctf_field_type_floating_point_create();
if (!*float_decl) {
_PERROR("%s",
- "cannot create floating point number declaration");
+ "cannot create floating point number field type");
ret = -ENOMEM;
goto error;
}
ret |= bt_ctf_field_type_set_alignment(*float_decl, alignment);
if (ret) {
_PERROR("%s",
- "cannot configure floating point number declaration");
+ "cannot configure floating point number field type");
ret = -EINVAL;
goto error;
}
*string_decl = bt_ctf_field_type_string_create();
if (!*string_decl) {
- _PERROR("%s", "cannot create string declaration");
+ _PERROR("%s", "cannot create string field type");
ret = -ENOMEM;
goto error;
}
ret = bt_ctf_field_type_string_set_encoding(*string_decl, encoding);
if (ret) {
- _PERROR("%s", "cannot configure string declaration");
+ _PERROR("%s", "cannot configure string field type");
ret = -EINVAL;
goto error;
}
ret = get_unary_unsigned(&node->u.ctf_expression.right,
(uint64_t *) &id);
- if (ret || id < 0) {
+ /* Only read "id" if get_unary_unsigned() succeeded. */
+ if (ret || (!ret && id < 0)) {
_PERROR("%s", "unexpected unary expression for event declaration's \"id\" attribute");
ret = -EINVAL;
goto error;
ret = get_unary_unsigned(&node->u.ctf_expression.right,
(uint64_t *) stream_id);
- if (ret || *stream_id < 0) {
+ /*
+ * Only read "stream_id" if get_unary_unsigned()
+ * succeeded.
+ */
+ if (ret || (!ret && *stream_id < 0)) {
_PERROR("%s", "unexpected unary expression for event declaration's \"stream_id\" attribute");
ret = -EINVAL;
goto error;
struct ctf_node, siblings),
&decl);
if (ret) {
- _PERROR("%s", "cannot create event payload declaration");
+ _PERROR("%s", "cannot create event payload field type");
goto error;
}
event_class, decl);
BT_PUT(decl);
if (ret) {
- _PERROR("%s", "cannot set event's payload declaration");
+ _PERROR("%s", "cannot set event's payload field type");
goto error;
}
} else {
assert(bt_ctf_trace_get_stream_class_count(
ctx->trace) == 1);
- stream_class = bt_ctf_trace_get_stream_class(
- ctx->trace, 0);
+ stream_class =
+ bt_ctf_trace_get_stream_class_by_index(
+ ctx->trace, 0);
assert(stream_class);
stream_id = bt_ctf_stream_class_get_id(
stream_class);
event_id);
if (eevent_class) {
BT_PUT(eevent_class);
- _PERROR("%s", "duplicate event with ID %" PRId64 " in same stream");
- ret = -EEXIST;
- goto error;
- }
-
- eevent_class = bt_ctf_stream_class_get_event_class_by_name(stream_class,
- event_name);
- if (eevent_class) {
- BT_PUT(eevent_class);
- _PERROR("%s",
- "duplicate event with name \"%s\" in same stream");
+ _PERROR("duplicate event with ID %" PRId64 " in same stream", event_id);
ret = -EEXIST;
goto error;
}
ret = get_unary_unsigned(&node->u.ctf_expression.right,
(uint64_t *) &id);
- if (ret || id < 0) {
+ /* Only read "id" if get_unary_unsigned() succeeded. */
+ if (ret || (!ret && id < 0)) {
_PERROR("%s", "unexpected unary expression for stream declaration's \"id\" attribute");
ret = -EINVAL;
goto error;
ret = bt_ctf_stream_class_set_id(stream_class, id);
if (ret) {
_PERROR("%s",
- "cannot set stream declaration's ID");
+ "cannot set stream class's ID");
goto error;
}
struct ctf_node, siblings),
&decl);
if (ret) {
- _PERROR("%s", "cannot create event header declaration");
+ _PERROR("%s", "cannot create event header field type");
goto error;
}
stream_class, decl);
BT_PUT(decl);
if (ret) {
- _PERROR("%s", "cannot set stream's event header declaration");
+ _PERROR("%s", "cannot set stream's event header field type");
goto error;
}
struct ctf_node, siblings),
&decl);
if (ret) {
- _PERROR("%s", "cannot create stream event context declaration");
+ _PERROR("%s", "cannot create stream event context field type");
goto error;
}
stream_class, decl);
BT_PUT(decl);
if (ret) {
- _PERROR("%s", "cannot set stream's event context declaration");
+ _PERROR("%s", "cannot set stream's event context field type");
goto error;
}
struct ctf_node, siblings),
&decl);
if (ret) {
- _PERROR("%s", "cannot create packet context declaration");
+ _PERROR("%s", "cannot create packet context field type");
goto error;
}
stream_class, decl);
BT_PUT(decl);
if (ret) {
- _PERROR("%s", "cannot set stream's packet context declaration");
+ _PERROR("%s", "cannot set stream's packet context field type");
goto error;
}
bt_ctf_trace_get_packet_header_type(ctx->trace);
if (!packet_header_decl) {
_PERROR("%s",
- "cannot get trace packet header declaration");
+ "cannot get trace packet header field type");
goto error;
}
goto error;
}
+ ret = bt_ctf_trace_set_uuid(ctx->trace, ctx->trace_uuid);
+ if (ret) {
+ _PERROR("%s",
+ "cannot set trace's UUID");
+ goto error;
+ }
+
_SET(set, _TRACE_UUID_SET);
} else if (!strcmp(left, "byte_order")) {
/* Native byte order is already known at this stage */
struct ctf_node, siblings),
&packet_header_decl);
if (ret) {
- _PERROR("%s", "cannot create packet header declaration");
+ _PERROR("%s", "cannot create packet header field type");
goto error;
}
packet_header_decl);
BT_PUT(packet_header_decl);
if (ret) {
- _PERROR("%s", "cannot set trace declaration's packet header declaration");
+ _PERROR("%s", "cannot set trace's packet header field type");
goto error;
}
return ret;
}
+static
+int set_trace_name(struct ctx *ctx)
+{
+ GString *name;
+ int ret = 0;
+ struct bt_value *value = NULL;
+
+ assert(bt_ctf_trace_get_stream_class_count(ctx->trace) == 0);
+ name = g_string_new(NULL);
+ if (!name) {
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Check if we have a trace environment string value named `hostname`.
+ * If so, use it as the trace name's prefix.
+ */
+ value = bt_ctf_trace_get_environment_field_value_by_name(ctx->trace,
+ "hostname");
+ if (bt_value_is_string(value)) {
+ const char *hostname;
+
+ ret = bt_value_string_get(value, &hostname);
+ assert(ret == 0);
+ g_string_append(name, hostname);
+
+ if (ctx->trace_name_suffix) {
+ g_string_append_c(name, G_DIR_SEPARATOR);
+ }
+ }
+
+ if (ctx->trace_name_suffix) {
+ g_string_append(name, ctx->trace_name_suffix);
+ }
+
+ ret = bt_ctf_trace_set_name(ctx->trace, name->str);
+ if (ret) {
+ goto error;
+ }
+
+ goto end;
+
+error:
+ ret = -1;
+
+end:
+ bt_put(value);
+
+ if (name) {
+ g_string_free(name, TRUE);
+ }
+
+ return ret;
+}
+
static
int move_ctx_stream_classes_to_trace(struct ctx *ctx)
{
- int ret;
+ int ret = 0;
GHashTableIter iter;
gpointer key, stream_class;
+ if (g_hash_table_size(ctx->stream_classes) > 0 &&
+ bt_ctf_trace_get_stream_class_count(ctx->trace) == 0) {
+ /*
+ * We're about to add the first stream class to the
+ * trace. This will freeze the trace, and after this
+ * we cannot set the name anymore. At this point,
+ * set the trace name.
+ */
+ ret = set_trace_name(ctx);
+ if (ret) {
+ goto end;
+ }
+ }
+
g_hash_table_iter_init(&iter, ctx->stream_classes);
while (g_hash_table_iter_next(&iter, &key, &stream_class)) {
BT_HIDDEN
struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd,
- uint64_t clock_class_offset_ns)
+ uint64_t clock_class_offset_ns, const char *name)
{
int ret;
struct ctx *ctx = NULL;
}
/* Create visitor's context */
- ctx = ctx_create(trace, efd, clock_class_offset_ns);
+ ctx = ctx_create(trace, efd, clock_class_offset_ns, name);
if (!ctx) {
_FPERROR(efd, "%s", "cannot create visitor context");
goto error;