|
6 | 6 | */
|
7 | 7 |
|
8 | 8 | #include <linux/stacktrace.h>
|
| 9 | +#include <linux/uaccess.h> |
| 10 | +#include <linux/compat.h> |
9 | 11 | #include <asm/stacktrace.h>
|
10 | 12 | #include <asm/unwind.h>
|
11 | 13 | #include <asm/kprobes.h>
|
| 14 | +#include <asm/ptrace.h> |
12 | 15 |
|
13 | 16 | void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
|
14 | 17 | struct task_struct *task, struct pt_regs *regs)
|
@@ -58,3 +61,43 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
|
58 | 61 | return -EINVAL;
|
59 | 62 | return 0;
|
60 | 63 | }
|
| 64 | + |
| 65 | +void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, |
| 66 | + const struct pt_regs *regs) |
| 67 | +{ |
| 68 | + struct stack_frame_user __user *sf; |
| 69 | + unsigned long ip, sp; |
| 70 | + bool first = true; |
| 71 | + |
| 72 | + if (is_compat_task()) |
| 73 | + return; |
| 74 | + if (!consume_entry(cookie, instruction_pointer(regs))) |
| 75 | + return; |
| 76 | + sf = (void __user *)user_stack_pointer(regs); |
| 77 | + pagefault_disable(); |
| 78 | + while (1) { |
| 79 | + if (__get_user(sp, &sf->back_chain)) |
| 80 | + break; |
| 81 | + if (__get_user(ip, &sf->gprs[8])) |
| 82 | + break; |
| 83 | + if (ip & 0x1) { |
| 84 | + /* |
| 85 | + * If the instruction address is invalid, and this |
| 86 | + * is the first stack frame, assume r14 has not |
| 87 | + * been written to the stack yet. Otherwise exit. |
| 88 | + */ |
| 89 | + if (first && !(regs->gprs[14] & 0x1)) |
| 90 | + ip = regs->gprs[14]; |
| 91 | + else |
| 92 | + break; |
| 93 | + } |
| 94 | + if (!consume_entry(cookie, ip)) |
| 95 | + break; |
| 96 | + /* Sanity check: ABI requires SP to be aligned 8 bytes. */ |
| 97 | + if (!sp || sp & 0x7) |
| 98 | + break; |
| 99 | + sf = (void __user *)sp; |
| 100 | + first = false; |
| 101 | + } |
| 102 | + pagefault_enable(); |
| 103 | +} |
0 commit comments