1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/kernel.h>
25#include <linux/highmem.h>
26#include <linux/uprobes.h>
27#include <linux/uaccess.h>
28#include <linux/sched.h>
29#include <linux/kdebug.h>
30
31#include <asm/cacheflush.h>
32#include <linux/uaccess.h>
33
34
35
36
37
38
39unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
40{
41 return instruction_pointer(regs);
42}
43
44static void copy_to_page(struct page *page, unsigned long vaddr,
45 const void *src, int len)
46{
47 void *kaddr = kmap_atomic(page);
48
49 memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len);
50 kunmap_atomic(kaddr);
51}
52
53
54
55
56
57
58
59
60void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
61 void *src, unsigned long len)
62{
63 const u32 stp_insn = UPROBE_STP_INSN;
64 u32 insn = *(u32 *) src;
65
66
67
68
69
70
71
72 u32 op = (insn >> 30) & 0x3;
73 u32 op2 = (insn >> 22) & 0x7;
74
75 if (op == 0 &&
76 (op2 == 1 || op2 == 2 || op2 == 3 || op2 == 5 || op2 == 6) &&
77 (insn & ANNUL_BIT) == ANNUL_BIT)
78 insn &= ~ANNUL_BIT;
79
80 copy_to_page(page, vaddr, &insn, len);
81 copy_to_page(page, vaddr+len, &stp_insn, 4);
82}
83
84
85
86
87
88
89int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
90 struct mm_struct *mm, unsigned long addr)
91{
92
93 return 0;
94}
95
96
97
98
99
100
101
102
103
104static unsigned long relbranch_fixup(u32 insn, struct uprobe_task *utask,
105 struct pt_regs *regs)
106{
107
108 if (regs->tnpc == regs->tpc + 0x4UL)
109 return utask->autask.saved_tnpc + 0x4UL;
110
111
112
113
114 if ((insn & 0xc0000000) == 0x40000000 ||
115 (insn & 0xc1c00000) == 0x00400000 ||
116 (insn & 0xc1c00000) == 0x00800000) {
117 unsigned long real_pc = (unsigned long) utask->vaddr;
118 unsigned long ixol_addr = utask->xol_vaddr;
119
120
121
122
123
124 return (real_pc + (regs->tnpc - ixol_addr));
125 }
126
127
128
129
130 return regs->tnpc;
131}
132
133
134
135
136static int retpc_fixup(struct pt_regs *regs, u32 insn,
137 unsigned long real_pc)
138{
139 unsigned long *slot = NULL;
140 int rc = 0;
141
142
143 if ((insn & 0xc0000000) == 0x40000000)
144 slot = ®s->u_regs[UREG_I7];
145
146
147 if ((insn & 0xc1f80000) == 0x81c00000) {
148 unsigned long rd = ((insn >> 25) & 0x1f);
149
150 if (rd <= 15) {
151 slot = ®s->u_regs[rd];
152 } else {
153 unsigned long fp = regs->u_regs[UREG_FP];
154
155 flushw_all();
156
157 rd -= 16;
158 if (test_thread_64bit_stack(fp)) {
159 unsigned long __user *uslot =
160 (unsigned long __user *) (fp + STACK_BIAS) + rd;
161 rc = __put_user(real_pc, uslot);
162 } else {
163 unsigned int __user *uslot = (unsigned int
164 __user *) fp + rd;
165 rc = __put_user((u32) real_pc, uslot);
166 }
167 }
168 }
169 if (slot != NULL)
170 *slot = real_pc;
171 return rc;
172}
173
174
175
176
177
178
179
180
181
182bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
183{
184
185
186
187 if (auprobe->ixol == (1 << 24)) {
188 regs->tnpc += 4;
189 regs->tpc += 4;
190 return true;
191 }
192
193 return false;
194}
195
196
197
198
199
200
201
202
203int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
204{
205 struct uprobe_task *utask = current->utask;
206 struct arch_uprobe_task *autask = ¤t->utask->autask;
207
208
209
210
211 autask->saved_tpc = regs->tpc;
212 autask->saved_tnpc = regs->tnpc;
213
214
215
216
217 instruction_pointer_set(regs, utask->xol_vaddr);
218
219 return 0;
220}
221
222
223
224
225
226
227
228
229int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
230{
231 struct uprobe_task *utask = current->utask;
232 struct arch_uprobe_task *autask = &utask->autask;
233 u32 insn = auprobe->ixol;
234 int rc = 0;
235
236 if (utask->state == UTASK_SSTEP_ACK) {
237 regs->tnpc = relbranch_fixup(insn, utask, regs);
238 regs->tpc = autask->saved_tnpc;
239 rc = retpc_fixup(regs, insn, (unsigned long) utask->vaddr);
240 } else {
241 regs->tnpc = utask->vaddr+4;
242 regs->tpc = autask->saved_tnpc+4;
243 }
244 return rc;
245}
246
247
248
249
250asmlinkage void uprobe_trap(struct pt_regs *regs,
251 unsigned long trap_level)
252{
253 BUG_ON(trap_level != 0x173 && trap_level != 0x174);
254
255
256
257
258 if (!user_mode(regs)) {
259 local_irq_enable();
260 bad_trap(regs, trap_level);
261 return;
262 }
263
264
265
266
267 if (notify_die((trap_level == 0x173) ? DIE_BPT : DIE_SSTEP,
268 (trap_level == 0x173) ? "bpt" : "sstep",
269 regs, 0, trap_level, SIGTRAP) != NOTIFY_STOP)
270 bad_trap(regs, trap_level);
271}
272
273
274
275int arch_uprobe_exception_notify(struct notifier_block *self,
276 unsigned long val, void *data)
277{
278 int ret = NOTIFY_DONE;
279 struct die_args *args = (struct die_args *)data;
280
281
282 if (args->regs && !user_mode(args->regs))
283 return NOTIFY_DONE;
284
285 switch (val) {
286 case DIE_BPT:
287 if (uprobe_pre_sstep_notifier(args->regs))
288 ret = NOTIFY_STOP;
289 break;
290
291 case DIE_SSTEP:
292 if (uprobe_post_sstep_notifier(args->regs))
293 ret = NOTIFY_STOP;
294
295 default:
296 break;
297 }
298
299 return ret;
300}
301
302
303
304
305
306void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
307{
308 struct uprobe_task *utask = current->utask;
309
310 instruction_pointer_set(regs, utask->vaddr);
311}
312
313
314
315
316
317bool arch_uprobe_xol_was_trapped(struct task_struct *t)
318{
319 return false;
320}
321
322unsigned long
323arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
324 struct pt_regs *regs)
325{
326 unsigned long orig_ret_vaddr = regs->u_regs[UREG_I7];
327
328 regs->u_regs[UREG_I7] = trampoline_vaddr-8;
329
330 return orig_ret_vaddr + 8;
331}
332