143dec91fSGreg Ungerer /*
243dec91fSGreg Ungerer * linux/arch/m68k/kernel/ptrace.c
343dec91fSGreg Ungerer *
443dec91fSGreg Ungerer * Copyright (C) 1994 by Hamish Macdonald
543dec91fSGreg Ungerer * Taken from linux/kernel/ptrace.c and modified for M680x0.
643dec91fSGreg Ungerer * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
743dec91fSGreg Ungerer *
843dec91fSGreg Ungerer * This file is subject to the terms and conditions of the GNU General
943dec91fSGreg Ungerer * Public License. See the file COPYING in the main directory of
1043dec91fSGreg Ungerer * this archive for more details.
1143dec91fSGreg Ungerer */
1243dec91fSGreg Ungerer
1343dec91fSGreg Ungerer #include <linux/kernel.h>
1443dec91fSGreg Ungerer #include <linux/sched.h>
1568db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
1643dec91fSGreg Ungerer #include <linux/mm.h>
1743dec91fSGreg Ungerer #include <linux/smp.h>
1843dec91fSGreg Ungerer #include <linux/errno.h>
1943dec91fSGreg Ungerer #include <linux/ptrace.h>
2043dec91fSGreg Ungerer #include <linux/user.h>
2143dec91fSGreg Ungerer #include <linux/signal.h>
22bd53e442SGreg Ungerer #include <linux/regset.h>
23bd53e442SGreg Ungerer #include <linux/elf.h>
24*6baaade1SMichael Schmitz #include <linux/seccomp.h>
257c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
2643dec91fSGreg Ungerer #include <asm/page.h>
2743dec91fSGreg Ungerer #include <asm/processor.h>
2843dec91fSGreg Ungerer
2943dec91fSGreg Ungerer /*
3043dec91fSGreg Ungerer * does not yet catch signals sent when the child dies.
3143dec91fSGreg Ungerer * in exit.c or in signal.c.
3243dec91fSGreg Ungerer */
3343dec91fSGreg Ungerer
3443dec91fSGreg Ungerer /* determines which bits in the SR the user has access to. */
3543dec91fSGreg Ungerer /* 1 = access 0 = no access */
3643dec91fSGreg Ungerer #define SR_MASK 0x001f
3743dec91fSGreg Ungerer
3843dec91fSGreg Ungerer /* sets the trace bits. */
3943dec91fSGreg Ungerer #define TRACE_BITS 0xC000
4043dec91fSGreg Ungerer #define T1_BIT 0x8000
4143dec91fSGreg Ungerer #define T0_BIT 0x4000
4243dec91fSGreg Ungerer
4343dec91fSGreg Ungerer /* Find the stack offset for a register, relative to thread.esp0. */
4443dec91fSGreg Ungerer #define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
4543dec91fSGreg Ungerer #define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
4643dec91fSGreg Ungerer - sizeof(struct switch_stack))
4743dec91fSGreg Ungerer /* Mapping from PT_xxx to the stack offset at which the register is
4843dec91fSGreg Ungerer saved. Notice that usp has no stack-slot and needs to be treated
4943dec91fSGreg Ungerer specially (see get_reg/put_reg below). */
5043dec91fSGreg Ungerer static const int regoff[] = {
5143dec91fSGreg Ungerer [0] = PT_REG(d1),
5243dec91fSGreg Ungerer [1] = PT_REG(d2),
5343dec91fSGreg Ungerer [2] = PT_REG(d3),
5443dec91fSGreg Ungerer [3] = PT_REG(d4),
5543dec91fSGreg Ungerer [4] = PT_REG(d5),
5643dec91fSGreg Ungerer [5] = SW_REG(d6),
5743dec91fSGreg Ungerer [6] = SW_REG(d7),
5843dec91fSGreg Ungerer [7] = PT_REG(a0),
5943dec91fSGreg Ungerer [8] = PT_REG(a1),
6043dec91fSGreg Ungerer [9] = PT_REG(a2),
6143dec91fSGreg Ungerer [10] = SW_REG(a3),
6243dec91fSGreg Ungerer [11] = SW_REG(a4),
6343dec91fSGreg Ungerer [12] = SW_REG(a5),
6443dec91fSGreg Ungerer [13] = SW_REG(a6),
6543dec91fSGreg Ungerer [14] = PT_REG(d0),
6643dec91fSGreg Ungerer [15] = -1,
6743dec91fSGreg Ungerer [16] = PT_REG(orig_d0),
6843dec91fSGreg Ungerer [17] = PT_REG(sr),
6943dec91fSGreg Ungerer [18] = PT_REG(pc),
7043dec91fSGreg Ungerer };
7143dec91fSGreg Ungerer
7243dec91fSGreg Ungerer /*
7343dec91fSGreg Ungerer * Get contents of register REGNO in task TASK.
7443dec91fSGreg Ungerer */
get_reg(struct task_struct * task,int regno)7543dec91fSGreg Ungerer static inline long get_reg(struct task_struct *task, int regno)
7643dec91fSGreg Ungerer {
7743dec91fSGreg Ungerer unsigned long *addr;
7843dec91fSGreg Ungerer
7943dec91fSGreg Ungerer if (regno == PT_USP)
8043dec91fSGreg Ungerer addr = &task->thread.usp;
8143dec91fSGreg Ungerer else if (regno < ARRAY_SIZE(regoff))
8243dec91fSGreg Ungerer addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
8343dec91fSGreg Ungerer else
8443dec91fSGreg Ungerer return 0;
8543dec91fSGreg Ungerer /* Need to take stkadj into account. */
8643dec91fSGreg Ungerer if (regno == PT_SR || regno == PT_PC) {
8743dec91fSGreg Ungerer long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
8843dec91fSGreg Ungerer addr = (unsigned long *) ((unsigned long)addr + stkadj);
8943dec91fSGreg Ungerer /* The sr is actually a 16 bit register. */
9043dec91fSGreg Ungerer if (regno == PT_SR)
9143dec91fSGreg Ungerer return *(unsigned short *)addr;
9243dec91fSGreg Ungerer }
9343dec91fSGreg Ungerer return *addr;
9443dec91fSGreg Ungerer }
9543dec91fSGreg Ungerer
9643dec91fSGreg Ungerer /*
9743dec91fSGreg Ungerer * Write contents of register REGNO in task TASK.
9843dec91fSGreg Ungerer */
put_reg(struct task_struct * task,int regno,unsigned long data)9943dec91fSGreg Ungerer static inline int put_reg(struct task_struct *task, int regno,
10043dec91fSGreg Ungerer unsigned long data)
10143dec91fSGreg Ungerer {
10243dec91fSGreg Ungerer unsigned long *addr;
10343dec91fSGreg Ungerer
10443dec91fSGreg Ungerer if (regno == PT_USP)
10543dec91fSGreg Ungerer addr = &task->thread.usp;
10643dec91fSGreg Ungerer else if (regno < ARRAY_SIZE(regoff))
10743dec91fSGreg Ungerer addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
10843dec91fSGreg Ungerer else
10943dec91fSGreg Ungerer return -1;
11043dec91fSGreg Ungerer /* Need to take stkadj into account. */
11143dec91fSGreg Ungerer if (regno == PT_SR || regno == PT_PC) {
11243dec91fSGreg Ungerer long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
11343dec91fSGreg Ungerer addr = (unsigned long *) ((unsigned long)addr + stkadj);
11443dec91fSGreg Ungerer /* The sr is actually a 16 bit register. */
11543dec91fSGreg Ungerer if (regno == PT_SR) {
11643dec91fSGreg Ungerer *(unsigned short *)addr = data;
11743dec91fSGreg Ungerer return 0;
11843dec91fSGreg Ungerer }
11943dec91fSGreg Ungerer }
12043dec91fSGreg Ungerer *addr = data;
12143dec91fSGreg Ungerer return 0;
12243dec91fSGreg Ungerer }
12343dec91fSGreg Ungerer
12443dec91fSGreg Ungerer /*
12543dec91fSGreg Ungerer * Make sure the single step bit is not set.
12643dec91fSGreg Ungerer */
singlestep_disable(struct task_struct * child)12743dec91fSGreg Ungerer static inline void singlestep_disable(struct task_struct *child)
12843dec91fSGreg Ungerer {
12943dec91fSGreg Ungerer unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
13043dec91fSGreg Ungerer put_reg(child, PT_SR, tmp);
13143dec91fSGreg Ungerer clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
13243dec91fSGreg Ungerer }
13343dec91fSGreg Ungerer
13443dec91fSGreg Ungerer /*
13543dec91fSGreg Ungerer * Called by kernel/ptrace.c when detaching..
13643dec91fSGreg Ungerer */
ptrace_disable(struct task_struct * child)13743dec91fSGreg Ungerer void ptrace_disable(struct task_struct *child)
13843dec91fSGreg Ungerer {
13943dec91fSGreg Ungerer singlestep_disable(child);
14043dec91fSGreg Ungerer }
14143dec91fSGreg Ungerer
user_enable_single_step(struct task_struct * child)14243dec91fSGreg Ungerer void user_enable_single_step(struct task_struct *child)
14343dec91fSGreg Ungerer {
14443dec91fSGreg Ungerer unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
14543dec91fSGreg Ungerer put_reg(child, PT_SR, tmp | T1_BIT);
14643dec91fSGreg Ungerer set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
14743dec91fSGreg Ungerer }
14843dec91fSGreg Ungerer
14966d857b0SGreg Ungerer #ifdef CONFIG_MMU
user_enable_block_step(struct task_struct * child)15043dec91fSGreg Ungerer void user_enable_block_step(struct task_struct *child)
15143dec91fSGreg Ungerer {
15243dec91fSGreg Ungerer unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
15343dec91fSGreg Ungerer put_reg(child, PT_SR, tmp | T0_BIT);
15443dec91fSGreg Ungerer }
15566d857b0SGreg Ungerer #endif
15643dec91fSGreg Ungerer
user_disable_single_step(struct task_struct * child)15743dec91fSGreg Ungerer void user_disable_single_step(struct task_struct *child)
15843dec91fSGreg Ungerer {
15943dec91fSGreg Ungerer singlestep_disable(child);
16043dec91fSGreg Ungerer }
16143dec91fSGreg Ungerer
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)16243dec91fSGreg Ungerer long arch_ptrace(struct task_struct *child, long request,
16343dec91fSGreg Ungerer unsigned long addr, unsigned long data)
16443dec91fSGreg Ungerer {
16543dec91fSGreg Ungerer unsigned long tmp;
16643dec91fSGreg Ungerer int i, ret = 0;
16743dec91fSGreg Ungerer int regno = addr >> 2; /* temporary hack. */
16843dec91fSGreg Ungerer unsigned long __user *datap = (unsigned long __user *) data;
16943dec91fSGreg Ungerer
17043dec91fSGreg Ungerer switch (request) {
17143dec91fSGreg Ungerer /* read the word at location addr in the USER area. */
17243dec91fSGreg Ungerer case PTRACE_PEEKUSR:
17343dec91fSGreg Ungerer if (addr & 3)
17443dec91fSGreg Ungerer goto out_eio;
17543dec91fSGreg Ungerer
17643dec91fSGreg Ungerer if (regno >= 0 && regno < 19) {
17743dec91fSGreg Ungerer tmp = get_reg(child, regno);
17843dec91fSGreg Ungerer } else if (regno >= 21 && regno < 49) {
17943dec91fSGreg Ungerer tmp = child->thread.fp[regno - 21];
18043dec91fSGreg Ungerer /* Convert internal fpu reg representation
18143dec91fSGreg Ungerer * into long double format
18243dec91fSGreg Ungerer */
18343dec91fSGreg Ungerer if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
18443dec91fSGreg Ungerer tmp = ((tmp & 0xffff0000) << 15) |
18543dec91fSGreg Ungerer ((tmp & 0x0000ffff) << 16);
18643dec91fSGreg Ungerer #ifndef CONFIG_MMU
18743dec91fSGreg Ungerer } else if (regno == 49) {
18843dec91fSGreg Ungerer tmp = child->mm->start_code;
18943dec91fSGreg Ungerer } else if (regno == 50) {
19043dec91fSGreg Ungerer tmp = child->mm->start_data;
19143dec91fSGreg Ungerer } else if (regno == 51) {
19243dec91fSGreg Ungerer tmp = child->mm->end_code;
19343dec91fSGreg Ungerer #endif
19443dec91fSGreg Ungerer } else
19543dec91fSGreg Ungerer goto out_eio;
19643dec91fSGreg Ungerer ret = put_user(tmp, datap);
19743dec91fSGreg Ungerer break;
19843dec91fSGreg Ungerer
19943dec91fSGreg Ungerer case PTRACE_POKEUSR:
20043dec91fSGreg Ungerer /* write the word at location addr in the USER area */
20143dec91fSGreg Ungerer if (addr & 3)
20243dec91fSGreg Ungerer goto out_eio;
20343dec91fSGreg Ungerer
20443dec91fSGreg Ungerer if (regno == PT_SR) {
20543dec91fSGreg Ungerer data &= SR_MASK;
20643dec91fSGreg Ungerer data |= get_reg(child, PT_SR) & ~SR_MASK;
20743dec91fSGreg Ungerer }
20843dec91fSGreg Ungerer if (regno >= 0 && regno < 19) {
20943dec91fSGreg Ungerer if (put_reg(child, regno, data))
21043dec91fSGreg Ungerer goto out_eio;
21143dec91fSGreg Ungerer } else if (regno >= 21 && regno < 48) {
21243dec91fSGreg Ungerer /* Convert long double format
21343dec91fSGreg Ungerer * into internal fpu reg representation
21443dec91fSGreg Ungerer */
21543dec91fSGreg Ungerer if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
21643dec91fSGreg Ungerer data <<= 15;
21743dec91fSGreg Ungerer data = (data & 0xffff0000) |
21843dec91fSGreg Ungerer ((data & 0x0000ffff) >> 1);
21943dec91fSGreg Ungerer }
22043dec91fSGreg Ungerer child->thread.fp[regno - 21] = data;
22143dec91fSGreg Ungerer } else
22243dec91fSGreg Ungerer goto out_eio;
22343dec91fSGreg Ungerer break;
22443dec91fSGreg Ungerer
22543dec91fSGreg Ungerer case PTRACE_GETREGS: /* Get all gp regs from the child. */
22643dec91fSGreg Ungerer for (i = 0; i < 19; i++) {
22743dec91fSGreg Ungerer tmp = get_reg(child, i);
22843dec91fSGreg Ungerer ret = put_user(tmp, datap);
22943dec91fSGreg Ungerer if (ret)
23043dec91fSGreg Ungerer break;
23143dec91fSGreg Ungerer datap++;
23243dec91fSGreg Ungerer }
23343dec91fSGreg Ungerer break;
23443dec91fSGreg Ungerer
23543dec91fSGreg Ungerer case PTRACE_SETREGS: /* Set all gp regs in the child. */
23643dec91fSGreg Ungerer for (i = 0; i < 19; i++) {
23743dec91fSGreg Ungerer ret = get_user(tmp, datap);
23843dec91fSGreg Ungerer if (ret)
23943dec91fSGreg Ungerer break;
24043dec91fSGreg Ungerer if (i == PT_SR) {
24143dec91fSGreg Ungerer tmp &= SR_MASK;
24243dec91fSGreg Ungerer tmp |= get_reg(child, PT_SR) & ~SR_MASK;
24343dec91fSGreg Ungerer }
24443dec91fSGreg Ungerer put_reg(child, i, tmp);
24543dec91fSGreg Ungerer datap++;
24643dec91fSGreg Ungerer }
24743dec91fSGreg Ungerer break;
24843dec91fSGreg Ungerer
24943dec91fSGreg Ungerer case PTRACE_GETFPREGS: /* Get the child FPU state. */
25043dec91fSGreg Ungerer if (copy_to_user(datap, &child->thread.fp,
25143dec91fSGreg Ungerer sizeof(struct user_m68kfp_struct)))
25243dec91fSGreg Ungerer ret = -EFAULT;
25343dec91fSGreg Ungerer break;
25443dec91fSGreg Ungerer
25543dec91fSGreg Ungerer case PTRACE_SETFPREGS: /* Set the child FPU state. */
25643dec91fSGreg Ungerer if (copy_from_user(&child->thread.fp, datap,
25743dec91fSGreg Ungerer sizeof(struct user_m68kfp_struct)))
25843dec91fSGreg Ungerer ret = -EFAULT;
25943dec91fSGreg Ungerer break;
26043dec91fSGreg Ungerer
26143dec91fSGreg Ungerer case PTRACE_GET_THREAD_AREA:
26243dec91fSGreg Ungerer ret = put_user(task_thread_info(child)->tp_value, datap);
26343dec91fSGreg Ungerer break;
26443dec91fSGreg Ungerer
26543dec91fSGreg Ungerer default:
26643dec91fSGreg Ungerer ret = ptrace_request(child, request, addr, data);
26743dec91fSGreg Ungerer break;
26843dec91fSGreg Ungerer }
26943dec91fSGreg Ungerer
27043dec91fSGreg Ungerer return ret;
27143dec91fSGreg Ungerer out_eio:
27243dec91fSGreg Ungerer return -EIO;
27343dec91fSGreg Ungerer }
27443dec91fSGreg Ungerer
syscall_trace_enter(void)27543dec91fSGreg Ungerer asmlinkage int syscall_trace_enter(void)
27643dec91fSGreg Ungerer {
27743dec91fSGreg Ungerer int ret = 0;
27843dec91fSGreg Ungerer
27943dec91fSGreg Ungerer if (test_thread_flag(TIF_SYSCALL_TRACE))
280153474baSEric W. Biederman ret = ptrace_report_syscall_entry(task_pt_regs(current));
281*6baaade1SMichael Schmitz
282*6baaade1SMichael Schmitz if (secure_computing() == -1)
283*6baaade1SMichael Schmitz return -1;
284*6baaade1SMichael Schmitz
28543dec91fSGreg Ungerer return ret;
28643dec91fSGreg Ungerer }
28743dec91fSGreg Ungerer
syscall_trace_leave(void)28843dec91fSGreg Ungerer asmlinkage void syscall_trace_leave(void)
28943dec91fSGreg Ungerer {
29043dec91fSGreg Ungerer if (test_thread_flag(TIF_SYSCALL_TRACE))
291153474baSEric W. Biederman ptrace_report_syscall_exit(task_pt_regs(current), 0);
29243dec91fSGreg Ungerer }
293bd53e442SGreg Ungerer
294bd53e442SGreg Ungerer #if defined(CONFIG_BINFMT_ELF_FDPIC) && defined(CONFIG_ELF_CORE)
295bd53e442SGreg Ungerer /*
296bd53e442SGreg Ungerer * Currently the only thing that needs to use regsets for m68k is the
297bd53e442SGreg Ungerer * coredump support of the elf_fdpic loader. Implement the minimum
298bd53e442SGreg Ungerer * definitions required for that.
299bd53e442SGreg Ungerer */
m68k_regset_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)300bd53e442SGreg Ungerer static int m68k_regset_get(struct task_struct *target,
301bd53e442SGreg Ungerer const struct user_regset *regset,
302bd53e442SGreg Ungerer struct membuf to)
303bd53e442SGreg Ungerer {
304bd53e442SGreg Ungerer struct pt_regs *ptregs = task_pt_regs(target);
305bd53e442SGreg Ungerer u32 uregs[ELF_NGREG];
306bd53e442SGreg Ungerer
307bd53e442SGreg Ungerer ELF_CORE_COPY_REGS(uregs, ptregs);
308bd53e442SGreg Ungerer return membuf_write(&to, uregs, sizeof(uregs));
309bd53e442SGreg Ungerer }
310bd53e442SGreg Ungerer
311bd53e442SGreg Ungerer enum m68k_regset {
312bd53e442SGreg Ungerer REGSET_GPR,
313bd53e442SGreg Ungerer #ifdef CONFIG_FPU
314bd53e442SGreg Ungerer REGSET_FPU,
315bd53e442SGreg Ungerer #endif
316bd53e442SGreg Ungerer };
317bd53e442SGreg Ungerer
318bd53e442SGreg Ungerer static const struct user_regset m68k_user_regsets[] = {
319bd53e442SGreg Ungerer [REGSET_GPR] = {
320bd53e442SGreg Ungerer .core_note_type = NT_PRSTATUS,
321bd53e442SGreg Ungerer .n = ELF_NGREG,
322bd53e442SGreg Ungerer .size = sizeof(u32),
323bd53e442SGreg Ungerer .align = sizeof(u16),
324bd53e442SGreg Ungerer .regset_get = m68k_regset_get,
325bd53e442SGreg Ungerer },
326bd53e442SGreg Ungerer #ifdef CONFIG_FPU
327bd53e442SGreg Ungerer [REGSET_FPU] = {
328bd53e442SGreg Ungerer .core_note_type = NT_PRFPREG,
329bd53e442SGreg Ungerer .n = sizeof(struct user_m68kfp_struct) / sizeof(u32),
330bd53e442SGreg Ungerer .size = sizeof(u32),
331bd53e442SGreg Ungerer .align = sizeof(u32),
332bd53e442SGreg Ungerer }
333bd53e442SGreg Ungerer #endif /* CONFIG_FPU */
334bd53e442SGreg Ungerer };
335bd53e442SGreg Ungerer
336bd53e442SGreg Ungerer static const struct user_regset_view user_m68k_view = {
337bd53e442SGreg Ungerer .name = "m68k",
338bd53e442SGreg Ungerer .e_machine = EM_68K,
339bd53e442SGreg Ungerer .ei_osabi = ELF_OSABI,
340bd53e442SGreg Ungerer .regsets = m68k_user_regsets,
341bd53e442SGreg Ungerer .n = ARRAY_SIZE(m68k_user_regsets)
342bd53e442SGreg Ungerer };
343bd53e442SGreg Ungerer
task_user_regset_view(struct task_struct * task)344bd53e442SGreg Ungerer const struct user_regset_view *task_user_regset_view(struct task_struct *task)
345bd53e442SGreg Ungerer {
346bd53e442SGreg Ungerer return &user_m68k_view;
347bd53e442SGreg Ungerer }
348bd53e442SGreg Ungerer #endif /* CONFIG_BINFMT_ELF_FDPIC && CONFIG_ELF_CORE */
349