]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/um/kernel/tt/ptproxy/proxy.c
Linux-2.6.12-rc2
[mirror_ubuntu-artful-kernel.git] / arch / um / kernel / tt / ptproxy / proxy.c
1 /**********************************************************************
2 proxy.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 /* XXX This file shouldn't refer to CONFIG_* */
11
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <signal.h>
17 #include <string.h>
18 #include <termios.h>
19 #include <sys/wait.h>
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <asm/unistd.h>
23 #include "ptrace_user.h"
24
25 #include "ptproxy.h"
26 #include "sysdep.h"
27 #include "wait.h"
28
29 #include "user_util.h"
30 #include "user.h"
31 #include "os.h"
32 #include "tempfile.h"
33
34 static int debugger_wait(debugger_state *debugger, int *status, int options,
35 int (*syscall)(debugger_state *debugger, pid_t child),
36 int (*normal_return)(debugger_state *debugger,
37 pid_t unused),
38 int (*wait_return)(debugger_state *debugger,
39 pid_t unused))
40 {
41 if(debugger->real_wait){
42 debugger->handle_trace = normal_return;
43 syscall_continue(debugger->pid);
44 debugger->real_wait = 0;
45 return(1);
46 }
47 debugger->wait_status_ptr = status;
48 debugger->wait_options = options;
49 if((debugger->debugee != NULL) && debugger->debugee->event){
50 syscall_continue(debugger->pid);
51 wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
52 NULL);
53 (*wait_return)(debugger, -1);
54 return(0);
55 }
56 else if(debugger->wait_options & WNOHANG){
57 syscall_cancel(debugger->pid, 0);
58 debugger->handle_trace = syscall;
59 return(0);
60 }
61 else {
62 syscall_pause(debugger->pid);
63 debugger->handle_trace = wait_return;
64 debugger->waiting = 1;
65 }
66 return(1);
67 }
68
69 /*
70 * Handle debugger trap, i.e. syscall.
71 */
72
73 int debugger_syscall(debugger_state *debugger, pid_t child)
74 {
75 long arg1, arg2, arg3, arg4, arg5, result;
76 int syscall, ret = 0;
77
78 syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
79 &arg5);
80
81 switch(syscall){
82 case __NR_execve:
83 /* execve never returns */
84 debugger->handle_trace = debugger_syscall;
85 break;
86
87 case __NR_ptrace:
88 if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
89 if(!debugger->debugee->in_context)
90 child = debugger->debugee->pid;
91 result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
92 &ret);
93 syscall_cancel(debugger->pid, result);
94 debugger->handle_trace = debugger_syscall;
95 return(ret);
96
97 #ifdef __NR_waitpid
98 case __NR_waitpid:
99 #endif
100 case __NR_wait4:
101 if(!debugger_wait(debugger, (int *) arg2, arg3,
102 debugger_syscall, debugger_normal_return,
103 proxy_wait_return))
104 return(0);
105 break;
106
107 case __NR_kill:
108 if(!debugger->debugee->in_context)
109 child = debugger->debugee->pid;
110 if(arg1 == debugger->debugee->pid){
111 result = kill(child, arg2);
112 syscall_cancel(debugger->pid, result);
113 debugger->handle_trace = debugger_syscall;
114 return(0);
115 }
116 else debugger->handle_trace = debugger_normal_return;
117 break;
118
119 default:
120 debugger->handle_trace = debugger_normal_return;
121 }
122
123 syscall_continue(debugger->pid);
124 return(0);
125 }
126
127 /* Used by the tracing thread */
128 static debugger_state parent;
129 static int parent_syscall(debugger_state *debugger, int pid);
130
131 int init_parent_proxy(int pid)
132 {
133 parent = ((debugger_state) { .pid = pid,
134 .wait_options = 0,
135 .wait_status_ptr = NULL,
136 .waiting = 0,
137 .real_wait = 0,
138 .expecting_child = 0,
139 .handle_trace = parent_syscall,
140 .debugee = NULL } );
141 return(0);
142 }
143
144 int parent_normal_return(debugger_state *debugger, pid_t unused)
145 {
146 debugger->handle_trace = parent_syscall;
147 syscall_continue(debugger->pid);
148 return(0);
149 }
150
151 static int parent_syscall(debugger_state *debugger, int pid)
152 {
153 long arg1, arg2, arg3, arg4, arg5;
154 int syscall;
155
156 syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
157
158 if((syscall == __NR_wait4)
159 #ifdef __NR_waitpid
160 || (syscall == __NR_waitpid)
161 #endif
162 ){
163 debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
164 parent_normal_return, parent_wait_return);
165 }
166 else ptrace(PTRACE_SYSCALL, pid, 0, 0);
167 return(0);
168 }
169
170 int debugger_normal_return(debugger_state *debugger, pid_t unused)
171 {
172 debugger->handle_trace = debugger_syscall;
173 syscall_continue(debugger->pid);
174 return(0);
175 }
176
177 void debugger_cancelled_return(debugger_state *debugger, int result)
178 {
179 debugger->handle_trace = debugger_syscall;
180 syscall_set_result(debugger->pid, result);
181 syscall_continue(debugger->pid);
182 }
183
184 /* Used by the tracing thread */
185 static debugger_state debugger;
186 static debugee_state debugee;
187
188 void init_proxy (pid_t debugger_pid, int stopped, int status)
189 {
190 debugger.pid = debugger_pid;
191 debugger.handle_trace = debugger_syscall;
192 debugger.debugee = &debugee;
193 debugger.waiting = 0;
194 debugger.real_wait = 0;
195 debugger.expecting_child = 0;
196
197 debugee.pid = 0;
198 debugee.traced = 0;
199 debugee.stopped = stopped;
200 debugee.event = 0;
201 debugee.zombie = 0;
202 debugee.died = 0;
203 debugee.wait_status = status;
204 debugee.in_context = 1;
205 }
206
207 int debugger_proxy(int status, int pid)
208 {
209 int ret = 0, sig;
210
211 if(WIFSTOPPED(status)){
212 sig = WSTOPSIG(status);
213 if (sig == SIGTRAP)
214 ret = (*debugger.handle_trace)(&debugger, pid);
215
216 else if(sig == SIGCHLD){
217 if(debugger.expecting_child){
218 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
219 debugger.expecting_child = 0;
220 }
221 else if(debugger.waiting)
222 real_wait_return(&debugger);
223 else {
224 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
225 debugger.real_wait = 1;
226 }
227 }
228 else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
229 }
230 else if(WIFEXITED(status)){
231 tracer_panic("debugger (pid %d) exited with status %d",
232 debugger.pid, WEXITSTATUS(status));
233 }
234 else if(WIFSIGNALED(status)){
235 tracer_panic("debugger (pid %d) exited with signal %d",
236 debugger.pid, WTERMSIG(status));
237 }
238 else {
239 tracer_panic("proxy got unknown status (0x%x) on debugger "
240 "(pid %d)", status, debugger.pid);
241 }
242 return(ret);
243 }
244
245 void child_proxy(pid_t pid, int status)
246 {
247 debugee.event = 1;
248 debugee.wait_status = status;
249
250 if(WIFSTOPPED(status)){
251 debugee.stopped = 1;
252 debugger.expecting_child = 1;
253 kill(debugger.pid, SIGCHLD);
254 }
255 else if(WIFEXITED(status) || WIFSIGNALED(status)){
256 debugee.zombie = 1;
257 debugger.expecting_child = 1;
258 kill(debugger.pid, SIGCHLD);
259 }
260 else panic("proxy got unknown status (0x%x) on child (pid %d)",
261 status, pid);
262 }
263
264 void debugger_parent_signal(int status, int pid)
265 {
266 int sig;
267
268 if(WIFSTOPPED(status)){
269 sig = WSTOPSIG(status);
270 if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
271 else ptrace(PTRACE_SYSCALL, pid, 0, sig);
272 }
273 }
274
275 void fake_child_exit(void)
276 {
277 int status, pid;
278
279 child_proxy(1, W_EXITCODE(0, 0));
280 while(debugger.waiting == 1){
281 CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
282 if(pid != debugger.pid){
283 printk("fake_child_exit - waitpid failed, "
284 "errno = %d\n", errno);
285 return;
286 }
287 debugger_proxy(status, debugger.pid);
288 }
289 CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
290 if(pid != debugger.pid){
291 printk("fake_child_exit - waitpid failed, "
292 "errno = %d\n", errno);
293 return;
294 }
295 if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
296 printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
297 errno);
298 }
299
300 char gdb_init_string[] =
301 "att 1 \n\
302 b panic \n\
303 b stop \n\
304 handle SIGWINCH nostop noprint pass \n\
305 ";
306
307 int start_debugger(char *prog, int startup, int stop, int *fd_out)
308 {
309 int slave, child;
310
311 slave = open_gdb_chan();
312 child = fork();
313 if(child == 0){
314 char *tempname = NULL;
315 int fd;
316
317 if(setsid() < 0) perror("setsid");
318 if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
319 (dup2(slave, 2) < 0)){
320 printk("start_debugger : dup2 failed, errno = %d\n",
321 errno);
322 exit(1);
323 }
324 if(ioctl(0, TIOCSCTTY, 0) < 0){
325 printk("start_debugger : TIOCSCTTY failed, "
326 "errno = %d\n", errno);
327 exit(1);
328 }
329 if(tcsetpgrp (1, os_getpid()) < 0){
330 printk("start_debugger : tcsetpgrp failed, "
331 "errno = %d\n", errno);
332 #ifdef notdef
333 exit(1);
334 #endif
335 }
336 fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
337 if(fd < 0){
338 printk("start_debugger : make_tempfile failed,"
339 "err = %d\n", -fd);
340 exit(1);
341 }
342 os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
343 if(startup){
344 if(stop){
345 os_write_file(fd, "b start_kernel\n",
346 strlen("b start_kernel\n"));
347 }
348 os_write_file(fd, "c\n", strlen("c\n"));
349 }
350 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
351 printk("start_debugger : PTRACE_TRACEME failed, "
352 "errno = %d\n", errno);
353 exit(1);
354 }
355 execlp("gdb", "gdb", "--command", tempname, prog, NULL);
356 printk("start_debugger : exec of gdb failed, errno = %d\n",
357 errno);
358 }
359 if(child < 0){
360 printk("start_debugger : fork for gdb failed, errno = %d\n",
361 errno);
362 return(-1);
363 }
364 *fd_out = slave;
365 return(child);
366 }
367
368 /*
369 * Overrides for Emacs so that we follow Linus's tabbing style.
370 * Emacs will notice this stuff at the end of the file and automatically
371 * adjust the settings for this buffer only. This must remain at the end
372 * of the file.
373 * ---------------------------------------------------------------------------
374 * Local variables:
375 * c-file-style: "linux"
376 * End:
377 */