Skip to content

Commit

Permalink
perf probe: Support static and global variables
Browse files Browse the repository at this point in the history
Add static and global variables support to perf probe.
This allows user to trace non-local variables (and
structure members) at probe points.

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: <20100519195749.2885.17451.stgit@localhost6.localdomain6>
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Masami Hiramatsu authored and Arnaldo Carvalho de Melo committed Jul 5, 2010
1 parent b2a3c12 commit b7dcb85
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 27 deletions.
15 changes: 12 additions & 3 deletions tools/perf/util/probe-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,7 @@ static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
char *buf, size_t buflen)
{
struct kprobe_trace_arg_ref *ref = arg->ref;
int ret, depth = 0;
char *tmp = buf;

Expand All @@ -939,16 +940,24 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
buf += ret;
buflen -= ret;

/* Special case: @XXX */
if (arg->value[0] == '@' && arg->ref)
ref = ref->next;

/* Dereferencing arguments */
if (arg->ref) {
depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
if (ref) {
depth = __synthesize_kprobe_trace_arg_ref(ref, &buf,
&buflen, 1);
if (depth < 0)
return depth;
}

/* Print argument value */
ret = e_snprintf(buf, buflen, "%s", arg->value);
if (arg->value[0] == '@' && arg->ref)
ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
arg->ref->offset);
else
ret = e_snprintf(buf, buflen, "%s", arg->value);
if (ret < 0)
return ret;
buf += ret;
Expand Down
85 changes: 61 additions & 24 deletions tools/perf/util/probe-finder.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,14 +406,50 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
* Probe finder related functions
*/

static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs)
{
struct kprobe_trace_arg_ref *ref;
ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
if (ref != NULL)
ref->offset = offs;
return ref;
}

/* Show a location */
static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
{
Dwarf_Attribute attr;
Dwarf_Op *op;
size_t nops;
unsigned int regn;
Dwarf_Word offs = 0;
bool ref = false;
const char *regs;
struct kprobe_trace_arg *tvar = pf->tvar;
int ret;

/* TODO: handle more than 1 exprs */
if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
nops == 0) {
/* TODO: Support const_value */
pr_err("Failed to find the location of %s at this address.\n"
" Perhaps, it has been optimized out.\n", pf->pvar->var);
return -ENOENT;
}

if (op->atom == DW_OP_addr) {
/* Static variables on memory (not stack), make @varname */
ret = strlen(dwarf_diename(vr_die));
tvar->value = zalloc(ret + 2);
if (tvar->value == NULL)
return -ENOMEM;
snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
tvar->ref = alloc_trace_arg_ref((long)offs);
if (tvar->ref == NULL)
return -ENOMEM;
return 0;
}

/* If this is based on frame buffer, set the offset */
if (op->atom == DW_OP_fbreg) {
Expand Down Expand Up @@ -455,10 +491,9 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
return -ENOMEM;

if (ref) {
tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
tvar->ref = alloc_trace_arg_ref((long)offs);
if (tvar->ref == NULL)
return -ENOMEM;
tvar->ref->offset = (long)offs;
}
return 0;
}
Expand Down Expand Up @@ -666,20 +701,13 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
/* Show a variables in kprobe event format */
static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
{
Dwarf_Attribute attr;
Dwarf_Die die_mem;
Dwarf_Op *expr;
size_t nexpr;
int ret;

if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
goto error;
/* TODO: handle more than 1 exprs */
ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
if (ret <= 0 || nexpr == 0)
goto error;
pr_debug("Converting variable %s into trace event.\n",
dwarf_diename(vr_die));

ret = convert_location(expr, pf);
ret = convert_variable_location(vr_die, pf);
if (ret == 0 && pf->pvar->field) {
ret = convert_variable_fields(vr_die, pf->pvar->var,
pf->pvar->field, &pf->tvar->ref,
Expand All @@ -690,19 +718,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
/* *expr will be cached in libdw. Don't free it. */
return ret;
error:
/* TODO: Support const_value */
pr_err("Failed to find the location of %s at this address.\n"
" Perhaps, it has been optimized out.\n", pf->pvar->var);
return -ENOENT;
}

/* Find a variable in a subprogram die */
static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
{
Dwarf_Die vr_die;
Dwarf_Die vr_die, *scopes;
char buf[32], *ptr;
int ret;
int ret, nscopes;

if (pf->pvar->name)
pf->tvar->name = strdup(pf->pvar->name);
Expand Down Expand Up @@ -730,12 +753,26 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
pr_debug("Searching '%s' variable in context.\n",
pf->pvar->var);
/* Search child die for local variables and parameters. */
if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) {
if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
ret = convert_variable(&vr_die, pf);
else {
/* Search upper class */
nscopes = dwarf_getscopes_die(sp_die, &scopes);
if (nscopes > 0) {
ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
0, NULL, 0, 0, &vr_die);
if (ret >= 0)
ret = convert_variable(&vr_die, pf);
else
ret = -ENOENT;
free(scopes);
} else
ret = -ENOENT;
}
if (ret < 0)
pr_warning("Failed to find '%s' in this function.\n",
pf->pvar->var);
return -ENOENT;
}
return convert_variable(&vr_die, pf);
return ret;
}

/* Show a probe point to output buffer */
Expand Down

0 comments on commit b7dcb85

Please sign in to comment.