]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /********************************************************************** |
2 | ptrace.c | |
3 | ||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | |
5 | terms and conditions. | |
6 | ||
7 | Jeff Dike (jdike@karaya.com) : Modified for integration into uml | |
8 | **********************************************************************/ | |
9 | ||
10 | #include <errno.h> | |
11 | #include <unistd.h> | |
12 | #include <signal.h> | |
13 | #include <sys/types.h> | |
14 | #include <sys/time.h> | |
15 | #include <sys/wait.h> | |
16 | ||
17 | #include "ptproxy.h" | |
18 | #include "debug.h" | |
1da177e4 LT |
19 | #include "kern_util.h" |
20 | #include "ptrace_user.h" | |
21 | #include "tt.h" | |
4fef0c10 | 22 | #include "os.h" |
1da177e4 LT |
23 | |
24 | long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, | |
25 | long arg3, long arg4, pid_t child, int *ret) | |
26 | { | |
27 | sigset_t relay; | |
28 | long result; | |
29 | int status; | |
30 | ||
31 | *ret = 0; | |
32 | if(debugger->debugee->died) return(-ESRCH); | |
33 | ||
34 | switch(arg1){ | |
35 | case PTRACE_ATTACH: | |
36 | if(debugger->debugee->traced) return(-EPERM); | |
37 | ||
38 | debugger->debugee->pid = arg2; | |
39 | debugger->debugee->traced = 1; | |
40 | ||
41 | if(is_valid_pid(arg2) && (arg2 != child)){ | |
42 | debugger->debugee->in_context = 0; | |
43 | kill(arg2, SIGSTOP); | |
44 | debugger->debugee->event = 1; | |
45 | debugger->debugee->wait_status = W_STOPCODE(SIGSTOP); | |
46 | } | |
47 | else { | |
48 | debugger->debugee->in_context = 1; | |
49 | if(debugger->debugee->stopped) | |
50 | child_proxy(child, W_STOPCODE(SIGSTOP)); | |
51 | else kill(child, SIGSTOP); | |
52 | } | |
53 | ||
54 | return(0); | |
55 | ||
56 | case PTRACE_DETACH: | |
57 | if(!debugger->debugee->traced) return(-EPERM); | |
58 | ||
59 | debugger->debugee->traced = 0; | |
60 | debugger->debugee->pid = 0; | |
61 | if(!debugger->debugee->in_context) | |
62 | kill(child, SIGCONT); | |
63 | ||
64 | return(0); | |
65 | ||
66 | case PTRACE_CONT: | |
67 | if(!debugger->debugee->in_context) return(-EPERM); | |
68 | *ret = PTRACE_CONT; | |
69 | return(ptrace(PTRACE_CONT, child, arg3, arg4)); | |
70 | ||
71 | #ifdef UM_HAVE_GETFPREGS | |
72 | case PTRACE_GETFPREGS: | |
73 | { | |
74 | long regs[FP_FRAME_SIZE]; | |
75 | int i, result; | |
76 | ||
77 | result = ptrace(PTRACE_GETFPREGS, child, 0, regs); | |
78 | if(result == -1) return(-errno); | |
79 | ||
80 | for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | |
81 | ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, | |
82 | regs[i]); | |
83 | return(result); | |
84 | } | |
85 | #endif | |
86 | ||
87 | #ifdef UM_HAVE_GETFPXREGS | |
88 | case PTRACE_GETFPXREGS: | |
89 | { | |
90 | long regs[FPX_FRAME_SIZE]; | |
91 | int i, result; | |
92 | ||
93 | result = ptrace(PTRACE_GETFPXREGS, child, 0, regs); | |
94 | if(result == -1) return(-errno); | |
95 | ||
96 | for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | |
97 | ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, | |
98 | regs[i]); | |
99 | return(result); | |
100 | } | |
101 | #endif | |
102 | ||
103 | #ifdef UM_HAVE_GETREGS | |
104 | case PTRACE_GETREGS: | |
105 | { | |
106 | long regs[FRAME_SIZE]; | |
107 | int i, result; | |
108 | ||
109 | result = ptrace(PTRACE_GETREGS, child, 0, regs); | |
110 | if(result == -1) return(-errno); | |
111 | ||
112 | for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | |
113 | ptrace (PTRACE_POKEDATA, debugger->pid, | |
114 | arg4 + 4 * i, regs[i]); | |
115 | return(result); | |
116 | } | |
117 | break; | |
118 | #endif | |
119 | ||
120 | case PTRACE_KILL: | |
121 | result = ptrace(PTRACE_KILL, child, arg3, arg4); | |
122 | if(result == -1) return(-errno); | |
123 | ||
124 | return(result); | |
125 | ||
126 | case PTRACE_PEEKDATA: | |
127 | case PTRACE_PEEKTEXT: | |
128 | case PTRACE_PEEKUSR: | |
129 | /* The value being read out could be -1, so we have to | |
130 | * check errno to see if there's an error, and zero it | |
131 | * beforehand so we're not faked out by an old error | |
132 | */ | |
133 | ||
134 | errno = 0; | |
135 | result = ptrace(arg1, child, arg3, 0); | |
136 | if((result == -1) && (errno != 0)) return(-errno); | |
137 | ||
138 | result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result); | |
139 | if(result == -1) return(-errno); | |
140 | ||
141 | return(result); | |
142 | ||
143 | case PTRACE_POKEDATA: | |
144 | case PTRACE_POKETEXT: | |
145 | case PTRACE_POKEUSR: | |
146 | result = ptrace(arg1, child, arg3, arg4); | |
147 | if(result == -1) return(-errno); | |
148 | ||
149 | if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4); | |
150 | return(result); | |
151 | ||
152 | #ifdef UM_HAVE_SETFPREGS | |
153 | case PTRACE_SETFPREGS: | |
154 | { | |
155 | long regs[FP_FRAME_SIZE]; | |
156 | int i; | |
157 | ||
158 | for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | |
159 | regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, | |
160 | arg4 + 4 * i, 0); | |
161 | result = ptrace(PTRACE_SETFPREGS, child, 0, regs); | |
162 | if(result == -1) return(-errno); | |
163 | ||
164 | return(result); | |
165 | } | |
166 | #endif | |
167 | ||
168 | #ifdef UM_HAVE_SETFPXREGS | |
169 | case PTRACE_SETFPXREGS: | |
170 | { | |
171 | long regs[FPX_FRAME_SIZE]; | |
172 | int i; | |
173 | ||
174 | for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | |
175 | regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, | |
176 | arg4 + 4 * i, 0); | |
177 | result = ptrace(PTRACE_SETFPXREGS, child, 0, regs); | |
178 | if(result == -1) return(-errno); | |
179 | ||
180 | return(result); | |
181 | } | |
182 | #endif | |
183 | ||
184 | #ifdef UM_HAVE_SETREGS | |
185 | case PTRACE_SETREGS: | |
186 | { | |
187 | long regs[FRAME_SIZE]; | |
188 | int i; | |
189 | ||
190 | for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | |
191 | regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid, | |
192 | arg4 + 4 * i, 0); | |
193 | result = ptrace(PTRACE_SETREGS, child, 0, regs); | |
194 | if(result == -1) return(-errno); | |
195 | ||
196 | return(result); | |
197 | } | |
198 | #endif | |
199 | ||
200 | case PTRACE_SINGLESTEP: | |
201 | if(!debugger->debugee->in_context) return(-EPERM); | |
202 | sigemptyset(&relay); | |
203 | sigaddset(&relay, SIGSEGV); | |
204 | sigaddset(&relay, SIGILL); | |
205 | sigaddset(&relay, SIGBUS); | |
206 | result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4); | |
207 | if(result == -1) return(-errno); | |
208 | ||
209 | status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP, | |
210 | &relay); | |
211 | child_proxy(child, status); | |
212 | return(result); | |
213 | ||
214 | case PTRACE_SYSCALL: | |
215 | if(!debugger->debugee->in_context) return(-EPERM); | |
216 | result = ptrace(PTRACE_SYSCALL, child, arg3, arg4); | |
217 | if(result == -1) return(-errno); | |
218 | ||
219 | *ret = PTRACE_SYSCALL; | |
220 | return(result); | |
221 | ||
222 | case PTRACE_TRACEME: | |
223 | default: | |
224 | return(-EINVAL); | |
225 | } | |
226 | } | |
227 | ||
228 | /* | |
229 | * Overrides for Emacs so that we follow Linus's tabbing style. | |
230 | * Emacs will notice this stuff at the end of the file and automatically | |
231 | * adjust the settings for this buffer only. This must remain at the end | |
232 | * of the file. | |
233 | * --------------------------------------------------------------------------- | |
234 | * Local variables: | |
235 | * c-file-style: "linux" | |
236 | * End: | |
237 | */ |