diff options
author | Arjan van de Ven <arjan@linux.intel.com> | 2008-01-30 13:33:07 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 13:33:07 +0100 |
commit | e9d4efddbec3d852d435b370b9c40ff7ac24afe6 (patch) | |
tree | 5cfb9de18cb756cdde51a529c6aabbfaae3a13c0 | |
parent | bc850d6b374fffd08336996f4b4d3bbd6bf427f6 (diff) |
x86: improve the 32 bit Frame Pointer backtracer to also use the traditional backtrace
The 32 bit Frame Pointer backtracer code checks if the EBP is valid
to do a backtrace; however currently on a failure it just gives up
and prints nothing. That's not very nice; we can do better and still
print a decent backtrace.
This patch changes the backtracer to use the regular backtracing algorithm
at the same time as the EBP backtracer; the EBP backtracer is basically
used to figure out which part of the backtrace are reliable vs those
which are likely to be noise.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/kernel/traps_32.c | 44 |
1 files changed, 20 insertions, 24 deletions
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 8ef8a9ddfec6..959d40edecd5 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -118,36 +118,32 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, unsigned long *stack, unsigned long bp, const struct stacktrace_ops *ops, void *data) { -#ifdef CONFIG_FRAME_POINTER struct stack_frame *frame = (struct stack_frame *)bp; - while (valid_stack_ptr(tinfo, frame, sizeof(*frame))) { - struct stack_frame *next; - unsigned long addr; - addr = frame->return_address; - if (__kernel_text_address(addr)) - ops->address(data, addr, 1); - /* - * break out of recursive entries (such as - * end_of_stack_stop_unwind_function). Also, - * we can never allow a frame pointer to - * move downwards! - */ - next = frame->next_frame; - bp = (unsigned long) next; - if (next <= frame) - break; - frame = next; - } -#else + /* + * if EBP is "deeper" into the stack than the actual stack pointer, + * we need to rewind the stack pointer a little to start at the + * first stack frame, but only if EBP is in this stack frame. + */ + if (stack > (unsigned long *) bp + && valid_stack_ptr(tinfo, frame, sizeof(*frame))) + stack = (unsigned long *) bp; + while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) { unsigned long addr; - addr = *stack++; - if (__kernel_text_address(addr)) - ops->address(data, addr, 1); + addr = *stack; + if (__kernel_text_address(addr)) { + if ((unsigned long) stack == bp + 4) { + ops->address(data, addr, 1); + frame = frame->next_frame; + bp = (unsigned long) frame; + } else { + ops->address(data, addr, 0); + } + } + stack++; } -#endif return bp; } |