Callsite support has been added to the spec.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
fprintf(fp, " (default: payload,context)\n");
fprintf(fp, " -f, --fields name1<,name2,...> Print additional fields:\n");
fprintf(fp, " all, trace, trace:hostname, trace:domain,\n");
- fprintf(fp, " trace:procname, trace:vpid, loglevel, emf.\n");
+ fprintf(fp, " trace:procname, trace:vpid, loglevel, emf, callsite.\n");
fprintf(fp, " (default: trace:hostname,trace:procname,trace:vpid)\n");
fprintf(fp, " --clock-cycles Timestamp in cycles\n");
fprintf(fp, " --clock-offset seconds Clock offset in seconds\n");
opt_loglevel_field = 1;
else if (!strcmp(str, "emf"))
opt_emf_field = 1;
+ else if (!strcmp(str, "callsite"))
+ opt_callsite_field = 1;
else {
fprintf(stderr, "[error] unknown field type %s\n", str);
return -EINVAL;
opt_trace_default_fields = 1,
opt_loglevel_field,
opt_emf_field,
+ opt_callsite_field,
opt_delta_field = 1;
enum field_item {
Q_STREAM_PACKET_CONTEXT_PACKET_SIZE = g_quark_from_static_string("stream.packet.context.packet_size");
}
+static
+struct ctf_callsite *ctf_trace_callsite_lookup(struct ctf_trace *trace,
+ GQuark callsite_name)
+{
+ return g_hash_table_lookup(trace->callsites,
+ (gpointer) (unsigned long) callsite_name);
+}
+
int print_field(struct definition *definition)
{
/* Print all fields in verbose mode */
fprintf(pos->fp, ", ");
dom_print = 1;
}
+ if ((opt_callsite_field || opt_all_fields)) {
+ struct ctf_callsite *callsite;
+
+ callsite = ctf_trace_callsite_lookup(stream_class->trace,
+ event_class->name);
+ if (callsite) {
+ set_field_names_print(pos, ITEM_HEADER);
+ if (pos->print_names) {
+ fprintf(pos->fp, "callsite = ");
+ } else if (dom_print) {
+ fprintf(pos->fp, ":");
+ }
+ fprintf(pos->fp, "[%s@%s:%" PRIu64 "]",
+ callsite->func, callsite->file,
+ callsite->line);
+ if (pos->print_names)
+ fprintf(pos->fp, ", ");
+ dom_print = 1;
+ }
+ }
if (dom_print && !pos->print_names)
fprintf(pos->fp, " ");
set_field_names_print(pos, ITEM_HEADER);
NODE_ENV,
NODE_TRACE,
NODE_CLOCK,
+ NODE_CALLSITE,
NODE_CTF_EXPRESSION,
NODE_UNARY_EXPRESSION,
struct bt_list_head stream;
struct bt_list_head event;
struct bt_list_head clock;
+ struct bt_list_head callsite;
} root;
struct {
/*
*/
struct bt_list_head declaration_list;
} clock;
+ struct {
+ /*
+ * Children nodes are ctf_expression, typedef,
+ * typealias and type_specifier_list.
+ */
+ struct bt_list_head declaration_list;
+ } callsite;
struct {
struct bt_list_head left; /* Should be string */
struct bt_list_head right; /* Unary exp. or type */
string setstring(yyextra, yylval, yytext); return STRING;
struct setstring(yyextra, yylval, yytext); return STRUCT;
trace setstring(yyextra, yylval, yytext); return TRACE;
+callsite setstring(yyextra, yylval, yytext); return CALLSITE;
typealias setstring(yyextra, yylval, yytext); return TYPEALIAS;
typedef setstring(yyextra, yylval, yytext); return TYPEDEF;
unsigned setstring(yyextra, yylval, yytext); return UNSIGNED;
[ NODE_STREAM ] = "NODE_STREAM",
[ NODE_TRACE ] = "NODE_TRACE",
[ NODE_CLOCK ] = "NODE_CLOCK",
+ [ NODE_CALLSITE ] = "NODE_CALLSITE",
[ NODE_CTF_EXPRESSION ] = "NODE_CTF_EXPRESSION",
[ NODE_UNARY_EXPRESSION ] = "NODE_UNARY_EXPRESSION",
[ NODE_TYPEDEF ] = "NODE_TYPEDEF",
case NODE_CLOCK:
BT_INIT_LIST_HEAD(&node->u.clock.declaration_list);
break;
+ case NODE_CALLSITE:
+ BT_INIT_LIST_HEAD(&node->u.callsite.declaration_list);
+ break;
case NODE_CTF_EXPRESSION:
BT_INIT_LIST_HEAD(&node->u.ctf_expression.left);
case NODE_CLOCK:
_bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
break;
+ case NODE_CALLSITE:
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
+ break;
case NODE_FLOATING_POINT:
_bt_list_splice_tail(&node->tmp_head, &parent->u.floating_point.expressions);
break;
case NODE_CLOCK:
_bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
break;
+ case NODE_CALLSITE:
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
+ break;
case NODE_VARIANT:
_bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
break;
case NODE_CLOCK:
_bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
break;
+ case NODE_CALLSITE:
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
+ break;
case NODE_VARIANT:
_bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
break;
case NODE_ENV:
case NODE_TRACE:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_VARIANT:
case NODE_STRUCT:
case NODE_TYPEDEF:
case NODE_CLOCK:
bt_list_add_tail(&node->siblings, &parent->u.clock.declaration_list);
break;
+ case NODE_CALLSITE:
+ bt_list_add_tail(&node->siblings, &parent->u.callsite.declaration_list);
+ break;
case NODE_VARIANT:
bt_list_add_tail(&node->siblings, &parent->u.variant.declaration_list);
break;
case NODE_ENV:
case NODE_TRACE:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_VARIANT:
case NODE_STRUCT:
case NODE_TYPEALIAS:
return -EPERM;
}
break;
+ case NODE_CALLSITE:
+ if (parent->type == NODE_ROOT) {
+ _bt_list_splice_tail(&node->tmp_head, &parent->u.root.callsite);
+ } else {
+ return -EPERM;
+ }
+ break;
case NODE_CTF_EXPRESSION:
return reparent_ctf_expression(node, parent);
BT_INIT_LIST_HEAD(&ast->root.u.root.stream);
BT_INIT_LIST_HEAD(&ast->root.u.root.event);
BT_INIT_LIST_HEAD(&ast->root.u.root.clock);
+ BT_INIT_LIST_HEAD(&ast->root.u.root.callsite);
return ast;
}
*/
%expect 2
%start file
-%token CHARACTER_CONSTANT_START SQUOTE STRING_LITERAL_START DQUOTE ESCSEQ CHAR_STRING_TOKEN LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW STAR PLUS MINUS LT GT TYPEASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA CONST CHAR DOUBLE ENUM ENV EVENT FLOATING_POINT FLOAT INTEGER INT LONG SHORT SIGNED STREAM STRING STRUCT TRACE CLOCK TYPEALIAS TYPEDEF UNSIGNED VARIANT VOID _BOOL _COMPLEX _IMAGINARY DECIMAL_CONSTANT OCTAL_CONSTANT HEXADECIMAL_CONSTANT TOK_ALIGN
+%token CHARACTER_CONSTANT_START SQUOTE STRING_LITERAL_START DQUOTE ESCSEQ CHAR_STRING_TOKEN LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW STAR PLUS MINUS LT GT TYPEASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA CONST CHAR DOUBLE ENUM ENV EVENT FLOATING_POINT FLOAT INTEGER INT LONG SHORT SIGNED STREAM STRING STRUCT TRACE CALLSITE CLOCK TYPEALIAS TYPEDEF UNSIGNED VARIANT VOID _BOOL _COMPLEX _IMAGINARY DECIMAL_CONSTANT OCTAL_CONSTANT HEXADECIMAL_CONSTANT TOK_ALIGN
%token <gs> IDENTIFIER ID_TYPE
%token ERROR
%union
%type <n> env_declaration
%type <n> trace_declaration
%type <n> clock_declaration
+%type <n> callsite_declaration
%type <n> integer_declaration_specifiers
%type <n> declaration_specifiers
%type <n> alias_declaration_specifiers
{ $$ = yylval.gs; }
| CLOCK
{ $$ = yylval.gs; }
+ | CALLSITE
+ { $$ = yylval.gs; }
| TOK_ALIGN
{ $$ = yylval.gs; }
;
{ $$ = $1; }
| clock_declaration
{ $$ = $1; }
+ | callsite_declaration
+ { $$ = $1; }
| declaration_specifiers TYPEDEF declaration_specifiers type_declarator_list SEMICOLON
{
struct ctf_node *list;
{ pop_scope(scanner); }
;
+callsite_declaration:
+ CALLSITE callsite_declaration_begin callsite_declaration_end
+ {
+ $$ = make_node(scanner, NODE_CALLSITE);
+ }
+ | CALLSITE callsite_declaration_begin ctf_assignment_expression_list callsite_declaration_end
+ {
+ $$ = make_node(scanner, NODE_CALLSITE);
+ if (set_parent_node($3, $$))
+ reparent_error(scanner, "trace_declaration");
+ }
+ ;
+
+callsite_declaration_begin:
+ LBRAC
+ { push_scope(scanner); }
+ ;
+
+callsite_declaration_end:
+ RBRAC SEMICOLON
+ { pop_scope(scanner); }
+ ;
+
integer_declaration_specifiers:
CONST
{
g_free(clock);
}
+static
+int ctf_callsite_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
+ struct ctf_callsite *callsite, 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_CALLSITE_FIELD_IS_SET(callsite, name)) {
+ fprintf(fd, "[error] %s: name already declared in callsite 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 callsite name\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ callsite->name = g_quark_from_string(right);
+ g_free(right);
+ CTF_CALLSITE_SET_FIELD(callsite, name);
+ } else if (!strcmp(left, "func")) {
+ char *right;
+
+ if (CTF_CALLSITE_FIELD_IS_SET(callsite, func)) {
+ fprintf(fd, "[error] %s: func already declared in callsite 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 callsite func\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ callsite->func = right;
+ CTF_CALLSITE_SET_FIELD(callsite, func);
+ } else if (!strcmp(left, "file")) {
+ char *right;
+
+ if (CTF_CALLSITE_FIELD_IS_SET(callsite, file)) {
+ fprintf(fd, "[error] %s: file already declared in callsite 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 callsite file\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ callsite->file = right;
+ CTF_CALLSITE_SET_FIELD(callsite, file);
+ } else if (!strcmp(left, "line")) {
+ if (CTF_CALLSITE_FIELD_IS_SET(callsite, line)) {
+ fprintf(fd, "[error] %s: line already declared in callsite declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &callsite->line);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for callsite line\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ CTF_CALLSITE_SET_FIELD(callsite, line);
+ } else {
+ fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in callsite declaration.\n", __func__, left);
+ }
+
+error:
+ g_free(left);
+ break;
+ }
+ default:
+ return -EPERM;
+ /* TODO: declaration specifier should be added. */
+ }
+
+ return ret;
+}
+
+static
+int ctf_callsite_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+ struct ctf_callsite *callsite;
+
+ callsite = g_new0(struct ctf_callsite, 1);
+ bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
+ ret = ctf_callsite_declaration_visit(fd, depth + 1, iter, callsite, trace);
+ if (ret)
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, name)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing name field in callsite declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, func)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing func field in callsite declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, file)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing file field in callsite declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, line)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing line field in callsite declaration\n", __func__);
+ goto error;
+ }
+
+ g_hash_table_insert(trace->callsites, (gpointer) (unsigned long) callsite->name, callsite);
+ return 0;
+
+error:
+ g_free(callsite->func);
+ g_free(callsite->file);
+ g_free(callsite);
+ return ret;
+}
+
+static
+void callsite_free(gpointer data)
+{
+ struct ctf_callsite *callsite = data;
+
+ g_free(callsite->func);
+ g_free(callsite->file);
+ g_free(callsite);
+}
+
static
int ctf_env_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
struct ctf_trace *trace)
trace->byte_order = byte_order;
trace->clocks = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, clock_free);
+ trace->callsites = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, callsite_free);
retry:
trace->root_declaration_scope = new_declaration_scope(NULL);
goto error;
}
}
+ bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
+ ret = ctf_callsite_visit(fd, depth + 1, iter,
+ trace);
+ if (ret) {
+ fprintf(fd, "[error] %s: callsite 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->callsites);
g_hash_table_destroy(trace->clocks);
return ret;
}
if (ret)
return ret;
}
+ bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
break;
case NODE_EVENT:
return ret;
}
break;
+ case NODE_CALLSITE:
+ bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
+ iter->parent = node;
+ ret = ctf_visitor_parent_links(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ break;
case NODE_CTF_EXPRESSION:
depth++;
case NODE_ENV:
case NODE_TRACE:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_TYPEDEF:
case NODE_TYPEALIAS_TARGET:
case NODE_TYPEALIAS_ALIAS:
case NODE_ENV:
case NODE_TRACE:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_UNARY_EXPRESSION:
case NODE_TYPEALIAS:
case NODE_TYPE_SPECIFIER:
case NODE_ENV:
case NODE_TRACE:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_UNARY_EXPRESSION:
case NODE_TYPEALIAS:
case NODE_TYPE_SPECIFIER:
case NODE_ENV:
case NODE_TRACE:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_CTF_EXPRESSION:
case NODE_UNARY_EXPRESSION:
case NODE_TYPEALIAS:
return ret;
}
break;
+ case NODE_CALLSITE:
+ switch (node->parent->type) {
+ case NODE_ROOT:
+ break; /* OK */
+ default:
+ goto errinval;
+ }
+ bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
+ ret = _ctf_visitor_semantic_check(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ break;
case NODE_CTF_EXPRESSION:
switch (node->parent->type) {
case NODE_ENV:
case NODE_TRACE:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_FLOATING_POINT:
case NODE_INTEGER:
case NODE_STRING:
case NODE_ENUMERATOR:
case NODE_ENUM:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_ENV:
default:
goto errinval;
case NODE_ENUMERATOR:
case NODE_ENUM:
case NODE_CLOCK:
+ case NODE_CALLSITE:
case NODE_ENV:
default:
goto errinval;
print_tabs(fd, depth);
fprintf(fd, "</clock>\n");
break;
+ case NODE_CALLSITE:
+ print_tabs(fd, depth);
+ fprintf(fd, "<callsite>\n");
+ bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
+ ret = ctf_visitor_print_xml(fd, depth + 1, iter);
+ if (ret)
+ return ret;
+ }
+ print_tabs(fd, depth);
+ fprintf(fd, "</callsite>\n");
+ break;
case NODE_CTF_EXPRESSION:
opt_trace_default_fields,
opt_loglevel_field,
opt_emf_field,
+ opt_callsite_field,
opt_delta_field,
opt_clock_cycles,
opt_clock_seconds,
struct ctf_stream_declaration;
struct ctf_event_declaration;
struct ctf_clock;
+struct ctf_callsite;
struct ctf_stream_definition {
struct ctf_stream_declaration *stream_class;
} field_mask;
};
+#define CTF_CALLSITE_SET_FIELD(ctf_callsite, field) \
+ do { \
+ (ctf_callsite)->field_mask |= CTF_CALLSITE_ ## field; \
+ } while (0)
+
+#define CTF_CALLSITE_FIELD_IS_SET(ctf_callsite, field) \
+ ((ctf_callsite)->field_mask & CTF_CALLSITE_ ## field)
+
+#define CTF_CALLSITE_GET_FIELD(ctf_callsite, field) \
+ ({ \
+ assert(CTF_CALLSITE_FIELD_IS_SET(ctf_callsite, field)); \
+ (ctf_callsite)->(field); \
+ })
+
+struct ctf_callsite {
+ GQuark name; /* event name associated with callsite */
+ char *func;
+ char *file;
+ uint64_t line;
+ enum { /* Fields populated mask */
+ CTF_CALLSITE_name = (1U << 0),
+ CTF_CALLSITE_func = (1U << 1),
+ CTF_CALLSITE_file = (1U << 2),
+ CTF_CALLSITE_line = (1U << 3),
+ } field_mask;
+};
+
#define CTF_TRACE_SET_FIELD(ctf_trace, field) \
do { \
(ctf_trace)->field_mask |= CTF_TRACE_ ## field; \
GPtrArray *streams; /* Array of struct ctf_stream_declaration pointers */
struct ctf_stream_definition *metadata;
GHashTable *clocks;
+ GHashTable *callsites;
struct ctf_clock *single_clock; /* currently supports only one clock */
struct trace_collection *collection; /* Container of this trace */
GPtrArray *event_declarations; /* Array of all the struct bt_ctf_event_decl */