diff options
Diffstat (limited to 'arch/arm/oprofile/backtrace.c')
| -rw-r--r-- | arch/arm/oprofile/backtrace.c | 46 |
1 files changed, 9 insertions, 37 deletions
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c index df35c452a8bf..7c22c12618cc 100644 --- a/arch/arm/oprofile/backtrace.c +++ b/arch/arm/oprofile/backtrace.c | |||
| @@ -49,42 +49,22 @@ static struct frame_tail* kernel_backtrace(struct frame_tail *tail) | |||
| 49 | 49 | ||
| 50 | static struct frame_tail* user_backtrace(struct frame_tail *tail) | 50 | static struct frame_tail* user_backtrace(struct frame_tail *tail) |
| 51 | { | 51 | { |
| 52 | struct frame_tail buftail; | 52 | struct frame_tail buftail[2]; |
| 53 | 53 | ||
| 54 | /* hardware pte might not be valid due to dirty/accessed bit emulation | 54 | /* Also check accessibility of one struct frame_tail beyond */ |
| 55 | * so we use copy_from_user and benefit from exception fixups */ | 55 | if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) |
| 56 | if (copy_from_user(&buftail, tail, sizeof(struct frame_tail))) | 56 | return NULL; |
| 57 | if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) | ||
| 57 | return NULL; | 58 | return NULL; |
| 58 | 59 | ||
| 59 | oprofile_add_trace(buftail.lr); | 60 | oprofile_add_trace(buftail[0].lr); |
| 60 | 61 | ||
| 61 | /* frame pointers should strictly progress back up the stack | 62 | /* frame pointers should strictly progress back up the stack |
| 62 | * (towards higher addresses) */ | 63 | * (towards higher addresses) */ |
| 63 | if (tail >= buftail.fp) | 64 | if (tail >= buftail[0].fp) |
| 64 | return NULL; | 65 | return NULL; |
| 65 | 66 | ||
| 66 | return buftail.fp-1; | 67 | return buftail[0].fp-1; |
| 67 | } | ||
| 68 | |||
| 69 | /* Compare two addresses and see if they're on the same page */ | ||
| 70 | #define CMP_ADDR_EQUAL(x,y,offset) ((((unsigned long) x) >> PAGE_SHIFT) \ | ||
| 71 | == ((((unsigned long) y) + offset) >> PAGE_SHIFT)) | ||
| 72 | |||
| 73 | /* check that the page(s) containing the frame tail are present */ | ||
| 74 | static int pages_present(struct frame_tail *tail) | ||
| 75 | { | ||
| 76 | struct mm_struct * mm = current->mm; | ||
| 77 | |||
| 78 | if (!check_user_page_readable(mm, (unsigned long)tail)) | ||
| 79 | return 0; | ||
| 80 | |||
| 81 | if (CMP_ADDR_EQUAL(tail, tail, 8)) | ||
| 82 | return 1; | ||
| 83 | |||
| 84 | if (!check_user_page_readable(mm, ((unsigned long)tail) + 8)) | ||
| 85 | return 0; | ||
| 86 | |||
| 87 | return 1; | ||
| 88 | } | 68 | } |
| 89 | 69 | ||
| 90 | /* | 70 | /* |
| @@ -118,7 +98,6 @@ static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs) | |||
| 118 | void arm_backtrace(struct pt_regs * const regs, unsigned int depth) | 98 | void arm_backtrace(struct pt_regs * const regs, unsigned int depth) |
| 119 | { | 99 | { |
| 120 | struct frame_tail *tail; | 100 | struct frame_tail *tail; |
| 121 | unsigned long last_address = 0; | ||
| 122 | 101 | ||
| 123 | tail = ((struct frame_tail *) regs->ARM_fp) - 1; | 102 | tail = ((struct frame_tail *) regs->ARM_fp) - 1; |
| 124 | 103 | ||
| @@ -132,13 +111,6 @@ void arm_backtrace(struct pt_regs * const regs, unsigned int depth) | |||
| 132 | return; | 111 | return; |
| 133 | } | 112 | } |
| 134 | 113 | ||
| 135 | while (depth-- && tail && !((unsigned long) tail & 3)) { | 114 | while (depth-- && tail && !((unsigned long) tail & 3)) |
| 136 | if ((!CMP_ADDR_EQUAL(last_address, tail, 0) | ||
| 137 | || !CMP_ADDR_EQUAL(last_address, tail, 8)) | ||
| 138 | && !pages_present(tail)) | ||
| 139 | return; | ||
| 140 | last_address = (unsigned long) tail; | ||
| 141 | tail = user_backtrace(tail); | 115 | tail = user_backtrace(tail); |
| 142 | } | ||
| 143 | } | 116 | } |
| 144 | |||
