aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/ptrace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-07 18:32:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-07 18:32:58 -0500
commit3ae423fe4734af3b2f7ac718c6e64e72bfe443b3 (patch)
treee323d3bd2ce253f739a1faa4b4486e6c603a36b8 /arch/mips/kernel/ptrace.c
parent280c84d1c1726be7ada045735858acdc8cfdd65a (diff)
parent723ff7943249efcea8fd814ec1eff728f38f5935 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: - Some minor work bringing the Cobalt MIPS platforms in line with other MIPS platforms - Make vmlinux.32 and vmlinux.64 build messages less verbose - Always register the R4k clocksource when selected, the clock source's rating will decide if this or another clock source is actually going to be used - Drop support for the Cisco (formerly Scientific Atlanta) PowerTV platform. There appears to be nobody left who cares and the USB driver went stale while waiting for years to be merged - Some cleanup of Loongson 2 related #ifdefery - Various minor cleanups - Major rework on all things related to tracing / ptrace on MIPS, including switching the MIPS ELF core dumper to regsets, enabling the entries for SIGSYS in struct siginfo for MIPS, enabling ftrace syscall trace points - Some more work to bring DECstation support code in line with other more modern code - Report the name of the detected CPU, not just its CP0 PrID value - Some more BCM 47xx and atheros ath79xx work - Support for compressed kernels using the XZ compression scheme * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (53 commits) MIPS: remove duplicate define MIPS: Random whitespace clean-ups MIPS: traps: Reformat notify_die invocations to 80 columns. MIPS: Print correct PC in trace dump after NMI exception MIPS: kernel: cpu-probe: Report CPU id during probe MIPS: Remove unused defines in piix4.h MIPS: Get rid of hard-coded values for Malta PIIX4 fixups MIPS: Always register R4K clock when selected MIPS: Loongson: Get rid of Loongson 2 #ifdefery all over arch/mips. MIPS: cacheops.h: Increase indentation by one tab. MIPS: Remove bogus BUG_ON() MIPS: PowerTV: Remove support code. MIPS: ftrace: Add support for syscall tracepoints. MIPS: ptrace: Switch syscall reporting to tracehook_report_syscall_entry(). MIPS: Move audit_arch() helper function to __syscall_get_arch(). MIPS: Enable HAVE_ARCH_TRACEHOOK. MIPS: Switch ELF core dumper to use regsets. MIPS: Implement task_user_regset_view. MIPS: ptrace: Use tracehook helpers. MIPS: O32 / 32-bit: Always copy 4 stack arguments. ...
Diffstat (limited to 'arch/mips/kernel/ptrace.c')
-rw-r--r--arch/mips/kernel/ptrace.c199
1 files changed, 147 insertions, 52 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 8ae1ebef8b71..b52e1d2b33e0 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -16,16 +16,20 @@
16 */ 16 */
17#include <linux/compiler.h> 17#include <linux/compiler.h>
18#include <linux/context_tracking.h> 18#include <linux/context_tracking.h>
19#include <linux/elf.h>
19#include <linux/kernel.h> 20#include <linux/kernel.h>
20#include <linux/sched.h> 21#include <linux/sched.h>
21#include <linux/mm.h> 22#include <linux/mm.h>
22#include <linux/errno.h> 23#include <linux/errno.h>
23#include <linux/ptrace.h> 24#include <linux/ptrace.h>
25#include <linux/regset.h>
24#include <linux/smp.h> 26#include <linux/smp.h>
25#include <linux/user.h> 27#include <linux/user.h>
26#include <linux/security.h> 28#include <linux/security.h>
29#include <linux/tracehook.h>
27#include <linux/audit.h> 30#include <linux/audit.h>
28#include <linux/seccomp.h> 31#include <linux/seccomp.h>
32#include <linux/ftrace.h>
29 33
30#include <asm/byteorder.h> 34#include <asm/byteorder.h>
31#include <asm/cpu.h> 35#include <asm/cpu.h>
@@ -35,10 +39,14 @@
35#include <asm/mipsmtregs.h> 39#include <asm/mipsmtregs.h>
36#include <asm/pgtable.h> 40#include <asm/pgtable.h>
37#include <asm/page.h> 41#include <asm/page.h>
42#include <asm/syscall.h>
38#include <asm/uaccess.h> 43#include <asm/uaccess.h>
39#include <asm/bootinfo.h> 44#include <asm/bootinfo.h>
40#include <asm/reg.h> 45#include <asm/reg.h>
41 46
47#define CREATE_TRACE_POINTS
48#include <trace/events/syscalls.h>
49
42/* 50/*
43 * Called by kernel/ptrace.c when detaching.. 51 * Called by kernel/ptrace.c when detaching..
44 * 52 *
@@ -255,6 +263,133 @@ int ptrace_set_watch_regs(struct task_struct *child,
255 return 0; 263 return 0;
256} 264}
257 265
266/* regset get/set implementations */
267
268static int gpr_get(struct task_struct *target,
269 const struct user_regset *regset,
270 unsigned int pos, unsigned int count,
271 void *kbuf, void __user *ubuf)
272{
273 struct pt_regs *regs = task_pt_regs(target);
274
275 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
276 regs, 0, sizeof(*regs));
277}
278
279static int gpr_set(struct task_struct *target,
280 const struct user_regset *regset,
281 unsigned int pos, unsigned int count,
282 const void *kbuf, const void __user *ubuf)
283{
284 struct pt_regs newregs;
285 int ret;
286
287 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
288 &newregs,
289 0, sizeof(newregs));
290 if (ret)
291 return ret;
292
293 *task_pt_regs(target) = newregs;
294
295 return 0;
296}
297
298static int fpr_get(struct task_struct *target,
299 const struct user_regset *regset,
300 unsigned int pos, unsigned int count,
301 void *kbuf, void __user *ubuf)
302{
303 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
304 &target->thread.fpu,
305 0, sizeof(elf_fpregset_t));
306 /* XXX fcr31 */
307}
308
309static int fpr_set(struct task_struct *target,
310 const struct user_regset *regset,
311 unsigned int pos, unsigned int count,
312 const void *kbuf, const void __user *ubuf)
313{
314 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
315 &target->thread.fpu,
316 0, sizeof(elf_fpregset_t));
317 /* XXX fcr31 */
318}
319
320enum mips_regset {
321 REGSET_GPR,
322 REGSET_FPR,
323};
324
325static const struct user_regset mips_regsets[] = {
326 [REGSET_GPR] = {
327 .core_note_type = NT_PRSTATUS,
328 .n = ELF_NGREG,
329 .size = sizeof(unsigned int),
330 .align = sizeof(unsigned int),
331 .get = gpr_get,
332 .set = gpr_set,
333 },
334 [REGSET_FPR] = {
335 .core_note_type = NT_PRFPREG,
336 .n = ELF_NFPREG,
337 .size = sizeof(elf_fpreg_t),
338 .align = sizeof(elf_fpreg_t),
339 .get = fpr_get,
340 .set = fpr_set,
341 },
342};
343
344static const struct user_regset_view user_mips_view = {
345 .name = "mips",
346 .e_machine = ELF_ARCH,
347 .ei_osabi = ELF_OSABI,
348 .regsets = mips_regsets,
349 .n = ARRAY_SIZE(mips_regsets),
350};
351
352static const struct user_regset mips64_regsets[] = {
353 [REGSET_GPR] = {
354 .core_note_type = NT_PRSTATUS,
355 .n = ELF_NGREG,
356 .size = sizeof(unsigned long),
357 .align = sizeof(unsigned long),
358 .get = gpr_get,
359 .set = gpr_set,
360 },
361 [REGSET_FPR] = {
362 .core_note_type = NT_PRFPREG,
363 .n = ELF_NFPREG,
364 .size = sizeof(elf_fpreg_t),
365 .align = sizeof(elf_fpreg_t),
366 .get = fpr_get,
367 .set = fpr_set,
368 },
369};
370
371static const struct user_regset_view user_mips64_view = {
372 .name = "mips",
373 .e_machine = ELF_ARCH,
374 .ei_osabi = ELF_OSABI,
375 .regsets = mips64_regsets,
376 .n = ARRAY_SIZE(mips_regsets),
377};
378
379const struct user_regset_view *task_user_regset_view(struct task_struct *task)
380{
381#ifdef CONFIG_32BIT
382 return &user_mips_view;
383#endif
384
385#ifdef CONFIG_MIPS32_O32
386 if (test_thread_flag(TIF_32BIT_REGS))
387 return &user_mips_view;
388#endif
389
390 return &user_mips64_view;
391}
392
258long arch_ptrace(struct task_struct *child, long request, 393long arch_ptrace(struct task_struct *child, long request,
259 unsigned long addr, unsigned long data) 394 unsigned long addr, unsigned long data)
260{ 395{
@@ -517,52 +652,27 @@ long arch_ptrace(struct task_struct *child, long request,
517 return ret; 652 return ret;
518} 653}
519 654
520static inline int audit_arch(void)
521{
522 int arch = EM_MIPS;
523#ifdef CONFIG_64BIT
524 arch |= __AUDIT_ARCH_64BIT;
525#endif
526#if defined(__LITTLE_ENDIAN)
527 arch |= __AUDIT_ARCH_LE;
528#endif
529 return arch;
530}
531
532/* 655/*
533 * Notification of system call entry/exit 656 * Notification of system call entry/exit
534 * - triggered by current->work.syscall_trace 657 * - triggered by current->work.syscall_trace
535 */ 658 */
536asmlinkage void syscall_trace_enter(struct pt_regs *regs) 659asmlinkage void syscall_trace_enter(struct pt_regs *regs)
537{ 660{
661 long ret = 0;
538 user_exit(); 662 user_exit();
539 663
540 /* do the secure computing check first */ 664 /* do the secure computing check first */
541 secure_computing_strict(regs->regs[2]); 665 secure_computing_strict(regs->regs[2]);
542 666
543 if (!(current->ptrace & PT_PTRACED)) 667 if (test_thread_flag(TIF_SYSCALL_TRACE) &&
544 goto out; 668 tracehook_report_syscall_entry(regs))
545 669 ret = -1;
546 if (!test_thread_flag(TIF_SYSCALL_TRACE))
547 goto out;
548 670
549 /* The 0x80 provides a way for the tracing parent to distinguish 671 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
550 between a syscall stop and SIGTRAP delivery */ 672 trace_sys_enter(regs, regs->regs[2]);
551 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
552 0x80 : 0));
553
554 /*
555 * this isn't the same as continuing with a signal, but it will do
556 * for normal use. strace only continues with a signal if the
557 * stopping signal is not SIGTRAP. -brl
558 */
559 if (current->exit_code) {
560 send_sig(current->exit_code, current, 1);
561 current->exit_code = 0;
562 }
563 673
564out: 674 audit_syscall_entry(__syscall_get_arch(),
565 audit_syscall_entry(audit_arch(), regs->regs[2], 675 regs->regs[2],
566 regs->regs[4], regs->regs[5], 676 regs->regs[4], regs->regs[5],
567 regs->regs[6], regs->regs[7]); 677 regs->regs[6], regs->regs[7]);
568} 678}
@@ -582,26 +692,11 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
582 692
583 audit_syscall_exit(regs); 693 audit_syscall_exit(regs);
584 694
585 if (!(current->ptrace & PT_PTRACED)) 695 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
586 return; 696 trace_sys_exit(regs, regs->regs[2]);
587
588 if (!test_thread_flag(TIF_SYSCALL_TRACE))
589 return;
590
591 /* The 0x80 provides a way for the tracing parent to distinguish
592 between a syscall stop and SIGTRAP delivery */
593 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
594 0x80 : 0));
595 697
596 /* 698 if (test_thread_flag(TIF_SYSCALL_TRACE))
597 * this isn't the same as continuing with a signal, but it will do 699 tracehook_report_syscall_exit(regs, 0);
598 * for normal use. strace only continues with a signal if the
599 * stopping signal is not SIGTRAP. -brl
600 */
601 if (current->exit_code) {
602 send_sig(current->exit_code, current, 1);
603 current->exit_code = 0;
604 }
605 700
606 user_enter(); 701 user_enter();
607} 702}