return ret;
}
+static
+int ctf_clock_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
+ struct ctf_clock *clock, struct ctf_trace *trace)
+{
+ int ret = 0;
+
+ switch (node->type) {
+ case NODE_CTF_EXPRESSION:
+ {
+ char *left;
+
+ left = concatenate_unary_strings(&node->u.ctf_expression.left);
+ if (!strcmp(left, "name")) {
+ char *right;
+
+ if (CTF_CLOCK_FIELD_IS_SET(clock, name)) {
+ fprintf(fd, "[error] %s: name already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ right = concatenate_unary_strings(&node->u.ctf_expression.right);
+ if (!right) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock name\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ clock->name = g_quark_from_string(right);
+ g_free(right);
+ CTF_EVENT_SET_FIELD(clock, name);
+ } else if (!strcmp(left, "uuid")) {
+ char *right;
+
+ if (clock->uuid) {
+ fprintf(fd, "[error] %s: uuid already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ right = concatenate_unary_strings(&node->u.ctf_expression.right);
+ if (!right) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock uuid\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ clock->uuid = g_quark_from_string(right);
+ g_free(right);
+ } else if (!strcmp(left, "description")) {
+ char *right;
+
+ if (clock->description) {
+ fprintf(fd, "[warning] %s: duplicated clock description\n", __func__);
+ goto error; /* ret is 0, so not an actual error, just warn. */
+ }
+ right = concatenate_unary_strings(&node->u.ctf_expression.right);
+ if (!right) {
+ fprintf(fd, "[warning] %s: unexpected unary expression for clock description\n", __func__);
+ goto error; /* ret is 0, so not an actual error, just warn. */
+ }
+ clock->description = right;
+ } else if (!strcmp(left, "freq")) {
+ if (clock->freq) {
+ fprintf(fd, "[error] %s: freq already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->freq);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock freq\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ } else if (!strcmp(left, "precision")) {
+ if (clock->precision) {
+ fprintf(fd, "[error] %s: precision already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->precision);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock precision\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ } else if (!strcmp(left, "offset_s")) {
+ if (clock->offset_s) {
+ fprintf(fd, "[error] %s: offset_s already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->offset_s);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock offset_s\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ } else if (!strcmp(left, "offset")) {
+ if (clock->offset) {
+ fprintf(fd, "[error] %s: offset already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->offset);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock offset\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ } else {
+ fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in clock declaration.\n", __func__, left);
+ }
+
+error:
+ g_free(left);
+ break;
+ }
+ default:
+ return -EPERM;
+ /* TODO: declaration specifier should be added. */
+ }
+
+ return ret;
+}
+
+static
+int ctf_clock_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+ struct ctf_clock *clock;
+
+ clock = g_new0(struct ctf_clock, 1);
+ cds_list_for_each_entry(iter, &node->u.clock.declaration_list, siblings) {
+ ret = ctf_clock_declaration_visit(fd, depth + 1, iter, clock, trace);
+ if (ret)
+ goto error;
+ }
+ if (!CTF_CLOCK_FIELD_IS_SET(clock, name)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing namefield in clock declaration\n", __func__);
+ goto error;
+ }
+ g_hash_table_insert(trace->clocks, (gpointer) (unsigned long) clock->name, clock);
+ return 0;
+
+error:
+ g_free(clock->description);
+ g_free(clock);
+ return ret;
+}
+
+static
+void clock_free(gpointer data)
+{
+ struct ctf_clock *clock = data;
+
+ g_free(clock->description);
+ g_free(clock);
+}
+
static
int ctf_root_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
{
return 0;
}
+/* TODO: missing metadata "destroy" (memory leak) */
int ctf_visitor_construct_metadata(FILE *fd, int depth, struct ctf_node *node,
struct ctf_trace *trace, int byte_order)
{
printf_verbose("CTF visitor: metadata construction... ");
trace->byte_order = byte_order;
+ trace->clocks = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, clock_free);
retry:
trace->root_declaration_scope = new_declaration_scope(NULL);
goto error;
}
}
+ cds_list_for_each_entry(iter, &node->u.root.clock, siblings) {
+ ret = ctf_clock_visit(fd, depth + 1, iter,
+ trace);
+ if (ret) {
+ fprintf(fd, "[error] %s: clock declaration error\n", __func__);
+ goto error;
+ }
+ }
+
if (!trace->streams) {
fprintf(fd, "[error] %s: missing trace declaration\n", __func__);
ret = -EINVAL;
error:
free_declaration_scope(trace->root_declaration_scope);
+ g_hash_table_destroy(trace->clocks);
return ret;
}
struct definition_struct *event_fields;
};
+#define CTF_CLOCK_SET_FIELD(ctf_clock, field) \
+ do { \
+ (ctf_clock)->field_mask |= CTF_CLOCK_ ## field; \
+ } while (0)
+
+#define CTF_CLOCK_FIELD_IS_SET(ctf_clock, field) \
+ ((ctf_clock)->field_mask & CTF_CLOCK_ ## field)
+
+#define CTF_CLOCK_GET_FIELD(ctf_clock, field) \
+ ({ \
+ assert(CTF_CLOCK_FIELD_IS_SET(ctf_clock, field)); \
+ (ctf_clock)->(field); \
+ })
+
+struct ctf_clock {
+ GQuark name;
+ GQuark uuid;
+ char *description;
+ uint64_t freq; /* frequency, in HZ */
+ /* precision in seconds is: precision * (1/freq) */
+ uint64_t precision;
+ /*
+ * The offset from Epoch is: offset_s + (offset * (1/freq))
+ * Coarse clock offset from Epoch (in seconds).
+ */
+ uint64_t offset_s;
+ /* Fine clock offset from Epoch, in (1/freq) units. */
+ uint64_t offset;
+
+ enum { /* Fields populated mask */
+ CTF_CLOCK_name = (1U << 0),
+ } field_mask;
+};
+
#define CTF_TRACE_SET_FIELD(ctf_trace, field) \
do { \
(ctf_trace)->field_mask |= CTF_TRACE_ ## field; \
(ctf_trace)->(field); \
})
-
struct ctf_trace {
struct trace_descriptor parent;
/* root scope */
struct definition_scope *definition_scope;
GPtrArray *streams; /* Array of struct ctf_stream_class pointers */
struct ctf_stream *metadata;
+ GHashTable *clocks;
struct declaration_struct *packet_header_decl;