Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/kernel/ptrace_no.c
10817 views
1
/*
2
* linux/arch/m68knommu/kernel/ptrace.c
3
*
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
7
*
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.
11
*/
12
13
#include <linux/kernel.h>
14
#include <linux/sched.h>
15
#include <linux/mm.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>
22
23
#include <asm/uaccess.h>
24
#include <asm/page.h>
25
#include <asm/pgtable.h>
26
#include <asm/system.h>
27
#include <asm/processor.h>
28
29
/*
30
* does not yet catch signals sent when the child dies.
31
* in exit.c or in signal.c.
32
*/
33
34
/* determines which bits in the SR the user has access to. */
35
/* 1 = access 0 = no access */
36
#define SR_MASK 0x001f
37
38
/* sets the trace bits. */
39
#define TRACE_BITS 0x8000
40
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),
54
};
55
56
/*
57
* Get contents of register REGNO in task TASK.
58
*/
59
static inline long get_reg(struct task_struct *task, int regno)
60
{
61
unsigned long *addr;
62
63
if (regno == PT_USP)
64
addr = &task->thread.usp;
65
else if (regno < ARRAY_SIZE(regoff))
66
addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
67
else
68
return 0;
69
return *addr;
70
}
71
72
/*
73
* Write contents of register REGNO in task TASK.
74
*/
75
static inline int put_reg(struct task_struct *task, int regno,
76
unsigned long data)
77
{
78
unsigned long *addr;
79
80
if (regno == PT_USP)
81
addr = &task->thread.usp;
82
else if (regno < ARRAY_SIZE(regoff))
83
addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
84
else
85
return -1;
86
*addr = data;
87
return 0;
88
}
89
90
void user_enable_single_step(struct task_struct *task)
91
{
92
unsigned long srflags;
93
srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
94
put_reg(task, PT_SR, srflags);
95
}
96
97
void user_disable_single_step(struct task_struct *task)
98
{
99
unsigned long srflags;
100
srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
101
put_reg(task, PT_SR, srflags);
102
}
103
104
/*
105
* Called by kernel/ptrace.c when detaching..
106
*
107
* Make sure the single step bit is not set.
108
*/
109
void ptrace_disable(struct task_struct *child)
110
{
111
/* make sure the single step bit is not set. */
112
user_disable_single_step(child);
113
}
114
115
long arch_ptrace(struct task_struct *child, long request,
116
unsigned long addr, unsigned long data)
117
{
118
int ret;
119
int regno = addr >> 2;
120
unsigned long __user *datap = (unsigned long __user *) data;
121
122
switch (request) {
123
/* read the word at location addr in the USER area. */
124
case PTRACE_PEEKUSR: {
125
unsigned long tmp;
126
127
ret = -EIO;
128
if ((addr & 3) || addr > sizeof(struct user) - 3)
129
break;
130
131
tmp = 0; /* Default return condition */
132
ret = -EIO;
133
if (regno < 19) {
134
tmp = get_reg(child, regno);
135
if (regno == PT_SR)
136
tmp >>= 16;
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;
145
} else
146
break;
147
ret = put_user(tmp, datap);
148
break;
149
}
150
151
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
152
ret = -EIO;
153
if ((addr & 3) || addr > sizeof(struct user) - 3)
154
break;
155
156
if (regno == PT_SR) {
157
data &= SR_MASK;
158
data <<= 16;
159
data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
160
}
161
if (regno < 19) {
162
if (put_reg(child, regno, data))
163
break;
164
ret = 0;
165
break;
166
}
167
if (regno >= 21 && regno < 48)
168
{
169
child->thread.fp[regno - 21] = data;
170
ret = 0;
171
}
172
break;
173
174
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
175
int i;
176
unsigned long tmp;
177
for (i = 0; i < 19; i++) {
178
tmp = get_reg(child, i);
179
if (i == PT_SR)
180
tmp >>= 16;
181
if (put_user(tmp, datap)) {
182
ret = -EFAULT;
183
break;
184
}
185
datap++;
186
}
187
ret = 0;
188
break;
189
}
190
191
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
192
int i;
193
unsigned long tmp;
194
for (i = 0; i < 19; i++) {
195
if (get_user(tmp, datap)) {
196
ret = -EFAULT;
197
break;
198
}
199
if (i == PT_SR) {
200
tmp &= SR_MASK;
201
tmp <<= 16;
202
tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
203
}
204
put_reg(child, i, tmp);
205
datap++;
206
}
207
ret = 0;
208
break;
209
}
210
211
#ifdef PTRACE_GETFPREGS
212
case PTRACE_GETFPREGS: { /* Get the child FPU state. */
213
ret = 0;
214
if (copy_to_user(datap, &child->thread.fp,
215
sizeof(struct user_m68kfp_struct)))
216
ret = -EFAULT;
217
break;
218
}
219
#endif
220
221
#ifdef PTRACE_SETFPREGS
222
case PTRACE_SETFPREGS: { /* Set the child FPU state. */
223
ret = 0;
224
if (copy_from_user(&child->thread.fp, datap,
225
sizeof(struct user_m68kfp_struct)))
226
ret = -EFAULT;
227
break;
228
}
229
#endif
230
231
case PTRACE_GET_THREAD_AREA:
232
ret = put_user(task_thread_info(child)->tp_value, datap);
233
break;
234
235
default:
236
ret = ptrace_request(child, request, addr, data);
237
break;
238
}
239
return ret;
240
}
241
242
asmlinkage int syscall_trace_enter(void)
243
{
244
int ret = 0;
245
246
if (test_thread_flag(TIF_SYSCALL_TRACE))
247
ret = tracehook_report_syscall_entry(task_pt_regs(current));
248
return ret;
249
}
250
251
asmlinkage void syscall_trace_leave(void)
252
{
253
if (test_thread_flag(TIF_SYSCALL_TRACE))
254
tracehook_report_syscall_exit(task_pt_regs(current), 0);
255
}
256
257