Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
mips
kernel
ptrace32.c
Go to the documentation of this file.
1
/*
2
* This file is subject to the terms and conditions of the GNU General Public
3
* License. See the file "COPYING" in the main directory of this archive
4
* for more details.
5
*
6
* Copyright (C) 1992 Ross Biro
7
* Copyright (C) Linus Torvalds
8
* Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
9
* Copyright (C) 1996 David S. Miller
10
* Kevin D. Kissell,
[email protected]
and Carsten Langgaard,
[email protected]
11
* Copyright (C) 1999 MIPS Technologies, Inc.
12
* Copyright (C) 2000 Ulf Carlsson
13
*
14
* At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
15
* binaries.
16
*/
17
#include <linux/compiler.h>
18
#include <
linux/compat.h
>
19
#include <linux/kernel.h>
20
#include <linux/sched.h>
21
#include <
linux/mm.h
>
22
#include <linux/errno.h>
23
#include <linux/ptrace.h>
24
#include <
linux/smp.h
>
25
#include <
linux/user.h
>
26
#include <
linux/security.h
>
27
28
#include <asm/cpu.h>
29
#include <
asm/dsp.h
>
30
#include <asm/fpu.h>
31
#include <
asm/mipsregs.h
>
32
#include <
asm/mipsmtregs.h
>
33
#include <asm/pgtable.h>
34
#include <asm/page.h>
35
#include <asm/uaccess.h>
36
#include <asm/bootinfo.h>
37
38
/*
39
* Tracing a 32-bit process with a 64-bit strace and vice versa will not
40
* work. I don't know how to fix this.
41
*/
42
long
compat_arch_ptrace
(
struct
task_struct
*
child
,
compat_long_t
request
,
43
compat_ulong_t
caddr,
compat_ulong_t
cdata
)
44
{
45
int
addr
= caddr;
46
int
data
=
cdata
;
47
int
ret
;
48
49
switch
(request) {
50
51
/*
52
* Read 4 bytes of the other process' storage
53
* data is a pointer specifying where the user wants the
54
* 4 bytes copied into
55
* addr is a pointer in the user's storage that contains an 8 byte
56
* address in the other process of the 4 bytes that is to be read
57
* (this is run in a 32-bit process looking at a 64-bit process)
58
* when I and D space are separate, these will need to be fixed.
59
*/
60
case
PTRACE_PEEKTEXT_3264
:
61
case
PTRACE_PEEKDATA_3264
: {
62
u32
tmp
;
63
int
copied;
64
u32
__user
* addrOthers;
65
66
ret = -
EIO
;
67
68
/* Get the addr in the other process that we want to read */
69
if
(
get_user
(addrOthers, (
u32
__user
*
__user
*) (
unsigned
long
) addr) != 0)
70
break
;
71
72
copied =
access_process_vm
(child, (
u64
)addrOthers, &tmp,
73
sizeof
(tmp), 0);
74
if
(copied !=
sizeof
(tmp))
75
break
;
76
ret =
put_user
(tmp, (
u32
__user
*) (
unsigned
long
) data);
77
break
;
78
}
79
80
/* Read the word at location addr in the USER area. */
81
case
PTRACE_PEEKUSR
: {
82
struct
pt_regs
*
regs
;
83
unsigned
int
tmp
;
84
85
regs =
task_pt_regs
(child);
86
ret = 0;
/* Default return value. */
87
88
switch
(addr) {
89
case
0 ... 31:
90
tmp = regs->
regs
[
addr
];
91
break
;
92
case
FPR_BASE
...
FPR_BASE
+ 31:
93
if
(
tsk_used_math
(child)) {
94
fpureg_t
*fregs = get_fpu_regs(child);
95
96
/*
97
* The odd registers are actually the high
98
* order bits of the values stored in the even
99
* registers - unless we're using r2k_switch.S.
100
*/
101
if
(addr & 1)
102
tmp = (
unsigned
long
) (fregs[((addr & ~1) - 32)] >> 32);
103
else
104
tmp = (
unsigned
long
) (fregs[(addr - 32)] & 0xffffffff);
105
}
else
{
106
tmp = -1;
/* FP not yet used */
107
}
108
break
;
109
case
PC
:
110
tmp = regs->
cp0_epc
;
111
break
;
112
case
CAUSE
:
113
tmp = regs->
cp0_cause
;
114
break
;
115
case
BADVADDR
:
116
tmp = regs->
cp0_badvaddr
;
117
break
;
118
case
MMHI
:
119
tmp = regs->
hi
;
120
break
;
121
case
MMLO
:
122
tmp = regs->
lo
;
123
break
;
124
case
FPC_CSR
:
125
tmp = child->
thread
.fpu.fcr31;
126
break
;
127
case
FPC_EIR
: {
/* implementation / version register */
128
unsigned
int
flags
;
129
#ifdef CONFIG_MIPS_MT_SMTC
130
unsigned
int
irqflags;
131
unsigned
int
mtflags;
132
#endif
/* CONFIG_MIPS_MT_SMTC */
133
134
preempt_disable
();
135
if
(!
cpu_has_fpu
) {
136
preempt_enable
();
137
tmp = 0;
138
break
;
139
}
140
141
#ifdef CONFIG_MIPS_MT_SMTC
142
/* Read-modify-write of Status must be atomic */
143
local_irq_save
(irqflags);
144
mtflags = dmt();
145
#endif
/* CONFIG_MIPS_MT_SMTC */
146
147
if
(
cpu_has_mipsmt
) {
148
unsigned
int
vpflags = dvpe();
149
flags =
read_c0_status
();
150
__enable_fpu
();
151
__asm__
__volatile__(
"cfc1\t%0,$0"
:
"=r"
(tmp));
152
write_c0_status
(flags);
153
evpe(vpflags);
154
}
else
{
155
flags =
read_c0_status
();
156
__enable_fpu
();
157
__asm__
__volatile__(
"cfc1\t%0,$0"
:
"=r"
(tmp));
158
write_c0_status
(flags);
159
}
160
#ifdef CONFIG_MIPS_MT_SMTC
161
emt(mtflags);
162
local_irq_restore
(irqflags);
163
#endif
/* CONFIG_MIPS_MT_SMTC */
164
preempt_enable
();
165
break
;
166
}
167
case
DSP_BASE
...
DSP_BASE
+ 5: {
168
dspreg_t
*dregs;
169
170
if
(!
cpu_has_dsp
) {
171
tmp = 0;
172
ret = -
EIO
;
173
goto
out
;
174
}
175
dregs =
__get_dsp_regs
(child);
176
tmp = (
unsigned
long
) (dregs[addr -
DSP_BASE
]);
177
break
;
178
}
179
case
DSP_CONTROL
:
180
if
(!
cpu_has_dsp
) {
181
tmp = 0;
182
ret = -
EIO
;
183
goto
out
;
184
}
185
tmp = child->
thread
.dsp.dspcontrol;
186
break
;
187
default
:
188
tmp = 0;
189
ret = -
EIO
;
190
goto
out
;
191
}
192
ret =
put_user
(tmp, (
unsigned
__user
*) (
unsigned
long
) data);
193
break
;
194
}
195
196
/*
197
* Write 4 bytes into the other process' storage
198
* data is the 4 bytes that the user wants written
199
* addr is a pointer in the user's storage that contains an
200
* 8 byte address in the other process where the 4 bytes
201
* that is to be written
202
* (this is run in a 32-bit process looking at a 64-bit process)
203
* when I and D space are separate, these will need to be fixed.
204
*/
205
case
PTRACE_POKETEXT_3264
:
206
case
PTRACE_POKEDATA_3264
: {
207
u32
__user
* addrOthers;
208
209
/* Get the addr in the other process that we want to write into */
210
ret = -
EIO
;
211
if
(
get_user
(addrOthers, (
u32
__user
*
__user
*) (
unsigned
long
) addr) != 0)
212
break
;
213
ret = 0;
214
if
(
access_process_vm
(child, (
u64
)addrOthers, &data,
215
sizeof
(data), 1) ==
sizeof
(data))
216
break
;
217
ret = -
EIO
;
218
break
;
219
}
220
221
case
PTRACE_POKEUSR
: {
222
struct
pt_regs
*
regs
;
223
ret = 0;
224
regs =
task_pt_regs
(child);
225
226
switch
(addr) {
227
case
0 ... 31:
228
regs->
regs
[
addr
] =
data
;
229
break
;
230
case
FPR_BASE
...
FPR_BASE
+ 31: {
231
fpureg_t
*fregs = get_fpu_regs(child);
232
233
if
(!
tsk_used_math
(child)) {
234
/* FP not yet used */
235
memset
(&child->
thread
.fpu, ~0,
236
sizeof
(child->
thread
.fpu));
237
child->
thread
.fpu.fcr31 = 0;
238
}
239
/*
240
* The odd registers are actually the high order bits
241
* of the values stored in the even registers - unless
242
* we're using r2k_switch.S.
243
*/
244
if
(addr & 1) {
245
fregs[(addr & ~1) -
FPR_BASE
] &= 0xffffffff;
246
fregs[(addr & ~1) -
FPR_BASE
] |= ((
unsigned
long
long
)
data
) << 32;
247
}
else
{
248
fregs[addr -
FPR_BASE
] &= ~0xffffffff
LL
;
249
/* Must cast, lest sign extension fill upper
250
bits! */
251
fregs[addr -
FPR_BASE
] |= (
unsigned
int
)data;
252
}
253
break
;
254
}
255
case
PC
:
256
regs->
cp0_epc
=
data
;
257
break
;
258
case
MMHI
:
259
regs->
hi
=
data
;
260
break
;
261
case
MMLO
:
262
regs->
lo
=
data
;
263
break
;
264
case
FPC_CSR
:
265
child->
thread
.fpu.fcr31 =
data
;
266
break
;
267
case
DSP_BASE
...
DSP_BASE
+ 5: {
268
dspreg_t
*dregs;
269
270
if
(!
cpu_has_dsp
) {
271
ret = -
EIO
;
272
break
;
273
}
274
275
dregs =
__get_dsp_regs
(child);
276
dregs[addr -
DSP_BASE
] =
data
;
277
break
;
278
}
279
case
DSP_CONTROL
:
280
if
(!
cpu_has_dsp
) {
281
ret = -
EIO
;
282
break
;
283
}
284
child->
thread
.dsp.dspcontrol =
data
;
285
break
;
286
default
:
287
/* The rest are not allowed. */
288
ret = -
EIO
;
289
break
;
290
}
291
break
;
292
}
293
294
case
PTRACE_GETREGS
:
295
ret =
ptrace_getregs
(child, (
__s64
__user
*) (
__u64
) data);
296
break
;
297
298
case
PTRACE_SETREGS
:
299
ret =
ptrace_setregs
(child, (
__s64
__user
*) (
__u64
) data);
300
break
;
301
302
case
PTRACE_GETFPREGS
:
303
ret =
ptrace_getfpregs
(child, (
__u32
__user
*) (
__u64
) data);
304
break
;
305
306
case
PTRACE_SETFPREGS
:
307
ret =
ptrace_setfpregs
(child, (
__u32
__user
*) (
__u64
) data);
308
break
;
309
310
case
PTRACE_GET_THREAD_AREA
:
311
ret =
put_user
(
task_thread_info
(child)->tp_value,
312
(
unsigned
int
__user
*) (
unsigned
long
) data);
313
break
;
314
315
case
PTRACE_GET_THREAD_AREA_3264
:
316
ret =
put_user
(
task_thread_info
(child)->tp_value,
317
(
unsigned
long
__user
*) (
unsigned
long
) data);
318
break
;
319
320
case
PTRACE_GET_WATCH_REGS
:
321
ret =
ptrace_get_watch_regs
(child,
322
(
struct
pt_watch_regs
__user
*) (
unsigned
long
) addr);
323
break
;
324
325
case
PTRACE_SET_WATCH_REGS
:
326
ret =
ptrace_set_watch_regs
(child,
327
(
struct
pt_watch_regs
__user
*) (
unsigned
long
) addr);
328
break
;
329
330
default
:
331
ret = compat_ptrace_request(child, request, addr, data);
332
break
;
333
}
334
out
:
335
return
ret
;
336
}
Generated on Thu Jan 10 2013 13:11:21 for Linux Kernel by
1.8.2