ARM: stacktrace: include exception PC value in stacktrace output
When we unwind through an exception stack, include the saved PC value into the stack trace: this fills in an otherwise missed functions from the trace (as indicated below): [<c03f4424>] fec_enet_interrupt+0xa0/0xe8 [<c0066c0c>] handle_irq_event_percpu+0x68/0x228 [<c0066e18>] handle_irq_event+0x4c/0x6c [<c006a024>] handle_fasteoi_irq+0xac/0x198 [<c00664b0>] generic_handle_irq+0x4c/0x60 [<c000f014>] handle_IRQ+0x40/0x98 [<c0008554>] gic_handle_irq+0x30/0x64 [<c0012900>] __irq_svc+0x40/0x50 [<c0029030>] __do_softirq+0xe0/0x2fc <==== [<c0029500>] irq_exit+0xb0/0x100 [<c000f018>] handle_IRQ+0x44/0x98 [<c0008554>] gic_handle_irq+0x30/0x64 [<c0012900>] __irq_svc+0x40/0x50 [<c000f34c>] arch_cpu_idle+0x30/0x38 <==== [<c005e1e4>] cpu_startup_entry+0xac/0x214 [<c066297c>] rest_init+0x68/0x80 [<c08ccb10>] start_kernel+0x2fc/0x358 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Родитель
3683f44c42
Коммит
07b4034158
|
@ -3,6 +3,7 @@
|
||||||
#include <linux/stacktrace.h>
|
#include <linux/stacktrace.h>
|
||||||
|
|
||||||
#include <asm/stacktrace.h>
|
#include <asm/stacktrace.h>
|
||||||
|
#include <asm/traps.h>
|
||||||
|
|
||||||
#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
|
#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
|
||||||
/*
|
/*
|
||||||
|
@ -61,6 +62,7 @@ EXPORT_SYMBOL(walk_stackframe);
|
||||||
#ifdef CONFIG_STACKTRACE
|
#ifdef CONFIG_STACKTRACE
|
||||||
struct stack_trace_data {
|
struct stack_trace_data {
|
||||||
struct stack_trace *trace;
|
struct stack_trace *trace;
|
||||||
|
unsigned long last_pc;
|
||||||
unsigned int no_sched_functions;
|
unsigned int no_sched_functions;
|
||||||
unsigned int skip;
|
unsigned int skip;
|
||||||
};
|
};
|
||||||
|
@ -69,6 +71,7 @@ static int save_trace(struct stackframe *frame, void *d)
|
||||||
{
|
{
|
||||||
struct stack_trace_data *data = d;
|
struct stack_trace_data *data = d;
|
||||||
struct stack_trace *trace = data->trace;
|
struct stack_trace *trace = data->trace;
|
||||||
|
struct pt_regs *regs;
|
||||||
unsigned long addr = frame->pc;
|
unsigned long addr = frame->pc;
|
||||||
|
|
||||||
if (data->no_sched_functions && in_sched_functions(addr))
|
if (data->no_sched_functions && in_sched_functions(addr))
|
||||||
|
@ -80,6 +83,25 @@ static int save_trace(struct stackframe *frame, void *d)
|
||||||
|
|
||||||
trace->entries[trace->nr_entries++] = addr;
|
trace->entries[trace->nr_entries++] = addr;
|
||||||
|
|
||||||
|
if (trace->nr_entries >= trace->max_entries)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* in_exception_text() is designed to test if the PC is one of
|
||||||
|
* the functions which has an exception stack above it, but
|
||||||
|
* unfortunately what is in frame->pc is the return LR value,
|
||||||
|
* not the saved PC value. So, we need to track the previous
|
||||||
|
* frame PC value when doing this.
|
||||||
|
*/
|
||||||
|
addr = data->last_pc;
|
||||||
|
data->last_pc = frame->pc;
|
||||||
|
if (!in_exception_text(addr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
regs = (struct pt_regs *)frame->sp;
|
||||||
|
|
||||||
|
trace->entries[trace->nr_entries++] = regs->ARM_pc;
|
||||||
|
|
||||||
return trace->nr_entries >= trace->max_entries;
|
return trace->nr_entries >= trace->max_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +113,7 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
|
||||||
struct stackframe frame;
|
struct stackframe frame;
|
||||||
|
|
||||||
data.trace = trace;
|
data.trace = trace;
|
||||||
|
data.last_pc = ULONG_MAX;
|
||||||
data.skip = trace->skip;
|
data.skip = trace->skip;
|
||||||
data.no_sched_functions = nosched;
|
data.no_sched_functions = nosched;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче