Skip to content

Commit

Permalink
ARM: stacktrace: include exception PC value in stacktrace output
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Russell King committed May 22, 2014
1 parent 3683f44 commit 07b4034
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions arch/arm/kernel/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <linux/stacktrace.h>

#include <asm/stacktrace.h>
#include <asm/traps.h>

#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
/*
Expand Down Expand Up @@ -61,6 +62,7 @@ EXPORT_SYMBOL(walk_stackframe);
#ifdef CONFIG_STACKTRACE
struct stack_trace_data {
struct stack_trace *trace;
unsigned long last_pc;
unsigned int no_sched_functions;
unsigned int skip;
};
Expand All @@ -69,6 +71,7 @@ static int save_trace(struct stackframe *frame, void *d)
{
struct stack_trace_data *data = d;
struct stack_trace *trace = data->trace;
struct pt_regs *regs;
unsigned long addr = frame->pc;

if (data->no_sched_functions && in_sched_functions(addr))
Expand All @@ -80,6 +83,25 @@ static int save_trace(struct stackframe *frame, void *d)

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;
}

Expand All @@ -91,6 +113,7 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
struct stackframe frame;

data.trace = trace;
data.last_pc = ULONG_MAX;
data.skip = trace->skip;
data.no_sched_functions = nosched;

Expand Down

0 comments on commit 07b4034

Please sign in to comment.