blob: c62d39d5c99f353d0050c3b4d7fbd2512f14bf5d [file] [log] [blame]
Will Deacon478fcb22012-03-05 11:49:33 +00001/*
2 * Based on arch/arm/kernel/ptrace.c
3 *
4 * By Ross Biro 1/23/92
5 * edited by Linus Torvalds
6 * ARM modifications Copyright (C) 2000 Russell King
7 * Copyright (C) 2012 ARM Ltd.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <linux/kernel.h>
23#include <linux/sched.h>
24#include <linux/mm.h>
25#include <linux/smp.h>
26#include <linux/ptrace.h>
27#include <linux/user.h>
28#include <linux/security.h>
29#include <linux/init.h>
30#include <linux/signal.h>
31#include <linux/uaccess.h>
32#include <linux/perf_event.h>
33#include <linux/hw_breakpoint.h>
34#include <linux/regset.h>
35#include <linux/tracehook.h>
36#include <linux/elf.h>
37
38#include <asm/compat.h>
39#include <asm/debug-monitors.h>
40#include <asm/pgtable.h>
41#include <asm/traps.h>
42#include <asm/system_misc.h>
43
44/*
45 * TODO: does not yet catch signals sent when the child dies.
46 * in exit.c or in signal.c.
47 */
48
49/*
50 * Called by kernel/ptrace.c when detaching..
51 */
52void ptrace_disable(struct task_struct *child)
53{
54}
55
56/*
57 * Handle hitting a breakpoint.
58 */
59static int ptrace_break(struct pt_regs *regs)
60{
61 siginfo_t info = {
62 .si_signo = SIGTRAP,
63 .si_errno = 0,
64 .si_code = TRAP_BRKPT,
65 .si_addr = (void __user *)instruction_pointer(regs),
66 };
67
68 force_sig_info(SIGTRAP, &info, current);
69 return 0;
70}
71
72static int arm64_break_trap(unsigned long addr, unsigned int esr,
73 struct pt_regs *regs)
74{
75 return ptrace_break(regs);
76}
77
78#ifdef CONFIG_HAVE_HW_BREAKPOINT
79/*
80 * Handle hitting a HW-breakpoint.
81 */
82static void ptrace_hbptriggered(struct perf_event *bp,
83 struct perf_sample_data *data,
84 struct pt_regs *regs)
85{
86 struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
87 siginfo_t info = {
88 .si_signo = SIGTRAP,
89 .si_errno = 0,
90 .si_code = TRAP_HWBKPT,
91 .si_addr = (void __user *)(bkpt->trigger),
92 };
93
94#ifdef CONFIG_COMPAT
95 int i;
96
97 if (!is_compat_task())
98 goto send_sig;
99
100 for (i = 0; i < ARM_MAX_BRP; ++i) {
101 if (current->thread.debug.hbp_break[i] == bp) {
102 info.si_errno = (i << 1) + 1;
103 break;
104 }
105 }
106 for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++i) {
107 if (current->thread.debug.hbp_watch[i] == bp) {
108 info.si_errno = -((i << 1) + 1);
109 break;
110 }
111 }
112
113send_sig:
114#endif
115 force_sig_info(SIGTRAP, &info, current);
116}
117
118/*
119 * Unregister breakpoints from this task and reset the pointers in
120 * the thread_struct.
121 */
122void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
123{
124 int i;
125 struct thread_struct *t = &tsk->thread;
126
127 for (i = 0; i < ARM_MAX_BRP; i++) {
128 if (t->debug.hbp_break[i]) {
129 unregister_hw_breakpoint(t->debug.hbp_break[i]);
130 t->debug.hbp_break[i] = NULL;
131 }
132 }
133
134 for (i = 0; i < ARM_MAX_WRP; i++) {
135 if (t->debug.hbp_watch[i]) {
136 unregister_hw_breakpoint(t->debug.hbp_watch[i]);
137 t->debug.hbp_watch[i] = NULL;
138 }
139 }
140}
141
142void ptrace_hw_copy_thread(struct task_struct *tsk)
143{
144 memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
145}
146
147static struct perf_event *ptrace_hbp_get_event(unsigned int note_type,
148 struct task_struct *tsk,
149 unsigned long idx)
150{
151 struct perf_event *bp = ERR_PTR(-EINVAL);
152
153 switch (note_type) {
154 case NT_ARM_HW_BREAK:
155 if (idx < ARM_MAX_BRP)
156 bp = tsk->thread.debug.hbp_break[idx];
157 break;
158 case NT_ARM_HW_WATCH:
159 if (idx < ARM_MAX_WRP)
160 bp = tsk->thread.debug.hbp_watch[idx];
161 break;
162 }
163
164 return bp;
165}
166
167static int ptrace_hbp_set_event(unsigned int note_type,
168 struct task_struct *tsk,
169 unsigned long idx,
170 struct perf_event *bp)
171{
172 int err = -EINVAL;
173
174 switch (note_type) {
175 case NT_ARM_HW_BREAK:
176 if (idx < ARM_MAX_BRP) {
177 tsk->thread.debug.hbp_break[idx] = bp;
178 err = 0;
179 }
180 break;
181 case NT_ARM_HW_WATCH:
182 if (idx < ARM_MAX_WRP) {
183 tsk->thread.debug.hbp_watch[idx] = bp;
184 err = 0;
185 }
186 break;
187 }
188
189 return err;
190}
191
192static struct perf_event *ptrace_hbp_create(unsigned int note_type,
193 struct task_struct *tsk,
194 unsigned long idx)
195{
196 struct perf_event *bp;
197 struct perf_event_attr attr;
198 int err, type;
199
200 switch (note_type) {
201 case NT_ARM_HW_BREAK:
202 type = HW_BREAKPOINT_X;
203 break;
204 case NT_ARM_HW_WATCH:
205 type = HW_BREAKPOINT_RW;
206 break;
207 default:
208 return ERR_PTR(-EINVAL);
209 }
210
211 ptrace_breakpoint_init(&attr);
212
213 /*
214 * Initialise fields to sane defaults
215 * (i.e. values that will pass validation).
216 */
217 attr.bp_addr = 0;
218 attr.bp_len = HW_BREAKPOINT_LEN_4;
219 attr.bp_type = type;
220 attr.disabled = 1;
221
222 bp = register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, tsk);
223 if (IS_ERR(bp))
224 return bp;
225
226 err = ptrace_hbp_set_event(note_type, tsk, idx, bp);
227 if (err)
228 return ERR_PTR(err);
229
230 return bp;
231}
232
233static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
234 struct arch_hw_breakpoint_ctrl ctrl,
235 struct perf_event_attr *attr)
236{
237 int err, len, type;
238
239 err = arch_bp_generic_fields(ctrl, &len, &type);
240 if (err)
241 return err;
242
243 switch (note_type) {
244 case NT_ARM_HW_BREAK:
245 if ((type & HW_BREAKPOINT_X) != type)
246 return -EINVAL;
247 break;
248 case NT_ARM_HW_WATCH:
249 if ((type & HW_BREAKPOINT_RW) != type)
250 return -EINVAL;
251 break;
252 default:
253 return -EINVAL;
254 }
255
256 attr->bp_len = len;
257 attr->bp_type = type;
258 attr->disabled = !ctrl.enabled;
259
260 return 0;
261}
262
263static int ptrace_hbp_get_resource_info(unsigned int note_type, u32 *info)
264{
265 u8 num;
266 u32 reg = 0;
267
268 switch (note_type) {
269 case NT_ARM_HW_BREAK:
270 num = hw_breakpoint_slots(TYPE_INST);
271 break;
272 case NT_ARM_HW_WATCH:
273 num = hw_breakpoint_slots(TYPE_DATA);
274 break;
275 default:
276 return -EINVAL;
277 }
278
279 reg |= debug_monitors_arch();
280 reg <<= 8;
281 reg |= num;
282
283 *info = reg;
284 return 0;
285}
286
287static int ptrace_hbp_get_ctrl(unsigned int note_type,
288 struct task_struct *tsk,
289 unsigned long idx,
290 u32 *ctrl)
291{
292 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
293
294 if (IS_ERR(bp))
295 return PTR_ERR(bp);
296
297 *ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0;
298 return 0;
299}
300
301static int ptrace_hbp_get_addr(unsigned int note_type,
302 struct task_struct *tsk,
303 unsigned long idx,
304 u64 *addr)
305{
306 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
307
308 if (IS_ERR(bp))
309 return PTR_ERR(bp);
310
311 *addr = bp ? bp->attr.bp_addr : 0;
312 return 0;
313}
314
315static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_type,
316 struct task_struct *tsk,
317 unsigned long idx)
318{
319 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
320
321 if (!bp)
322 bp = ptrace_hbp_create(note_type, tsk, idx);
323
324 return bp;
325}
326
327static int ptrace_hbp_set_ctrl(unsigned int note_type,
328 struct task_struct *tsk,
329 unsigned long idx,
330 u32 uctrl)
331{
332 int err;
333 struct perf_event *bp;
334 struct perf_event_attr attr;
335 struct arch_hw_breakpoint_ctrl ctrl;
336
337 bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
338 if (IS_ERR(bp)) {
339 err = PTR_ERR(bp);
340 return err;
341 }
342
343 attr = bp->attr;
344 decode_ctrl_reg(uctrl, &ctrl);
345 err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
346 if (err)
347 return err;
348
349 return modify_user_hw_breakpoint(bp, &attr);
350}
351
352static int ptrace_hbp_set_addr(unsigned int note_type,
353 struct task_struct *tsk,
354 unsigned long idx,
355 u64 addr)
356{
357 int err;
358 struct perf_event *bp;
359 struct perf_event_attr attr;
360
361 bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
362 if (IS_ERR(bp)) {
363 err = PTR_ERR(bp);
364 return err;
365 }
366
367 attr = bp->attr;
368 attr.bp_addr = addr;
369 err = modify_user_hw_breakpoint(bp, &attr);
370 return err;
371}
372
373#define PTRACE_HBP_ADDR_SZ sizeof(u64)
374#define PTRACE_HBP_CTRL_SZ sizeof(u32)
Will Deacon7797d172012-10-11 12:10:57 +0100375#define PTRACE_HBP_PAD_SZ sizeof(u32)
Will Deacon478fcb22012-03-05 11:49:33 +0000376
377static int hw_break_get(struct task_struct *target,
378 const struct user_regset *regset,
379 unsigned int pos, unsigned int count,
380 void *kbuf, void __user *ubuf)
381{
382 unsigned int note_type = regset->core_note_type;
Will Deacon7797d172012-10-11 12:10:57 +0100383 int ret, idx = 0, offset, limit;
Will Deacon478fcb22012-03-05 11:49:33 +0000384 u32 info, ctrl;
385 u64 addr;
386
387 /* Resource info */
388 ret = ptrace_hbp_get_resource_info(note_type, &info);
389 if (ret)
390 return ret;
391
Will Deacon7797d172012-10-11 12:10:57 +0100392 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0,
393 sizeof(info));
394 if (ret)
395 return ret;
396
397 /* Pad */
398 offset = offsetof(struct user_hwdebug_state, pad);
399 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset,
400 offset + PTRACE_HBP_PAD_SZ);
Will Deacon478fcb22012-03-05 11:49:33 +0000401 if (ret)
402 return ret;
403
404 /* (address, ctrl) registers */
Will Deacon7797d172012-10-11 12:10:57 +0100405 offset = offsetof(struct user_hwdebug_state, dbg_regs);
Will Deacon478fcb22012-03-05 11:49:33 +0000406 limit = regset->n * regset->size;
407 while (count && offset < limit) {
408 ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
409 if (ret)
410 return ret;
411 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr,
412 offset, offset + PTRACE_HBP_ADDR_SZ);
413 if (ret)
414 return ret;
415 offset += PTRACE_HBP_ADDR_SZ;
416
417 ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
418 if (ret)
419 return ret;
420 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl,
421 offset, offset + PTRACE_HBP_CTRL_SZ);
422 if (ret)
423 return ret;
424 offset += PTRACE_HBP_CTRL_SZ;
Will Deacon7797d172012-10-11 12:10:57 +0100425
426 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
427 offset,
428 offset + PTRACE_HBP_PAD_SZ);
429 if (ret)
430 return ret;
431 offset += PTRACE_HBP_PAD_SZ;
Will Deacon478fcb22012-03-05 11:49:33 +0000432 idx++;
433 }
434
435 return 0;
436}
437
438static int hw_break_set(struct task_struct *target,
439 const struct user_regset *regset,
440 unsigned int pos, unsigned int count,
441 const void *kbuf, const void __user *ubuf)
442{
443 unsigned int note_type = regset->core_note_type;
Will Deacon7797d172012-10-11 12:10:57 +0100444 int ret, idx = 0, offset, limit;
Will Deacon478fcb22012-03-05 11:49:33 +0000445 u32 ctrl;
446 u64 addr;
447
Will Deacon7797d172012-10-11 12:10:57 +0100448 /* Resource info and pad */
449 offset = offsetof(struct user_hwdebug_state, dbg_regs);
450 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset);
Will Deacon478fcb22012-03-05 11:49:33 +0000451 if (ret)
452 return ret;
453
454 /* (address, ctrl) registers */
455 limit = regset->n * regset->size;
456 while (count && offset < limit) {
457 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
458 offset, offset + PTRACE_HBP_ADDR_SZ);
459 if (ret)
460 return ret;
461 ret = ptrace_hbp_set_addr(note_type, target, idx, addr);
462 if (ret)
463 return ret;
464 offset += PTRACE_HBP_ADDR_SZ;
465
466 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
467 offset, offset + PTRACE_HBP_CTRL_SZ);
468 if (ret)
469 return ret;
470 ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl);
471 if (ret)
472 return ret;
473 offset += PTRACE_HBP_CTRL_SZ;
Will Deacon7797d172012-10-11 12:10:57 +0100474
475 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
476 offset,
477 offset + PTRACE_HBP_PAD_SZ);
478 if (ret)
479 return ret;
480 offset += PTRACE_HBP_PAD_SZ;
Will Deacon478fcb22012-03-05 11:49:33 +0000481 idx++;
482 }
483
484 return 0;
485}
486#endif /* CONFIG_HAVE_HW_BREAKPOINT */
487
488static int gpr_get(struct task_struct *target,
489 const struct user_regset *regset,
490 unsigned int pos, unsigned int count,
491 void *kbuf, void __user *ubuf)
492{
493 struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
494 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
495}
496
497static int gpr_set(struct task_struct *target, const struct user_regset *regset,
498 unsigned int pos, unsigned int count,
499 const void *kbuf, const void __user *ubuf)
500{
501 int ret;
502 struct user_pt_regs newregs;
503
504 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
505 if (ret)
506 return ret;
507
508 if (!valid_user_regs(&newregs))
509 return -EINVAL;
510
511 task_pt_regs(target)->user_regs = newregs;
512 return 0;
513}
514
515/*
516 * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
517 */
518static int fpr_get(struct task_struct *target, const struct user_regset *regset,
519 unsigned int pos, unsigned int count,
520 void *kbuf, void __user *ubuf)
521{
522 struct user_fpsimd_state *uregs;
523 uregs = &target->thread.fpsimd_state.user_fpsimd;
524 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
525}
526
527static int fpr_set(struct task_struct *target, const struct user_regset *regset,
528 unsigned int pos, unsigned int count,
529 const void *kbuf, const void __user *ubuf)
530{
531 int ret;
532 struct user_fpsimd_state newstate;
533
534 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
535 if (ret)
536 return ret;
537
538 target->thread.fpsimd_state.user_fpsimd = newstate;
539 return ret;
540}
541
542static int tls_get(struct task_struct *target, const struct user_regset *regset,
543 unsigned int pos, unsigned int count,
544 void *kbuf, void __user *ubuf)
545{
546 unsigned long *tls = &target->thread.tp_value;
547 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1);
548}
549
550static int tls_set(struct task_struct *target, const struct user_regset *regset,
551 unsigned int pos, unsigned int count,
552 const void *kbuf, const void __user *ubuf)
553{
554 int ret;
555 unsigned long tls;
556
557 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
558 if (ret)
559 return ret;
560
561 target->thread.tp_value = tls;
562 return ret;
563}
564
565enum aarch64_regset {
566 REGSET_GPR,
567 REGSET_FPR,
568 REGSET_TLS,
569#ifdef CONFIG_HAVE_HW_BREAKPOINT
570 REGSET_HW_BREAK,
571 REGSET_HW_WATCH,
572#endif
573};
574
575static const struct user_regset aarch64_regsets[] = {
576 [REGSET_GPR] = {
577 .core_note_type = NT_PRSTATUS,
578 .n = sizeof(struct user_pt_regs) / sizeof(u64),
579 .size = sizeof(u64),
580 .align = sizeof(u64),
581 .get = gpr_get,
582 .set = gpr_set
583 },
584 [REGSET_FPR] = {
585 .core_note_type = NT_PRFPREG,
586 .n = sizeof(struct user_fpsimd_state) / sizeof(u32),
587 /*
588 * We pretend we have 32-bit registers because the fpsr and
589 * fpcr are 32-bits wide.
590 */
591 .size = sizeof(u32),
592 .align = sizeof(u32),
593 .get = fpr_get,
594 .set = fpr_set
595 },
596 [REGSET_TLS] = {
597 .core_note_type = NT_ARM_TLS,
598 .n = 1,
599 .size = sizeof(void *),
600 .align = sizeof(void *),
601 .get = tls_get,
602 .set = tls_set,
603 },
604#ifdef CONFIG_HAVE_HW_BREAKPOINT
605 [REGSET_HW_BREAK] = {
606 .core_note_type = NT_ARM_HW_BREAK,
607 .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
608 .size = sizeof(u32),
609 .align = sizeof(u32),
610 .get = hw_break_get,
611 .set = hw_break_set,
612 },
613 [REGSET_HW_WATCH] = {
614 .core_note_type = NT_ARM_HW_WATCH,
615 .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
616 .size = sizeof(u32),
617 .align = sizeof(u32),
618 .get = hw_break_get,
619 .set = hw_break_set,
620 },
621#endif
622};
623
624static const struct user_regset_view user_aarch64_view = {
625 .name = "aarch64", .e_machine = EM_AARCH64,
626 .regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets)
627};
628
629#ifdef CONFIG_COMPAT
630#include <linux/compat.h>
631
632enum compat_regset {
633 REGSET_COMPAT_GPR,
634 REGSET_COMPAT_VFP,
635};
636
637static int compat_gpr_get(struct task_struct *target,
638 const struct user_regset *regset,
639 unsigned int pos, unsigned int count,
640 void *kbuf, void __user *ubuf)
641{
642 int ret = 0;
643 unsigned int i, start, num_regs;
644
645 /* Calculate the number of AArch32 registers contained in count */
646 num_regs = count / regset->size;
647
648 /* Convert pos into an register number */
649 start = pos / regset->size;
650
651 if (start + num_regs > regset->n)
652 return -EIO;
653
654 for (i = 0; i < num_regs; ++i) {
655 unsigned int idx = start + i;
656 void *reg;
657
658 switch (idx) {
659 case 15:
660 reg = (void *)&task_pt_regs(target)->pc;
661 break;
662 case 16:
663 reg = (void *)&task_pt_regs(target)->pstate;
664 break;
665 case 17:
666 reg = (void *)&task_pt_regs(target)->orig_x0;
667 break;
668 default:
669 reg = (void *)&task_pt_regs(target)->regs[idx];
670 }
671
672 ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t));
673
674 if (ret)
675 break;
676 else
677 ubuf += sizeof(compat_ulong_t);
678 }
679
680 return ret;
681}
682
683static int compat_gpr_set(struct task_struct *target,
684 const struct user_regset *regset,
685 unsigned int pos, unsigned int count,
686 const void *kbuf, const void __user *ubuf)
687{
688 struct pt_regs newregs;
689 int ret = 0;
690 unsigned int i, start, num_regs;
691
692 /* Calculate the number of AArch32 registers contained in count */
693 num_regs = count / regset->size;
694
695 /* Convert pos into an register number */
696 start = pos / regset->size;
697
698 if (start + num_regs > regset->n)
699 return -EIO;
700
701 newregs = *task_pt_regs(target);
702
703 for (i = 0; i < num_regs; ++i) {
704 unsigned int idx = start + i;
705 void *reg;
706
707 switch (idx) {
708 case 15:
709 reg = (void *)&newregs.pc;
710 break;
711 case 16:
712 reg = (void *)&newregs.pstate;
713 break;
714 case 17:
715 reg = (void *)&newregs.orig_x0;
716 break;
717 default:
718 reg = (void *)&newregs.regs[idx];
719 }
720
721 ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t));
722
723 if (ret)
724 goto out;
725 else
726 ubuf += sizeof(compat_ulong_t);
727 }
728
729 if (valid_user_regs(&newregs.user_regs))
730 *task_pt_regs(target) = newregs;
731 else
732 ret = -EINVAL;
733
734out:
735 return ret;
736}
737
738static int compat_vfp_get(struct task_struct *target,
739 const struct user_regset *regset,
740 unsigned int pos, unsigned int count,
741 void *kbuf, void __user *ubuf)
742{
743 struct user_fpsimd_state *uregs;
744 compat_ulong_t fpscr;
745 int ret;
746
747 uregs = &target->thread.fpsimd_state.user_fpsimd;
748
749 /*
750 * The VFP registers are packed into the fpsimd_state, so they all sit
751 * nicely together for us. We just need to create the fpscr separately.
752 */
753 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
754 VFP_STATE_SIZE - sizeof(compat_ulong_t));
755
756 if (count && !ret) {
757 fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
758 (uregs->fpcr & VFP_FPSCR_CTRL_MASK);
759 ret = put_user(fpscr, (compat_ulong_t *)ubuf);
760 }
761
762 return ret;
763}
764
765static int compat_vfp_set(struct task_struct *target,
766 const struct user_regset *regset,
767 unsigned int pos, unsigned int count,
768 const void *kbuf, const void __user *ubuf)
769{
770 struct user_fpsimd_state *uregs;
771 compat_ulong_t fpscr;
772 int ret;
773
774 if (pos + count > VFP_STATE_SIZE)
775 return -EIO;
776
777 uregs = &target->thread.fpsimd_state.user_fpsimd;
778
779 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
780 VFP_STATE_SIZE - sizeof(compat_ulong_t));
781
782 if (count && !ret) {
783 ret = get_user(fpscr, (compat_ulong_t *)ubuf);
784 uregs->fpsr = fpscr & VFP_FPSCR_STAT_MASK;
785 uregs->fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
786 }
787
788 return ret;
789}
790
791static const struct user_regset aarch32_regsets[] = {
792 [REGSET_COMPAT_GPR] = {
793 .core_note_type = NT_PRSTATUS,
794 .n = COMPAT_ELF_NGREG,
795 .size = sizeof(compat_elf_greg_t),
796 .align = sizeof(compat_elf_greg_t),
797 .get = compat_gpr_get,
798 .set = compat_gpr_set
799 },
800 [REGSET_COMPAT_VFP] = {
801 .core_note_type = NT_ARM_VFP,
802 .n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
803 .size = sizeof(compat_ulong_t),
804 .align = sizeof(compat_ulong_t),
805 .get = compat_vfp_get,
806 .set = compat_vfp_set
807 },
808};
809
810static const struct user_regset_view user_aarch32_view = {
811 .name = "aarch32", .e_machine = EM_ARM,
812 .regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
813};
814
815int aarch32_break_trap(struct pt_regs *regs)
816{
817 unsigned int instr;
818 bool bp = false;
819 void __user *pc = (void __user *)instruction_pointer(regs);
820
821 if (compat_thumb_mode(regs)) {
822 /* get 16-bit Thumb instruction */
823 get_user(instr, (u16 __user *)pc);
824 if (instr == AARCH32_BREAK_THUMB2_LO) {
825 /* get second half of 32-bit Thumb-2 instruction */
826 get_user(instr, (u16 __user *)(pc + 2));
827 bp = instr == AARCH32_BREAK_THUMB2_HI;
828 } else {
829 bp = instr == AARCH32_BREAK_THUMB;
830 }
831 } else {
832 /* 32-bit ARM instruction */
833 get_user(instr, (u32 __user *)pc);
834 bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
835 }
836
837 if (bp)
838 return ptrace_break(regs);
839 return 1;
840}
841
842static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
843 compat_ulong_t __user *ret)
844{
845 compat_ulong_t tmp;
846
847 if (off & 3)
848 return -EIO;
849
Catalin Marinas7606c372012-10-10 15:50:03 +0100850 if (off == COMPAT_PT_TEXT_ADDR)
Will Deacon478fcb22012-03-05 11:49:33 +0000851 tmp = tsk->mm->start_code;
Catalin Marinas7606c372012-10-10 15:50:03 +0100852 else if (off == COMPAT_PT_DATA_ADDR)
Will Deacon478fcb22012-03-05 11:49:33 +0000853 tmp = tsk->mm->start_data;
Catalin Marinas7606c372012-10-10 15:50:03 +0100854 else if (off == COMPAT_PT_TEXT_END_ADDR)
Will Deacon478fcb22012-03-05 11:49:33 +0000855 tmp = tsk->mm->end_code;
856 else if (off < sizeof(compat_elf_gregset_t))
857 return copy_regset_to_user(tsk, &user_aarch32_view,
858 REGSET_COMPAT_GPR, off,
859 sizeof(compat_ulong_t), ret);
860 else if (off >= COMPAT_USER_SZ)
861 return -EIO;
862 else
863 tmp = 0;
864
865 return put_user(tmp, ret);
866}
867
868static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
869 compat_ulong_t val)
870{
871 int ret;
872
873 if (off & 3 || off >= COMPAT_USER_SZ)
874 return -EIO;
875
876 if (off >= sizeof(compat_elf_gregset_t))
877 return 0;
878
879 ret = copy_regset_from_user(tsk, &user_aarch32_view,
880 REGSET_COMPAT_GPR, off,
881 sizeof(compat_ulong_t),
882 &val);
883 return ret;
884}
885
886#ifdef CONFIG_HAVE_HW_BREAKPOINT
887
888/*
889 * Convert a virtual register number into an index for a thread_info
890 * breakpoint array. Breakpoints are identified using positive numbers
891 * whilst watchpoints are negative. The registers are laid out as pairs
892 * of (address, control), each pair mapping to a unique hw_breakpoint struct.
893 * Register 0 is reserved for describing resource information.
894 */
895static int compat_ptrace_hbp_num_to_idx(compat_long_t num)
896{
897 return (abs(num) - 1) >> 1;
898}
899
900static int compat_ptrace_hbp_get_resource_info(u32 *kdata)
901{
902 u8 num_brps, num_wrps, debug_arch, wp_len;
903 u32 reg = 0;
904
905 num_brps = hw_breakpoint_slots(TYPE_INST);
906 num_wrps = hw_breakpoint_slots(TYPE_DATA);
907
908 debug_arch = debug_monitors_arch();
909 wp_len = 8;
910 reg |= debug_arch;
911 reg <<= 8;
912 reg |= wp_len;
913 reg <<= 8;
914 reg |= num_wrps;
915 reg <<= 8;
916 reg |= num_brps;
917
918 *kdata = reg;
919 return 0;
920}
921
922static int compat_ptrace_hbp_get(unsigned int note_type,
923 struct task_struct *tsk,
924 compat_long_t num,
925 u32 *kdata)
926{
927 u64 addr = 0;
928 u32 ctrl = 0;
929
930 int err, idx = compat_ptrace_hbp_num_to_idx(num);;
931
932 if (num & 1) {
933 err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr);
934 *kdata = (u32)addr;
935 } else {
936 err = ptrace_hbp_get_ctrl(note_type, tsk, idx, &ctrl);
937 *kdata = ctrl;
938 }
939
940 return err;
941}
942
943static int compat_ptrace_hbp_set(unsigned int note_type,
944 struct task_struct *tsk,
945 compat_long_t num,
946 u32 *kdata)
947{
948 u64 addr;
949 u32 ctrl;
950
951 int err, idx = compat_ptrace_hbp_num_to_idx(num);
952
953 if (num & 1) {
954 addr = *kdata;
955 err = ptrace_hbp_set_addr(note_type, tsk, idx, addr);
956 } else {
957 ctrl = *kdata;
958 err = ptrace_hbp_set_ctrl(note_type, tsk, idx, ctrl);
959 }
960
961 return err;
962}
963
964static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num,
965 compat_ulong_t __user *data)
966{
967 int ret;
968 u32 kdata;
969 mm_segment_t old_fs = get_fs();
970
971 set_fs(KERNEL_DS);
972 /* Watchpoint */
973 if (num < 0) {
974 ret = compat_ptrace_hbp_get(NT_ARM_HW_WATCH, tsk, num, &kdata);
975 /* Resource info */
976 } else if (num == 0) {
977 ret = compat_ptrace_hbp_get_resource_info(&kdata);
978 /* Breakpoint */
979 } else {
980 ret = compat_ptrace_hbp_get(NT_ARM_HW_BREAK, tsk, num, &kdata);
981 }
982 set_fs(old_fs);
983
984 if (!ret)
985 ret = put_user(kdata, data);
986
987 return ret;
988}
989
990static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num,
991 compat_ulong_t __user *data)
992{
993 int ret;
994 u32 kdata = 0;
995 mm_segment_t old_fs = get_fs();
996
997 if (num == 0)
998 return 0;
999
1000 ret = get_user(kdata, data);
1001 if (ret)
1002 return ret;
1003
1004 set_fs(KERNEL_DS);
1005 if (num < 0)
1006 ret = compat_ptrace_hbp_set(NT_ARM_HW_WATCH, tsk, num, &kdata);
1007 else
1008 ret = compat_ptrace_hbp_set(NT_ARM_HW_BREAK, tsk, num, &kdata);
1009 set_fs(old_fs);
1010
1011 return ret;
1012}
1013#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1014
1015long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
1016 compat_ulong_t caddr, compat_ulong_t cdata)
1017{
1018 unsigned long addr = caddr;
1019 unsigned long data = cdata;
1020 void __user *datap = compat_ptr(data);
1021 int ret;
1022
1023 switch (request) {
1024 case PTRACE_PEEKUSR:
1025 ret = compat_ptrace_read_user(child, addr, datap);
1026 break;
1027
1028 case PTRACE_POKEUSR:
1029 ret = compat_ptrace_write_user(child, addr, data);
1030 break;
1031
Will Deacon27aa55c2012-09-27 11:38:12 +01001032 case COMPAT_PTRACE_GETREGS:
Will Deacon478fcb22012-03-05 11:49:33 +00001033 ret = copy_regset_to_user(child,
1034 &user_aarch32_view,
1035 REGSET_COMPAT_GPR,
1036 0, sizeof(compat_elf_gregset_t),
1037 datap);
1038 break;
1039
Will Deacon27aa55c2012-09-27 11:38:12 +01001040 case COMPAT_PTRACE_SETREGS:
Will Deacon478fcb22012-03-05 11:49:33 +00001041 ret = copy_regset_from_user(child,
1042 &user_aarch32_view,
1043 REGSET_COMPAT_GPR,
1044 0, sizeof(compat_elf_gregset_t),
1045 datap);
1046 break;
1047
Will Deacon27aa55c2012-09-27 11:38:12 +01001048 case COMPAT_PTRACE_GET_THREAD_AREA:
Will Deacon478fcb22012-03-05 11:49:33 +00001049 ret = put_user((compat_ulong_t)child->thread.tp_value,
1050 (compat_ulong_t __user *)datap);
1051 break;
1052
Will Deacon27aa55c2012-09-27 11:38:12 +01001053 case COMPAT_PTRACE_SET_SYSCALL:
Will Deacon478fcb22012-03-05 11:49:33 +00001054 task_pt_regs(child)->syscallno = data;
1055 ret = 0;
1056 break;
1057
1058 case COMPAT_PTRACE_GETVFPREGS:
1059 ret = copy_regset_to_user(child,
1060 &user_aarch32_view,
1061 REGSET_COMPAT_VFP,
1062 0, VFP_STATE_SIZE,
1063 datap);
1064 break;
1065
1066 case COMPAT_PTRACE_SETVFPREGS:
1067 ret = copy_regset_from_user(child,
1068 &user_aarch32_view,
1069 REGSET_COMPAT_VFP,
1070 0, VFP_STATE_SIZE,
1071 datap);
1072 break;
1073
1074#ifdef CONFIG_HAVE_HW_BREAKPOINT
Will Deacon27aa55c2012-09-27 11:38:12 +01001075 case COMPAT_PTRACE_GETHBPREGS:
Will Deacon478fcb22012-03-05 11:49:33 +00001076 ret = compat_ptrace_gethbpregs(child, addr, datap);
1077 break;
1078
Will Deacon27aa55c2012-09-27 11:38:12 +01001079 case COMPAT_PTRACE_SETHBPREGS:
Will Deacon478fcb22012-03-05 11:49:33 +00001080 ret = compat_ptrace_sethbpregs(child, addr, datap);
1081 break;
1082#endif
1083
1084 default:
1085 ret = compat_ptrace_request(child, request, addr,
1086 data);
1087 break;
1088 }
1089
1090 return ret;
1091}
1092#endif /* CONFIG_COMPAT */
1093
1094const struct user_regset_view *task_user_regset_view(struct task_struct *task)
1095{
1096#ifdef CONFIG_COMPAT
1097 if (is_compat_thread(task_thread_info(task)))
1098 return &user_aarch32_view;
1099#endif
1100 return &user_aarch64_view;
1101}
1102
1103long arch_ptrace(struct task_struct *child, long request,
1104 unsigned long addr, unsigned long data)
1105{
1106 return ptrace_request(child, request, addr, data);
1107}
1108
1109
1110static int __init ptrace_break_init(void)
1111{
1112 hook_debug_fault_code(DBG_ESR_EVT_BRK, arm64_break_trap, SIGTRAP,
1113 TRAP_BRKPT, "ptrace BRK handler");
1114 return 0;
1115}
1116core_initcall(ptrace_break_init);
1117
1118
1119asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
1120{
1121 unsigned long saved_reg;
1122
1123 if (!test_thread_flag(TIF_SYSCALL_TRACE))
1124 return regs->syscallno;
1125
1126 if (is_compat_task()) {
1127 /* AArch32 uses ip (r12) for scratch */
1128 saved_reg = regs->regs[12];
1129 regs->regs[12] = dir;
1130 } else {
1131 /*
1132 * Save X7. X7 is used to denote syscall entry/exit:
1133 * X7 = 0 -> entry, = 1 -> exit
1134 */
1135 saved_reg = regs->regs[7];
1136 regs->regs[7] = dir;
1137 }
1138
1139 if (dir)
1140 tracehook_report_syscall_exit(regs, 0);
1141 else if (tracehook_report_syscall_entry(regs))
1142 regs->syscallno = ~0UL;
1143
1144 if (is_compat_task())
1145 regs->regs[12] = saved_reg;
1146 else
1147 regs->regs[7] = saved_reg;
1148
1149 return regs->syscallno;
1150}