Skip to content

Commit

Permalink
perf probe: Support "$vars" meta argument syntax for local variables
Browse files Browse the repository at this point in the history
Support "$vars" meta argument syntax for tracing all local variables at
probe point.

Now you can trace all available local variables (including function
parameters) at the probe point by passing $vars.

 # perf probe --add foo $vars

This automatically finds all local variables at foo() and adds it as
probe arguments.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20131011071023.15557.51770.stgit@udc4-manage.rcp.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Masami Hiramatsu authored and Arnaldo Carvalho de Melo committed Oct 23, 2013
1 parent c824c43 commit 7969ec7
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 9 deletions.
1 change: 0 additions & 1 deletion tools/perf/util/probe-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
#include "session.h"

#define MAX_CMDLEN 256
#define MAX_PROBE_ARGS 128
#define PERFPROBE_GROUP "probe"

bool probe_event_dry_run; /* Dry run flag */
Expand Down
96 changes: 88 additions & 8 deletions tools/perf/util/probe-finder.c
Original file line number Diff line number Diff line change
Expand Up @@ -1136,12 +1136,78 @@ static int debuginfo__find_probes(struct debuginfo *self,
return ret;
}

struct local_vars_finder {
struct probe_finder *pf;
struct perf_probe_arg *args;
int max_args;
int nargs;
int ret;
};

/* Collect available variables in this scope */
static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
{
struct local_vars_finder *vf = data;
int tag;

tag = dwarf_tag(die_mem);
if (tag == DW_TAG_formal_parameter ||
tag == DW_TAG_variable) {
if (convert_variable_location(die_mem, vf->pf->addr,
vf->pf->fb_ops, NULL) == 0) {
vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
if (vf->args[vf->nargs].var == NULL) {
vf->ret = -ENOMEM;
return DIE_FIND_CB_END;
}
pr_debug(" %s", vf->args[vf->nargs].var);
vf->nargs++;
}
}

if (dwarf_haspc(die_mem, vf->pf->addr))
return DIE_FIND_CB_CONTINUE;
else
return DIE_FIND_CB_SIBLING;
}

static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
struct perf_probe_arg *args)
{
Dwarf_Die die_mem;
int i;
int n = 0;
struct local_vars_finder vf = {.pf = pf, .args = args,
.max_args = MAX_PROBE_ARGS, .ret = 0};

for (i = 0; i < pf->pev->nargs; i++) {
/* var never be NULL */
if (strcmp(pf->pev->args[i].var, "$vars") == 0) {
pr_debug("Expanding $vars into:");
vf.nargs = n;
/* Special local variables */
die_find_child(sc_die, copy_variables_cb, (void *)&vf,
&die_mem);
pr_debug(" (%d)\n", vf.nargs - n);
if (vf.ret < 0)
return vf.ret;
n = vf.nargs;
} else {
/* Copy normal argument */
args[n] = pf->pev->args[i];
n++;
}
}
return n;
}

/* Add a found probe point into trace event list */
static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
{
struct trace_event_finder *tf =
container_of(pf, struct trace_event_finder, pf);
struct probe_trace_event *tev;
struct perf_probe_arg *args;
int ret, i;

/* Check number of tevs */
Expand All @@ -1161,21 +1227,35 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
tev->point.offset);

/* Find each argument */
tev->nargs = pf->pev->nargs;
tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
if (tev->args == NULL)
/* Expand special probe argument if exist */
args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
if (args == NULL)
return -ENOMEM;
for (i = 0; i < pf->pev->nargs; i++) {
pf->pvar = &pf->pev->args[i];

ret = expand_probe_args(sc_die, pf, args);
if (ret < 0)
goto end;

tev->nargs = ret;
tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
if (tev->args == NULL) {
ret = -ENOMEM;
goto end;
}

/* Find each argument */
for (i = 0; i < tev->nargs; i++) {
pf->pvar = &args[i];
pf->tvar = &tev->args[i];
/* Variable should be found from scope DIE */
ret = find_variable(sc_die, pf);
if (ret != 0)
return ret;
break;
}

return 0;
end:
free(args);
return ret;
}

/* Find probe_trace_events specified by perf_probe_event from debuginfo */
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/probe-finder.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#define MAX_PROBE_BUFFER 1024
#define MAX_PROBES 128
#define MAX_PROBE_ARGS 128

static inline int is_c_varname(const char *name)
{
Expand Down

0 comments on commit 7969ec7

Please sign in to comment.