2
* linux/arch/m68knommu/kernel/ptrace.c
4
* Copyright (C) 1994 by Hamish Macdonald
5
* Taken from linux/kernel/ptrace.c and modified for M680x0.
6
* linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
8
* This file is subject to the terms and conditions of the GNU General
9
* Public License. See the file COPYING in the main directory of
10
* this archive for more details.
13
#include <linux/kernel.h>
14
#include <linux/sched.h>
16
#include <linux/smp.h>
17
#include <linux/errno.h>
18
#include <linux/ptrace.h>
19
#include <linux/user.h>
20
#include <linux/signal.h>
21
#include <linux/tracehook.h>
23
#include <asm/uaccess.h>
25
#include <asm/pgtable.h>
26
#include <asm/system.h>
27
#include <asm/processor.h>
30
* does not yet catch signals sent when the child dies.
31
* in exit.c or in signal.c.
34
/* determines which bits in the SR the user has access to. */
35
/* 1 = access 0 = no access */
36
#define SR_MASK 0x001f
38
/* sets the trace bits. */
39
#define TRACE_BITS 0x8000
41
/* Find the stack offset for a register, relative to thread.esp0. */
42
#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
43
#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
44
- sizeof(struct switch_stack))
45
/* Mapping from PT_xxx to the stack offset at which the register is
46
saved. Notice that usp has no stack-slot and needs to be treated
47
specially (see get_reg/put_reg below). */
48
static int regoff[] = {
49
PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
50
PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
51
PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
52
SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
53
PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
57
* Get contents of register REGNO in task TASK.
59
static inline long get_reg(struct task_struct *task, int regno)
64
addr = &task->thread.usp;
65
else if (regno < ARRAY_SIZE(regoff))
66
addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
73
* Write contents of register REGNO in task TASK.
75
static inline int put_reg(struct task_struct *task, int regno,
81
addr = &task->thread.usp;
82
else if (regno < ARRAY_SIZE(regoff))
83
addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
90
void user_enable_single_step(struct task_struct *task)
92
unsigned long srflags;
93
srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
94
put_reg(task, PT_SR, srflags);
97
void user_disable_single_step(struct task_struct *task)
99
unsigned long srflags;
100
srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
101
put_reg(task, PT_SR, srflags);
105
* Called by kernel/ptrace.c when detaching..
107
* Make sure the single step bit is not set.
109
void ptrace_disable(struct task_struct *child)
111
/* make sure the single step bit is not set. */
112
user_disable_single_step(child);
115
long arch_ptrace(struct task_struct *child, long request,
116
unsigned long addr, unsigned long data)
119
int regno = addr >> 2;
120
unsigned long __user *datap = (unsigned long __user *) data;
123
/* read the word at location addr in the USER area. */
124
case PTRACE_PEEKUSR: {
128
if ((addr & 3) || addr > sizeof(struct user) - 3)
131
tmp = 0; /* Default return condition */
134
tmp = get_reg(child, regno);
137
} else if (regno >= 21 && regno < 49) {
138
tmp = child->thread.fp[regno - 21];
139
} else if (regno == 49) {
140
tmp = child->mm->start_code;
141
} else if (regno == 50) {
142
tmp = child->mm->start_data;
143
} else if (regno == 51) {
144
tmp = child->mm->end_code;
147
ret = put_user(tmp, datap);
151
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
153
if ((addr & 3) || addr > sizeof(struct user) - 3)
156
if (regno == PT_SR) {
159
data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
162
if (put_reg(child, regno, data))
167
if (regno >= 21 && regno < 48)
169
child->thread.fp[regno - 21] = data;
174
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
177
for (i = 0; i < 19; i++) {
178
tmp = get_reg(child, i);
181
if (put_user(tmp, datap)) {
191
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
194
for (i = 0; i < 19; i++) {
195
if (get_user(tmp, datap)) {
202
tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
204
put_reg(child, i, tmp);
211
#ifdef PTRACE_GETFPREGS
212
case PTRACE_GETFPREGS: { /* Get the child FPU state. */
214
if (copy_to_user(datap, &child->thread.fp,
215
sizeof(struct user_m68kfp_struct)))
221
#ifdef PTRACE_SETFPREGS
222
case PTRACE_SETFPREGS: { /* Set the child FPU state. */
224
if (copy_from_user(&child->thread.fp, datap,
225
sizeof(struct user_m68kfp_struct)))
231
case PTRACE_GET_THREAD_AREA:
232
ret = put_user(task_thread_info(child)->tp_value, datap);
236
ret = ptrace_request(child, request, addr, data);
242
asmlinkage int syscall_trace_enter(void)
246
if (test_thread_flag(TIF_SYSCALL_TRACE))
247
ret = tracehook_report_syscall_entry(task_pt_regs(current));
251
asmlinkage void syscall_trace_leave(void)
253
if (test_thread_flag(TIF_SYSCALL_TRACE))
254
tracehook_report_syscall_exit(task_pt_regs(current), 0);