summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'driver/gator_backtrace.c')
-rw-r--r--driver/gator_backtrace.c76
1 files changed, 49 insertions, 27 deletions
diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c
index 94f01e6..0670d6c 100644
--- a/driver/gator_backtrace.c
+++ b/driver/gator_backtrace.c
@@ -10,16 +10,22 @@
10/* 10/*
11 * EABI backtrace stores {fp,lr} on the stack. 11 * EABI backtrace stores {fp,lr} on the stack.
12 */ 12 */
13struct frame_tail_eabi { 13struct stack_frame_eabi {
14 union { 14 union {
15 struct { 15 struct {
16 unsigned long fp; // points to prev_lr 16 unsigned long fp;
17 // May be the fp in the case of a leaf function or clang
17 unsigned long lr; 18 unsigned long lr;
19 // If lr is really the fp, lr2 is the corresponding lr
20 unsigned long lr2;
18 }; 21 };
19 // Used to read 32 bit fp/lr from a 64 bit kernel 22 // Used to read 32 bit fp/lr from a 64 bit kernel
20 struct { 23 struct {
21 u32 fp_32; 24 u32 fp_32;
25 // same as lr above
22 u32 lr_32; 26 u32 lr_32;
27 // same as lr2 above
28 u32 lr2_32;
23 }; 29 };
24 }; 30 };
25}; 31};
@@ -27,61 +33,76 @@ struct frame_tail_eabi {
27static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth) 33static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth)
28{ 34{
29#if defined(__arm__) || defined(__aarch64__) 35#if defined(__arm__) || defined(__aarch64__)
30 struct frame_tail_eabi *tail; 36 struct stack_frame_eabi *curr;
31 struct frame_tail_eabi *next; 37 struct stack_frame_eabi bufcurr;
32 struct frame_tail_eabi buftail;
33#if defined(__arm__) 38#if defined(__arm__)
34 const bool is_compat = false; 39 const bool is_compat = false;
35 unsigned long fp = regs->ARM_fp; 40 unsigned long fp = regs->ARM_fp;
36 unsigned long sp = regs->ARM_sp; 41 unsigned long sp = regs->ARM_sp;
37 unsigned long lr = regs->ARM_lr; 42 unsigned long lr = regs->ARM_lr;
38 const int frame_offset = 4; 43 const int gcc_frame_offset = sizeof(unsigned long);
39#else 44#else
40 // Is userspace aarch32 (32 bit) 45 // Is userspace aarch32 (32 bit)
41 const bool is_compat = compat_user_mode(regs); 46 const bool is_compat = compat_user_mode(regs);
42 unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]); 47 unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]);
43 unsigned long sp = (is_compat ? regs->compat_sp : regs->sp); 48 unsigned long sp = (is_compat ? regs->compat_sp : regs->sp);
44 unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]); 49 unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]);
45 const int frame_offset = (is_compat ? 4 : 0); 50 const int gcc_frame_offset = (is_compat ? sizeof(u32) : 0);
46#endif 51#endif
52 // clang frame offset is always zero
47 int is_user_mode = user_mode(regs); 53 int is_user_mode = user_mode(regs);
48 54
55 // pc (current function) has already been added
56
49 if (!is_user_mode) { 57 if (!is_user_mode) {
50 return; 58 return;
51 } 59 }
52 60
53 /* entry preamble may not have executed */ 61 // Add the lr (parent function)
62 // entry preamble may not have executed
54 gator_add_trace(cpu, lr); 63 gator_add_trace(cpu, lr);
55 64
56 /* check tail is valid */ 65 // check fp is valid
57 if (fp == 0 || fp < sp) { 66 if (fp == 0 || fp < sp) {
58 return; 67 return;
59 } 68 }
60 69
61 tail = (struct frame_tail_eabi *)(fp - frame_offset); 70 // Get the current stack frame
71 curr = (struct stack_frame_eabi *)(fp - gcc_frame_offset);
72 if ((unsigned long)curr & 3) {
73 return;
74 }
62 75
63 while (depth-- && tail && !((unsigned long)tail & 3)) { 76 while (depth-- && curr) {
64 /* Also check accessibility of one struct frame_tail beyond */ 77 if (!access_ok(VERIFY_READ, curr, sizeof(struct stack_frame_eabi)) ||
65 if (!access_ok(VERIFY_READ, tail, sizeof(struct frame_tail_eabi))) 78 __copy_from_user_inatomic(&bufcurr, curr, sizeof(struct stack_frame_eabi))) {
66 return;
67 if (__copy_from_user_inatomic(&buftail, tail, sizeof(struct frame_tail_eabi)))
68 return; 79 return;
80 }
81
82 fp = (is_compat ? bufcurr.fp_32 : bufcurr.fp);
83 lr = (is_compat ? bufcurr.lr_32 : bufcurr.lr);
84
85#define calc_next(reg) ((reg) - gcc_frame_offset)
86 // Returns true if reg is a valid fp
87#define validate_next(reg, curr) \
88 ((reg) != 0 && (calc_next(reg) & 3) == 0 && (unsigned long)(curr) < calc_next(reg))
89
90 // Try lr from the stack as the fp because gcc leaf functions do not push lr
91 // If gcc_frame_offset is non-zero, the lr will also be the clang fp
92 // This assumes code is at a lower address than the stack
93 if (validate_next(lr, curr)) {
94 fp = lr;
95 lr = (is_compat ? bufcurr.lr2_32 : bufcurr.lr2);
96 }
69 97
70 lr = (is_compat ? buftail.lr_32 : buftail.lr);
71 gator_add_trace(cpu, lr); 98 gator_add_trace(cpu, lr);
72 99
73 /* frame pointers should progress back up the stack, towards higher addresses */ 100 if (!validate_next(fp, curr)) {
74 next = (struct frame_tail_eabi *)(lr - frame_offset); 101 return;
75 if (tail >= next || lr == 0) {
76 fp = (is_compat ? buftail.fp_32 : buftail.fp);
77 next = (struct frame_tail_eabi *)(fp - frame_offset);
78 /* check tail is valid */
79 if (tail >= next || fp == 0) {
80 return;
81 }
82 } 102 }
83 103
84 tail = next; 104 // Move to the next stack frame
105 curr = (struct stack_frame_eabi *)calc_next(fp);
85 } 106 }
86#endif 107#endif
87} 108}
@@ -89,11 +110,12 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
89#if defined(__arm__) || defined(__aarch64__) 110#if defined(__arm__) || defined(__aarch64__)
90static int report_trace(struct stackframe *frame, void *d) 111static int report_trace(struct stackframe *frame, void *d)
91{ 112{
92 unsigned int *depth = d, cookie = NO_COOKIE, cpu = get_physical_cpu(); 113 unsigned int *depth = d, cookie = NO_COOKIE;
93 unsigned long addr = frame->pc; 114 unsigned long addr = frame->pc;
94 115
95 if (*depth) { 116 if (*depth) {
96#if defined(MODULE) 117#if defined(MODULE)
118 unsigned int cpu = get_physical_cpu();
97 struct module *mod = __module_address(addr); 119 struct module *mod = __module_address(addr);
98 if (mod) { 120 if (mod) {
99 cookie = get_cookie(cpu, current, mod->name, false); 121 cookie = get_cookie(cpu, current, mod->name, false);