diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 18:32:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 18:32:58 -0500 |
commit | 3ae423fe4734af3b2f7ac718c6e64e72bfe443b3 (patch) | |
tree | e323d3bd2ce253f739a1faa4b4486e6c603a36b8 /arch/mips/kernel/ptrace.c | |
parent | 280c84d1c1726be7ada045735858acdc8cfdd65a (diff) | |
parent | 723ff7943249efcea8fd814ec1eff728f38f5935 (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.c | 199 |
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 | |||
268 | static 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 | |||
279 | static 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 | |||
298 | static 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 | |||
309 | static 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 | |||
320 | enum mips_regset { | ||
321 | REGSET_GPR, | ||
322 | REGSET_FPR, | ||
323 | }; | ||
324 | |||
325 | static 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 | |||
344 | static 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 | |||
352 | static 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 | |||
371 | static 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 | |||
379 | const 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 | |||
258 | long arch_ptrace(struct task_struct *child, long request, | 393 | long 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 | ||
520 | static 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 | */ |
536 | asmlinkage void syscall_trace_enter(struct pt_regs *regs) | 659 | asmlinkage 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 | ||
564 | out: | 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 | } |