Skip to content

Commit

Permalink
perf events, x86/stacktrace: Make stack walking optional
Browse files Browse the repository at this point in the history
The current print_context_stack helper that does the stack
walking job is good for usual stacktraces as it walks through
all the stack and reports even addresses that look unreliable,
which is nice when we don't have frame pointers for example.

But we have users like perf that only require reliable
stacktraces, and those may want a more adapted stack walker, so
lets make this function a callback in stacktrace_ops that users
can tune for their needs.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1261024834-5336-1-git-send-regression-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Frederic Weisbecker authored and Ingo Molnar committed Dec 17, 2009
1 parent 5b74ed4 commit 61c1917
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 25 deletions.
18 changes: 18 additions & 0 deletions arch/x86/include/asm/stacktrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ extern int kstack_depth_to_print;

int x86_is_stack_id(int id, char *name);

struct thread_info;
struct stacktrace_ops;

typedef unsigned long (*walk_stack_t)(struct thread_info *tinfo,
unsigned long *stack,
unsigned long bp,
const struct stacktrace_ops *ops,
void *data,
unsigned long *end,
int *graph);

extern unsigned long
print_context_stack(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data,
unsigned long *end, int *graph);

/* Generic stack tracer with callbacks */

struct stacktrace_ops {
Expand All @@ -14,6 +31,7 @@ struct stacktrace_ops {
void (*address)(void *data, unsigned long address, int reliable);
/* On negative return stop dumping */
int (*stack)(void *data, char *name);
walk_stack_t walk_stack;
};

void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
Expand Down
1 change: 1 addition & 0 deletions arch/x86/kernel/cpu/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -2336,6 +2336,7 @@ static const struct stacktrace_ops backtrace_ops = {
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.walk_stack = print_context_stack,
};

#include "../dumpstack.h"
Expand Down
9 changes: 5 additions & 4 deletions arch/x86/kernel/dumpstack.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,11 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
}

static const struct stacktrace_ops print_trace_ops = {
.warning = print_trace_warning,
.warning_symbol = print_trace_warning_symbol,
.stack = print_trace_stack,
.address = print_trace_address,
.warning = print_trace_warning,
.warning_symbol = print_trace_warning_symbol,
.stack = print_trace_stack,
.address = print_trace_address,
.walk_stack = print_context_stack,
};

void
Expand Down
6 changes: 0 additions & 6 deletions arch/x86/kernel/dumpstack.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
#endif

extern unsigned long
print_context_stack(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data,
unsigned long *end, int *graph);

extern void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp, char *log_lvl);
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/dumpstack_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,

context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1)));
bp = print_context_stack(context, stack, bp, ops, data, NULL, &graph);
bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);

stack = (unsigned long *)context->previous_esp;
if (!stack)
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/kernel/dumpstack_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
if (ops->stack(data, id) < 0)
break;

bp = print_context_stack(tinfo, stack, bp, ops,
data, estack_end, &graph);
bp = ops->walk_stack(tinfo, stack, bp, ops,
data, estack_end, &graph);
ops->stack(data, "<EOE>");
/*
* We link to the next stack via the
Expand Down
18 changes: 10 additions & 8 deletions arch/x86/kernel/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,19 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable)
}

static const struct stacktrace_ops save_stack_ops = {
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address,
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address,
.walk_stack = print_context_stack,
};

static const struct stacktrace_ops save_stack_ops_nosched = {
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address_nosched,
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address_nosched,
.walk_stack = print_context_stack,
};

/*
Expand Down
9 changes: 5 additions & 4 deletions arch/x86/oprofile/backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
}

static struct stacktrace_ops backtrace_ops = {
.warning = backtrace_warning,
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.warning = backtrace_warning,
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.walk_stack = print_context_stack,
};

struct frame_head {
Expand Down
1 change: 1 addition & 0 deletions kernel/trace/trace_sysprof.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ static const struct stacktrace_ops backtrace_ops = {
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.walk_stack = print_context_stack,
};

static int
Expand Down

0 comments on commit 61c1917

Please sign in to comment.