perf probe: Support basic type casting
authorMasami Hiramatsu <mhiramat@redhat.com>
Mon, 12 Apr 2010 17:17:22 +0000 (13:17 -0400)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 14 Apr 2010 20:28:09 +0000 (17:28 -0300)
Add basic type casting for arguments to perf probe. This allows
users to specify the actual type of arguments. Of course, if
user sets invalid types, kprobe-tracer rejects that.

Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20100412171722.3790.50372.stgit@localhost6.localdomain6>
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-probe.txt
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-finder.c

index 441324f2615d3a79a6625cc9bf01e89e5e7f35c0..63c25d3048803bb5fcc2796ba02365c41aa80581 100644 (file)
@@ -85,9 +85,10 @@ PROBE ARGUMENT
 --------------
 Each probe argument follows below syntax.
 
- [NAME=]LOCALVAR|$retval|%REG|@SYMBOL
+ [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
 
 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
+'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo.
 
 LINE SYNTAX
 -----------
index 05ca4a959e60c77b8b3996639cbf4a06009a4973..bef280527e60d334dacd28aeae64cbb98fa1fac7 100644 (file)
@@ -435,7 +435,7 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 }
 
 /* Parse perf-probe event argument */
-static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg)
+static void parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
 {
        char *tmp;
        struct perf_probe_arg_field **fieldp;
@@ -445,9 +445,17 @@ static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg)
        tmp = strchr(str, '=');
        if (tmp) {
                arg->name = xstrndup(str, tmp - str);
+               pr_debug("name:%s ", arg->name);
                str = tmp + 1;
        }
 
+       tmp = strchr(str, ':');
+       if (tmp) {      /* Type setting */
+               *tmp = '\0';
+               arg->type = xstrdup(tmp + 1);
+               pr_debug("type:%s ", arg->type);
+       }
+
        tmp = strpbrk(str, "-.");
        if (!is_c_varname(str) || !tmp) {
                /* A variable, register, symbol or special value */
@@ -603,6 +611,15 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
                len -= ret;
                field = field->next;
        }
+
+       if (pa->type) {
+               ret = e_snprintf(tmp, len, ":%s", pa->type);
+               if (ret <= 0)
+                       goto error;
+               tmp += ret;
+               len -= ret;
+       }
+
        return tmp - buf;
 error:
        die("Failed to synthesize perf probe argument: %s", strerror(-ret));
@@ -825,6 +842,8 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
                        free(pev->args[i].name);
                if (pev->args[i].var)
                        free(pev->args[i].var);
+               if (pev->args[i].type)
+                       free(pev->args[i].type);
                field = pev->args[i].field;
                while (field) {
                        next = field->next;
@@ -1145,6 +1164,8 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
                        if (pev->args[i].name)
                                tev->args[i].name = xstrdup(pev->args[i].name);
                        tev->args[i].value = xstrdup(pev->args[i].var);
+                       if (pev->args[i].type)
+                               tev->args[i].type = xstrdup(pev->args[i].type);
                }
        }
 
index a393a3f87cd025fd8dbae2df6b455b8d0444810a..ff2f26b1822c328e4dc86ff83722a52ebc0d3a03 100644 (file)
@@ -57,6 +57,7 @@ struct perf_probe_arg_field {
 struct perf_probe_arg {
        char                            *name;  /* Argument name */
        char                            *var;   /* Variable name */
+       char                            *type;  /* Type name */
        struct perf_probe_arg_field     *field; /* Structure fields */
 };
 
index ebeb413ac4732476604d315fb676a8db4593ed48..ab476736cbe77b15b79a4c7725c300d3f3e5169f 100644 (file)
@@ -547,7 +547,10 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
                                        &die_mem);
                vr_die = &die_mem;
        }
-       convert_variable_type(vr_die, pf->tvar);
+       if (pf->pvar->type)
+               pf->tvar->type = xstrdup(pf->pvar->type);
+       else
+               convert_variable_type(vr_die, pf->tvar);
        /* *expr will be cached in libdw. Don't free it. */
        return ;
 error:
@@ -560,13 +563,16 @@ error:
 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
        Dwarf_Die vr_die;
-       char buf[32];
+       char buf[32], *ptr;
 
        /* TODO: Support arrays */
        if (pf->pvar->name)
                pf->tvar->name = xstrdup(pf->pvar->name);
        else {
                synthesize_perf_probe_arg(pf->pvar, buf, 32);
+               ptr = strchr(buf, ':'); /* Change type separator to _ */
+               if (ptr)
+                       *ptr = '_';
                pf->tvar->name = xstrdup(buf);
        }