diff options
author | Andi Kleen <ak@suse.de> | 2006-12-06 20:14:12 -0500 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-12-06 20:14:12 -0500 |
commit | e2124bb8d369a4bc1afde1959040e33d71c41d5e (patch) | |
tree | 66edded37e2922f255b53645416fbfd0c2fd0cd8 /kernel/unwind.c | |
parent | f3d73707a1e84f0687a05144b70b660441e999c7 (diff) |
[PATCH] unwinder: Use probe_kernel_address instead of __get_user in kernel/unwind.c
This avoids trouble with the page fault handler if the fault
happens inside an interrupt context.
Suggested by Linus
Cc: jbeulich@novell.com
Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'kernel/unwind.c')
-rw-r--r-- | kernel/unwind.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/kernel/unwind.c b/kernel/unwind.c index ed0a21d4a902..af48168a3afb 100644 --- a/kernel/unwind.c +++ b/kernel/unwind.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/bootmem.h> | 14 | #include <linux/bootmem.h> |
15 | #include <linux/sort.h> | 15 | #include <linux/sort.h> |
16 | #include <linux/stop_machine.h> | 16 | #include <linux/stop_machine.h> |
17 | #include <linux/uaccess.h> | ||
17 | #include <asm/sections.h> | 18 | #include <asm/sections.h> |
18 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
19 | #include <asm/unaligned.h> | 20 | #include <asm/unaligned.h> |
@@ -550,7 +551,7 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
550 | return 0; | 551 | return 0; |
551 | } | 552 | } |
552 | if ((ptrType & DW_EH_PE_indirect) | 553 | if ((ptrType & DW_EH_PE_indirect) |
553 | && __get_user(value, (unsigned long *)value)) | 554 | && probe_kernel_address((unsigned long *)value, value)) |
554 | return 0; | 555 | return 0; |
555 | *pLoc = ptr.p8; | 556 | *pLoc = ptr.p8; |
556 | 557 | ||
@@ -982,18 +983,19 @@ int unwind(struct unwind_frame_info *frame) | |||
982 | & (sizeof(unsigned long) - 1))) { | 983 | & (sizeof(unsigned long) - 1))) { |
983 | unsigned long link; | 984 | unsigned long link; |
984 | 985 | ||
985 | if (!__get_user(link, | 986 | if (!probe_kernel_address( |
986 | (unsigned long *)(UNW_FP(frame) | 987 | (unsigned long *)(UNW_FP(frame) |
987 | + FRAME_LINK_OFFSET)) | 988 | + FRAME_LINK_OFFSET), |
989 | link) | ||
988 | # if FRAME_RETADDR_OFFSET < 0 | 990 | # if FRAME_RETADDR_OFFSET < 0 |
989 | && link > bottom && link < UNW_FP(frame) | 991 | && link > bottom && link < UNW_FP(frame) |
990 | # else | 992 | # else |
991 | && link > UNW_FP(frame) && link < bottom | 993 | && link > UNW_FP(frame) && link < bottom |
992 | # endif | 994 | # endif |
993 | && !(link & (sizeof(link) - 1)) | 995 | && !(link & (sizeof(link) - 1)) |
994 | && !__get_user(UNW_PC(frame), | 996 | && !probe_kernel_address( |
995 | (unsigned long *)(UNW_FP(frame) | 997 | (unsigned long *)(UNW_FP(frame) |
996 | + FRAME_RETADDR_OFFSET))) { | 998 | + FRAME_RETADDR_OFFSET), UNW_PC(frame))) { |
997 | UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET | 999 | UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET |
998 | # if FRAME_RETADDR_OFFSET < 0 | 1000 | # if FRAME_RETADDR_OFFSET < 0 |
999 | - | 1001 | - |
@@ -1104,7 +1106,7 @@ int unwind(struct unwind_frame_info *frame) | |||
1104 | return -EIO; | 1106 | return -EIO; |
1105 | switch(reg_info[i].width) { | 1107 | switch(reg_info[i].width) { |
1106 | #define CASE(n) case sizeof(u##n): \ | 1108 | #define CASE(n) case sizeof(u##n): \ |
1107 | __get_user(FRAME_REG(i, u##n), (u##n *)addr); \ | 1109 | probe_kernel_address((u##n *)addr, FRAME_REG(i, u##n)); \ |
1108 | break | 1110 | break |
1109 | CASES; | 1111 | CASES; |
1110 | #undef CASE | 1112 | #undef CASE |