Skip to content

Commit

Permalink
perf probe: Support DW_OP_call_frame_cfa in debuginfo
Browse files Browse the repository at this point in the history
When building kernel without CONFIG_FRAME_POINTER, gcc uses
CFA (canonical frame address) for frame base. With this patch,
perf probe just gets CFI (call frame information) from debuginfo
and search corresponding CFA from the CFI. IOW, this allows
perf probe works correctly on the kernel without CONFIG_FRAME_POINTER.

<Before>
 ./perf probe -fn sched_slice:12 lw.weight
  Fatal: DW_OP 156 is not supported.
              (^^^ DW_OP_call_frame_cfa)

<After>
./perf probe -fn sched_slice:12 lw.weight
Add new event:
  probe:sched_slice    (on sched_slice:12 with weight=lw.weight)

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: <20100412171728.3790.98217.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 Apr 14, 2010
1 parent 11a1ca3 commit a34a985
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 3 deletions.
14 changes: 11 additions & 3 deletions tools/perf/util/probe-finder.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,6 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
const char *regs;
struct kprobe_trace_arg *tvar = pf->tvar;

/* TODO: support CFA */
/* If this is based on frame buffer, set the offset */
if (op->atom == DW_OP_fbreg) {
if (pf->fb_ops == NULL)
Expand Down Expand Up @@ -629,11 +628,17 @@ static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
/* Get the frame base attribute/ops */
dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
if (ret <= 0 || nops == 0)
if (ret <= 0 || nops == 0) {
pf->fb_ops = NULL;
} else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
pf->cfi != NULL) {
Dwarf_Frame *frame;
ret = dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame);
DIE_IF(ret != 0);
dwarf_frame_cfa(frame, &pf->fb_ops, &nops);
}

/* Find each argument */
/* TODO: use dwarf_cfi_addrframe */
tev->nargs = pf->pev->nargs;
tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
for (i = 0; i < pf->pev->nargs; i++) {
Expand Down Expand Up @@ -842,6 +847,9 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
if (!dbg)
return -ENOENT;

/* Get the call frame information from this dwarf */
pf.cfi = dwarf_getcfi(dbg);

off = 0;
line_list__init(&pf.lcache);
/* Loop on CUs (Compilation Unit) */
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 @@ -42,6 +42,7 @@ struct probe_finder {
struct list_head lcache; /* Line cache for lazy match */

/* For variable searching */
Dwarf_CFI *cfi; /* Call Frame Information */
Dwarf_Op *fb_ops; /* Frame base attribute */
struct perf_probe_arg *pvar; /* Current target variable */
struct kprobe_trace_arg *tvar; /* Current result variable */
Expand Down

0 comments on commit a34a985

Please sign in to comment.