parisc: Fix stack unwinder
Debugging shows a large number of unaligned access traps in the unwinder code. Code analysis reveals a number of issues with this code: - handle_interruption is passed twice through dereference_kernel_function_descriptor() - ret_from_kernel_thread, syscall_exit, intr_return, _switch_to_ret, and _call_on_stack are passed through dereference_kernel_function_descriptor() even though they are not declared as function pointers. To fix the problems, drop one of the calls to dereference_kernel_function_descriptor() for handle_interruption, and compare the other pointers directly. Fixes:6414b30b39
("parisc: unwind: Avoid missing prototype warning for handle_interruption()") Fixes:8e0ba125c2
("parisc/unwind: fix unwinder when CONFIG_64BIT is enabled") Cc: Helge Deller <deller@gmx.de> Cc: Sven Schnelle <svens@stackframe.org> Cc: John David Anglin <dave.anglin@bell.net> Cc: Charlie Jenkins <charlie@rivosinc.com> Cc: David Laight <David.Laight@ACULAB.COM> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Helge Deller <deller@gmx.de>
This commit is contained in:
parent
f945a404ed
commit
882a2a724e
@ -228,10 +228,8 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
|
||||
#ifdef CONFIG_IRQSTACKS
|
||||
extern void * const _call_on_stack;
|
||||
#endif /* CONFIG_IRQSTACKS */
|
||||
void *ptr;
|
||||
|
||||
ptr = dereference_kernel_function_descriptor(&handle_interruption);
|
||||
if (pc_is_kernel_fn(pc, ptr)) {
|
||||
if (pc_is_kernel_fn(pc, handle_interruption)) {
|
||||
struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
|
||||
dbg("Unwinding through handle_interruption()\n");
|
||||
info->prev_sp = regs->gr[30];
|
||||
@ -239,13 +237,13 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pc_is_kernel_fn(pc, ret_from_kernel_thread) ||
|
||||
pc_is_kernel_fn(pc, syscall_exit)) {
|
||||
if (pc == (unsigned long)&ret_from_kernel_thread ||
|
||||
pc == (unsigned long)&syscall_exit) {
|
||||
info->prev_sp = info->prev_ip = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pc_is_kernel_fn(pc, intr_return)) {
|
||||
if (pc == (unsigned long)&intr_return) {
|
||||
struct pt_regs *regs;
|
||||
|
||||
dbg("Found intr_return()\n");
|
||||
@ -257,14 +255,14 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
|
||||
}
|
||||
|
||||
if (pc_is_kernel_fn(pc, _switch_to) ||
|
||||
pc_is_kernel_fn(pc, _switch_to_ret)) {
|
||||
pc == (unsigned long)&_switch_to_ret) {
|
||||
info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
|
||||
info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IRQSTACKS
|
||||
if (pc_is_kernel_fn(pc, _call_on_stack)) {
|
||||
if (pc == (unsigned long)&_call_on_stack) {
|
||||
info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
|
||||
info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
|
||||
return 1;
|
||||
|
Loading…
Reference in New Issue
Block a user