12b438454SMichal Simek /*
22b438454SMichal Simek * `ptrace' system call
32b438454SMichal Simek *
42b438454SMichal Simek * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
52b438454SMichal Simek * Copyright (C) 2007-2009 PetaLogix
62b438454SMichal Simek * Copyright (C) 2004-2007 John Williams <john.williams@petalogix.com>
72b438454SMichal Simek *
82b438454SMichal Simek * derived from arch/v850/kernel/ptrace.c
92b438454SMichal Simek *
102b438454SMichal Simek * Copyright (C) 2002,03 NEC Electronics Corporation
112b438454SMichal Simek * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
122b438454SMichal Simek *
132b438454SMichal Simek * Derived from arch/mips/kernel/ptrace.c:
142b438454SMichal Simek *
152b438454SMichal Simek * Copyright (C) 1992 Ross Biro
162b438454SMichal Simek * Copyright (C) Linus Torvalds
172b438454SMichal Simek * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
182b438454SMichal Simek * Copyright (C) 1996 David S. Miller
192b438454SMichal Simek * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
202b438454SMichal Simek * Copyright (C) 1999 MIPS Technologies, Inc.
212b438454SMichal Simek *
222b438454SMichal Simek * This file is subject to the terms and conditions of the GNU General
232b438454SMichal Simek * Public License. See the file COPYING in the main directory of this
242b438454SMichal Simek * archive for more details.
252b438454SMichal Simek */
262b438454SMichal Simek
272b438454SMichal Simek #include <linux/kernel.h>
282b438454SMichal Simek #include <linux/mm.h>
292b438454SMichal Simek #include <linux/sched.h>
3068db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
312b438454SMichal Simek #include <linux/ptrace.h>
322b438454SMichal Simek #include <linux/signal.h>
3323575483SMichal Simek #include <linux/elf.h>
3423575483SMichal Simek #include <linux/audit.h>
3523575483SMichal Simek #include <linux/seccomp.h>
362b438454SMichal Simek
372b438454SMichal Simek #include <linux/errno.h>
382b438454SMichal Simek #include <asm/processor.h>
392b438454SMichal Simek #include <linux/uaccess.h>
402b438454SMichal Simek #include <asm/asm-offsets.h>
416847ba91SMichal Simek #include <asm/cacheflush.h>
42c1df53b3SMichal Simek #include <asm/syscall.h>
436bd55f0bSMichal Simek #include <linux/io.h>
442b438454SMichal Simek
452b438454SMichal Simek /* Returns the address where the register at REG_OFFS in P is stashed away. */
reg_save_addr(unsigned reg_offs,struct task_struct * t)462b438454SMichal Simek static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
472b438454SMichal Simek struct task_struct *t)
482b438454SMichal Simek {
492b438454SMichal Simek struct pt_regs *regs;
502b438454SMichal Simek
512b438454SMichal Simek /*
522b438454SMichal Simek * Three basic cases:
532b438454SMichal Simek *
542b438454SMichal Simek * (1) A register normally saved before calling the scheduler, is
552b438454SMichal Simek * available in the kernel entry pt_regs structure at the top
562b438454SMichal Simek * of the kernel stack. The kernel trap/irq exit path takes
572b438454SMichal Simek * care to save/restore almost all registers for ptrace'd
582b438454SMichal Simek * processes.
592b438454SMichal Simek *
602b438454SMichal Simek * (2) A call-clobbered register, where the process P entered the
612b438454SMichal Simek * kernel via [syscall] trap, is not stored anywhere; that's
622b438454SMichal Simek * OK, because such registers are not expected to be preserved
632b438454SMichal Simek * when the trap returns anyway (so we don't actually bother to
642b438454SMichal Simek * test for this case).
652b438454SMichal Simek *
662b438454SMichal Simek * (3) A few registers not used at all by the kernel, and so
672b438454SMichal Simek * normally never saved except by context-switches, are in the
682b438454SMichal Simek * context switch state.
692b438454SMichal Simek */
702b438454SMichal Simek
712b438454SMichal Simek /* Register saved during kernel entry (or not available). */
722b438454SMichal Simek regs = task_pt_regs(t);
732b438454SMichal Simek
742b438454SMichal Simek return (microblaze_reg_t *)((char *)regs + reg_offs);
752b438454SMichal Simek }
762b438454SMichal Simek
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)779b05a69eSNamhyung Kim long arch_ptrace(struct task_struct *child, long request,
789b05a69eSNamhyung Kim unsigned long addr, unsigned long data)
792b438454SMichal Simek {
802b438454SMichal Simek int rval;
812b438454SMichal Simek unsigned long val = 0;
822b438454SMichal Simek
832b438454SMichal Simek switch (request) {
842b438454SMichal Simek /* Read/write the word at location ADDR in the registers. */
852b438454SMichal Simek case PTRACE_PEEKUSR:
862b438454SMichal Simek case PTRACE_POKEUSR:
872b438454SMichal Simek pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
882b438454SMichal Simek rval = 0;
892b438454SMichal Simek if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
902b438454SMichal Simek /*
912b438454SMichal Simek * Special requests that don't actually correspond
922b438454SMichal Simek * to offsets in struct pt_regs.
932b438454SMichal Simek */
942b438454SMichal Simek if (addr == PT_TEXT_ADDR) {
952b438454SMichal Simek val = child->mm->start_code;
962b438454SMichal Simek } else if (addr == PT_DATA_ADDR) {
972b438454SMichal Simek val = child->mm->start_data;
982b438454SMichal Simek } else if (addr == PT_TEXT_LEN) {
992b438454SMichal Simek val = child->mm->end_code
1002b438454SMichal Simek - child->mm->start_code;
1012b438454SMichal Simek } else {
1022b438454SMichal Simek rval = -EIO;
1032b438454SMichal Simek }
104cfd866f6SNamhyung Kim } else if (addr < PT_SIZE && (addr & 0x3) == 0) {
1052b438454SMichal Simek microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
1062b438454SMichal Simek if (request == PTRACE_PEEKUSR)
1072b438454SMichal Simek val = *reg_addr;
1086847ba91SMichal Simek else {
1096847ba91SMichal Simek #if 1
1102b438454SMichal Simek *reg_addr = data;
1116847ba91SMichal Simek #else
1126847ba91SMichal Simek /* MS potential problem on WB system
1136847ba91SMichal Simek * Be aware that reg_addr is virtual address
1146847ba91SMichal Simek * virt_to_phys conversion is necessary.
1156847ba91SMichal Simek * This could be sensible solution.
1166847ba91SMichal Simek */
1176847ba91SMichal Simek u32 paddr = virt_to_phys((u32)reg_addr);
1186847ba91SMichal Simek invalidate_icache_range(paddr, paddr + 4);
1196847ba91SMichal Simek *reg_addr = data;
1206847ba91SMichal Simek flush_dcache_range(paddr, paddr + 4);
1216847ba91SMichal Simek #endif
1226847ba91SMichal Simek }
1232b438454SMichal Simek } else
1242b438454SMichal Simek rval = -EIO;
1252b438454SMichal Simek
1262b438454SMichal Simek if (rval == 0 && request == PTRACE_PEEKUSR)
127c1df53b3SMichal Simek rval = put_user(val, (unsigned long __user *)data);
1282b438454SMichal Simek break;
1292b438454SMichal Simek default:
130b3c1e01aSChristoph Hellwig rval = ptrace_request(child, request, addr, data);
1312b438454SMichal Simek }
1322b438454SMichal Simek return rval;
1332b438454SMichal Simek }
1342b438454SMichal Simek
do_syscall_trace_enter(struct pt_regs * regs)1358543e6c9SMichal Simek asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs)
13623575483SMichal Simek {
1378543e6c9SMichal Simek unsigned long ret = 0;
13823575483SMichal Simek
139e4da89d0SWill Drewry secure_computing_strict(regs->r12);
14023575483SMichal Simek
14123575483SMichal Simek if (test_thread_flag(TIF_SYSCALL_TRACE) &&
142*153474baSEric W. Biederman ptrace_report_syscall_entry(regs))
14323575483SMichal Simek /*
14423575483SMichal Simek * Tracing decided this syscall should not happen.
14523575483SMichal Simek * We'll return a bogus call number to get an ENOSYS
14623575483SMichal Simek * error, but leave the original number in regs->regs[0].
14723575483SMichal Simek */
14823575483SMichal Simek ret = -1L;
14923575483SMichal Simek
15091397401SEric Paris audit_syscall_entry(regs->r12, regs->r5, regs->r6, regs->r7, regs->r8);
15123575483SMichal Simek
15223575483SMichal Simek return ret ?: regs->r12;
15323575483SMichal Simek }
15423575483SMichal Simek
do_syscall_trace_leave(struct pt_regs * regs)15523575483SMichal Simek asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
15623575483SMichal Simek {
15723575483SMichal Simek int step;
15823575483SMichal Simek
159d7e7528bSEric Paris audit_syscall_exit(regs);
16023575483SMichal Simek
16123575483SMichal Simek step = test_thread_flag(TIF_SINGLESTEP);
16223575483SMichal Simek if (step || test_thread_flag(TIF_SYSCALL_TRACE))
163*153474baSEric W. Biederman ptrace_report_syscall_exit(regs, step);
16423575483SMichal Simek }
16523575483SMichal Simek
ptrace_disable(struct task_struct * child)1662b438454SMichal Simek void ptrace_disable(struct task_struct *child)
1672b438454SMichal Simek {
1682b438454SMichal Simek /* nothing to do */
1692b438454SMichal Simek }
170