forked from iipeace/guider
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathust_arm_apcs.patch
113 lines (111 loc) · 2.96 KB
/
ust_arm_apcs.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index 92b7237..5ac52e2 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -1,7 +1,9 @@
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/stacktrace.h>
+#include <linux/uaccess.h>
+#include <asm/uaccess.h>
#include <asm/stacktrace.h>
#include <asm/traps.h>
@@ -177,3 +179,98 @@ void save_stack_trace(struct stack_trace *trace)
}
EXPORT_SYMBOL_GPL(save_stack_trace);
#endif
+
+#ifdef CONFIG_USER_STACKTRACE_SUPPORT
+/*
+ * User-stack-tracer for ARM archtecture
+ * 1. enable CONFIG_USER_STACKTRACE_SUPPORT option in Kconfig
+ * 2. patch and rebuild kernel
+ * 3. build target binary with bellow options
+ * -g -mapcs-frame -rdynamic -fno-omit-frame-pointer option
+ */
+struct stack_frame_user {
+ unsigned long next_fp;
+ unsigned long ip;
+ unsigned long lr;
+ unsigned long pc;
+};
+
+static int copy_stack_frame_user(const void __user *fp,
+ struct stack_frame_user *frame)
+{
+ int ret = 0;
+
+ if (!access_ok(VERIFY_READ, fp, sizeof(*frame)))
+ return 0;
+
+ pagefault_disable();
+
+ ret = __copy_from_user_inatomic(frame, fp, sizeof(*frame));
+
+ pagefault_enable();
+
+ return !ret;
+}
+
+static inline void __save_stack_trace_user(struct stack_trace *trace)
+{
+ int try = 0;
+ int max_try = trace->max_entries * 2;
+ int offset = sizeof(struct stack_frame_user) - 4;
+ struct stack_frame_user frame;
+ const void __user *saved_addr;
+
+ const struct pt_regs *regs = task_pt_regs(current);
+ const void __user *fp = (const void __user *)regs->ARM_fp;
+ const void __user *sp = (const void __user *)regs->ARM_sp;
+
+ trace->entries[trace->nr_entries++] = regs->ARM_pc;
+
+ if (regs->ARM_lr) {
+ trace->entries[trace->nr_entries++] = regs->ARM_lr;
+ saved_addr = (const void __user *)regs->ARM_lr;
+ } else {
+ saved_addr = (const void __user *)regs->ARM_pc;
+ }
+
+ while (trace->nr_entries < trace->max_entries && try++ < max_try) {
+ if (!fp || !copy_stack_frame_user(fp - offset, &frame))
+ break;
+
+ if (!frame.lr) {
+ while(0);
+ } else if ((unsigned long)frame.lr & 0x1) {
+ /*
+ * Thumb code is not supported because
+ * FP register is not used in thumb mode.
+ * so that it is impossible to know
+ * base addr or size of stack frame.
+ */
+ trace->entries[trace->nr_entries++] = 0xC0FFEE;
+ break;
+ } else if (saved_addr != (const void __user *)frame.lr) {
+ trace->entries[trace->nr_entries++] = frame.lr;
+ saved_addr = (const void __user *)frame.lr;
+ }
+
+ if (frame.next_fp > (unsigned long)sp) {
+ fp = (const void __user *)frame.next_fp;
+ } else if (frame.ip > (unsigned long)sp) {
+ fp = (const void __user *)frame.ip;
+ } else {
+ break;
+ }
+ }
+}
+
+void save_stack_trace_user(struct stack_trace *trace)
+{
+ if (current->mm) {
+ __save_stack_trace_user(trace);
+
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+ }
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_user);
+#endif