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
cris
arch-v10
kernel
ptrace.c
Go to the documentation of this file.
1
/*
2
* Copyright (C) 2000-2003, Axis Communications AB.
3
*/
4
5
#include <linux/kernel.h>
6
#include <linux/sched.h>
7
#include <
linux/mm.h
>
8
#include <
linux/smp.h
>
9
#include <linux/errno.h>
10
#include <linux/ptrace.h>
11
#include <
linux/user.h
>
12
#include <linux/signal.h>
13
#include <
linux/security.h
>
14
15
#include <asm/uaccess.h>
16
#include <asm/page.h>
17
#include <asm/pgtable.h>
18
#include <asm/processor.h>
19
20
/*
21
* Determines which bits in DCCR the user has access to.
22
* 1 = access, 0 = no access.
23
*/
24
#define DCCR_MASK 0x0000001f
/* XNZVC */
25
26
/*
27
* Get contents of register REGNO in task TASK.
28
*/
29
inline
long
get_reg
(
struct
task_struct
*
task
,
unsigned
int
regno)
30
{
31
/* USP is a special case, it's not in the pt_regs struct but
32
* in the tasks thread struct
33
*/
34
35
if
(regno ==
PT_USP
)
36
return
task->
thread
.usp;
37
else
if
(regno <
PT_MAX
)
38
return
((
unsigned
long
*)
task_pt_regs
(task))[regno];
39
else
40
return
0;
41
}
42
43
/*
44
* Write contents of register REGNO in task TASK.
45
*/
46
inline
int
put_reg
(
struct
task_struct
*
task
,
unsigned
int
regno,
47
unsigned
long
data
)
48
{
49
if
(regno ==
PT_USP
)
50
task->
thread
.usp =
data
;
51
else
if
(regno <
PT_MAX
)
52
((
unsigned
long
*)
task_pt_regs
(task))[regno] = data;
53
else
54
return
-1;
55
return
0;
56
}
57
58
/*
59
* Called by kernel/ptrace.c when detaching.
60
*
61
* Make sure the single step bit is not set.
62
*/
63
void
64
ptrace_disable
(
struct
task_struct
*
child
)
65
{
66
/* Todo - pending singlesteps? */
67
clear_tsk_thread_flag(child,
TIF_SYSCALL_TRACE
);
68
}
69
70
/*
71
* Note that this implementation of ptrace behaves differently from vanilla
72
* ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT,
73
* PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
74
* ignored. Instead, the data variable is expected to point at a location
75
* (in user space) where the result of the ptrace call is written (instead of
76
* being returned).
77
*/
78
long
arch_ptrace
(
struct
task_struct
*
child
,
long
request
,
79
unsigned
long
addr
,
unsigned
long
data
)
80
{
81
int
ret
;
82
unsigned
int
regno = addr >> 2;
83
unsigned
long
__user
*datap = (
unsigned
long
__user
*)data;
84
85
switch
(request) {
86
/* Read word at location address. */
87
case
PTRACE_PEEKTEXT
:
88
case
PTRACE_PEEKDATA
:
89
ret =
generic_ptrace_peekdata
(child, addr, data);
90
break
;
91
92
/* Read the word at location address in the USER area. */
93
case
PTRACE_PEEKUSR
: {
94
unsigned
long
tmp
;
95
96
ret = -
EIO
;
97
if
((addr & 3) || regno >
PT_MAX
)
98
break
;
99
100
tmp =
get_reg
(child, regno);
101
ret =
put_user
(tmp, datap);
102
break
;
103
}
104
105
/* Write the word at location address. */
106
case
PTRACE_POKETEXT
:
107
case
PTRACE_POKEDATA
:
108
ret =
generic_ptrace_pokedata
(child, addr, data);
109
break
;
110
111
/* Write the word at location address in the USER area. */
112
case
PTRACE_POKEUSR
:
113
ret = -
EIO
;
114
if
((addr & 3) || regno >
PT_MAX
)
115
break
;
116
117
if
(regno ==
PT_DCCR
) {
118
/* don't allow the tracing process to change stuff like
119
* interrupt enable, kernel/user bit, dma enables etc.
120
*/
121
data &=
DCCR_MASK
;
122
data |=
get_reg
(child,
PT_DCCR
) & ~
DCCR_MASK
;
123
}
124
if
(
put_reg
(child, regno, data))
125
break
;
126
ret = 0;
127
break
;
128
129
/* Get all GP registers from the child. */
130
case
PTRACE_GETREGS
: {
131
int
i
;
132
unsigned
long
tmp
;
133
134
ret = 0;
135
for
(i = 0; i <=
PT_MAX
; i++) {
136
tmp =
get_reg
(child, i);
137
138
if
(
put_user
(tmp, datap)) {
139
ret = -
EFAULT
;
140
break
;
141
}
142
143
datap++;
144
}
145
146
break
;
147
}
148
149
/* Set all GP registers in the child. */
150
case
PTRACE_SETREGS
: {
151
int
i
;
152
unsigned
long
tmp
;
153
154
ret = 0;
155
for
(i = 0; i <=
PT_MAX
; i++) {
156
if
(
get_user
(tmp, datap)) {
157
ret = -
EFAULT
;
158
break
;
159
}
160
161
if
(i ==
PT_DCCR
) {
162
tmp &=
DCCR_MASK
;
163
tmp |=
get_reg
(child,
PT_DCCR
) & ~
DCCR_MASK
;
164
}
165
166
put_reg
(child, i, tmp);
167
datap++;
168
}
169
170
break
;
171
}
172
173
default
:
174
ret =
ptrace_request
(child, request, addr, data);
175
break
;
176
}
177
178
return
ret
;
179
}
180
181
void
do_syscall_trace
(
void
)
182
{
183
if
(!test_thread_flag(
TIF_SYSCALL_TRACE
))
184
return
;
185
186
if
(!(
current
->ptrace &
PT_PTRACED
))
187
return
;
188
189
/* the 0x80 provides a way for the tracing parent to distinguish
190
between a syscall stop and SIGTRAP delivery */
191
ptrace_notify
(
SIGTRAP
| ((
current
->ptrace &
PT_TRACESYSGOOD
)
192
? 0x80 : 0));
193
194
/*
195
* This isn't the same as continuing with a signal, but it will do for
196
* normal use.
197
*/
198
if
(
current
->exit_code) {
199
send_sig
(
current
->exit_code,
current
, 1);
200
current
->exit_code = 0;
201
}
202
}
Generated on Thu Jan 10 2013 12:52:31 for Linux Kernel by
1.8.2