Skip to content

Commit 752ec62

Browse files
Li HuafeiRussell King (Oracle)
authored andcommitted
ARM: 9234/1: stacktrace: Avoid duplicate saving of exception PC value
Because an exception stack frame is not created in the exception entry, save_trace() does special handling for the exception PC, but this is only needed when CONFIG_FRAME_POINTER_UNWIND=y. When CONFIG_ARM_UNWIND=y, unwind annotations have been added to the exception entry and save_trace() will repeatedly save the exception PC: [0x7f000090] hrtimer_hander+0x8/0x10 [hrtimer] [0x8019ec50] __hrtimer_run_queues+0x18c/0x394 [0x8019f760] hrtimer_run_queues+0xbc/0xd0 [0x8019def0] update_process_times+0x34/0x80 [0x801ad2a4] tick_periodic+0x48/0xd0 [0x801ad3dc] tick_handle_periodic+0x1c/0x7c [0x8010f2e0] twd_handler+0x30/0x40 [0x80177620] handle_percpu_devid_irq+0xa0/0x23c [0x801718d0] generic_handle_domain_irq+0x24/0x34 [0x80502d28] gic_handle_irq+0x74/0x88 [0x8085817c] generic_handle_arch_irq+0x58/0x78 [0x80100ba8] __irq_svc+0x88/0xc8 [0x80108114] arch_cpu_idle+0x38/0x3c [0x80108114] arch_cpu_idle+0x38/0x3c <==== duplicate saved exception PC [0x80861bf8] default_idle_call+0x38/0x130 [0x8015d5cc] do_idle+0x150/0x214 [0x8015d978] cpu_startup_entry+0x18/0x1c [0x808589c0] rest_init+0xd8/0xdc [0x80c00a44] arch_post_acpi_subsys_init+0x0/0x8 We can move the special handling of the exception PC in save_trace() to the unwind_frame() of the frame pointer unwinder. Signed-off-by: Li Huafei <[email protected]> Reviewed-by: Linus Waleij <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]>
1 parent 5854e4d commit 752ec62

File tree

3 files changed

+37
-14
lines changed

3 files changed

+37
-14
lines changed

arch/arm/include/asm/stacktrace.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ struct stackframe {
2121
struct llist_node *kr_cur;
2222
struct task_struct *tsk;
2323
#endif
24+
#ifdef CONFIG_UNWINDER_FRAME_POINTER
25+
bool ex_frame;
26+
#endif
2427
};
2528

2629
static __always_inline
@@ -34,6 +37,9 @@ void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)
3437
frame->kr_cur = NULL;
3538
frame->tsk = current;
3639
#endif
40+
#ifdef CONFIG_UNWINDER_FRAME_POINTER
41+
frame->ex_frame = in_entry_text(frame->pc);
42+
#endif
3743
}
3844

3945
extern int unwind_frame(struct stackframe *frame);

arch/arm/kernel/return_address.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void *return_address(unsigned int level)
4747
frame.kr_cur = NULL;
4848
frame.tsk = current;
4949
#endif
50+
frame.ex_frame = false;
5051

5152
walk_stackframe(&frame, save_return_addr, &data);
5253

arch/arm/kernel/stacktrace.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ int notrace unwind_frame(struct stackframe *frame)
8282
if (frame_pointer_check(frame))
8383
return -EINVAL;
8484

85+
/*
86+
* When we unwind through an exception stack, include the saved PC
87+
* value into the stack trace.
88+
*/
89+
if (frame->ex_frame) {
90+
struct pt_regs *regs = (struct pt_regs *)frame->sp;
91+
92+
/*
93+
* We check that 'regs + sizeof(struct pt_regs)' (that is,
94+
* &regs[1]) does not exceed the bottom of the stack to avoid
95+
* accessing data outside the task's stack. This may happen
96+
* when frame->ex_frame is a false positive.
97+
*/
98+
if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
99+
return -EINVAL;
100+
101+
frame->pc = regs->ARM_pc;
102+
frame->ex_frame = false;
103+
return 0;
104+
}
105+
85106
/* restore the registers from the stack frame */
86107
#ifdef CONFIG_CC_IS_CLANG
87108
frame->sp = frame->fp;
@@ -98,6 +119,9 @@ int notrace unwind_frame(struct stackframe *frame)
98119
(void *)frame->fp, &frame->kr_cur);
99120
#endif
100121

122+
if (in_entry_text(frame->pc))
123+
frame->ex_frame = true;
124+
101125
return 0;
102126
}
103127
#endif
@@ -128,7 +152,6 @@ static int save_trace(struct stackframe *frame, void *d)
128152
{
129153
struct stack_trace_data *data = d;
130154
struct stack_trace *trace = data->trace;
131-
struct pt_regs *regs;
132155
unsigned long addr = frame->pc;
133156

134157
if (data->no_sched_functions && in_sched_functions(addr))
@@ -139,19 +162,6 @@ static int save_trace(struct stackframe *frame, void *d)
139162
}
140163

141164
trace->entries[trace->nr_entries++] = addr;
142-
143-
if (trace->nr_entries >= trace->max_entries)
144-
return 1;
145-
146-
if (!in_entry_text(frame->pc))
147-
return 0;
148-
149-
regs = (struct pt_regs *)frame->sp;
150-
if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
151-
return 0;
152-
153-
trace->entries[trace->nr_entries++] = regs->ARM_pc;
154-
155165
return trace->nr_entries >= trace->max_entries;
156166
}
157167

@@ -193,6 +203,9 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
193203
frame.kr_cur = NULL;
194204
frame.tsk = tsk;
195205
#endif
206+
#ifdef CONFIG_UNWINDER_FRAME_POINTER
207+
frame.ex_frame = false;
208+
#endif
196209

197210
walk_stackframe(&frame, save_trace, &data);
198211
}
@@ -214,6 +227,9 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
214227
frame.kr_cur = NULL;
215228
frame.tsk = current;
216229
#endif
230+
#ifdef CONFIG_UNWINDER_FRAME_POINTER
231+
frame.ex_frame = in_entry_text(frame.pc);
232+
#endif
217233

218234
walk_stackframe(&frame, save_trace, &data);
219235
}

0 commit comments

Comments
 (0)