1 /**********************************************************************
4 Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
7 Jeff Dike (jdike@karaya.com) : Modified for integration into uml
8 **********************************************************************/
10 /* XXX This file shouldn't refer to CONFIG_* */
21 #include <sys/types.h>
22 #include <sys/ptrace.h>
23 #include <sys/ioctl.h>
24 #include <asm/unistd.h>
30 #include "user_util.h"
35 static int debugger_wait(debugger_state *debugger, int *status, int options,
36 int (*syscall)(debugger_state *debugger, pid_t child),
37 int (*normal_return)(debugger_state *debugger,
39 int (*wait_return)(debugger_state *debugger,
42 if(debugger->real_wait){
43 debugger->handle_trace = normal_return;
44 syscall_continue(debugger->pid);
45 debugger->real_wait = 0;
48 debugger->wait_status_ptr = status;
49 debugger->wait_options = options;
50 if((debugger->debugee != NULL) && debugger->debugee->event){
51 syscall_continue(debugger->pid);
52 wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
54 (*wait_return)(debugger, -1);
57 else if(debugger->wait_options & WNOHANG){
58 syscall_cancel(debugger->pid, 0);
59 debugger->handle_trace = syscall;
63 syscall_pause(debugger->pid);
64 debugger->handle_trace = wait_return;
65 debugger->waiting = 1;
71 * Handle debugger trap, i.e. syscall.
74 int debugger_syscall(debugger_state *debugger, pid_t child)
76 long arg1, arg2, arg3, arg4, arg5, result;
79 syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
84 /* execve never returns */
85 debugger->handle_trace = debugger_syscall;
89 if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
90 if(!debugger->debugee->in_context)
91 child = debugger->debugee->pid;
92 result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
94 syscall_cancel(debugger->pid, result);
95 debugger->handle_trace = debugger_syscall;
100 if(!debugger_wait(debugger, (int *) arg2, arg3,
101 debugger_syscall, debugger_normal_return,
107 if(!debugger->debugee->in_context)
108 child = debugger->debugee->pid;
109 if(arg1 == debugger->debugee->pid){
110 result = kill(child, arg2);
111 syscall_cancel(debugger->pid, result);
112 debugger->handle_trace = debugger_syscall;
115 else debugger->handle_trace = debugger_normal_return;
119 debugger->handle_trace = debugger_normal_return;
122 syscall_continue(debugger->pid);
126 /* Used by the tracing thread */
127 static debugger_state parent;
128 static int parent_syscall(debugger_state *debugger, int pid);
130 int init_parent_proxy(int pid)
132 parent = ((debugger_state) { .pid = pid,
134 .wait_status_ptr = NULL,
137 .expecting_child = 0,
138 .handle_trace = parent_syscall,
143 int parent_normal_return(debugger_state *debugger, pid_t unused)
145 debugger->handle_trace = parent_syscall;
146 syscall_continue(debugger->pid);
150 static int parent_syscall(debugger_state *debugger, int pid)
152 long arg1, arg2, arg3, arg4, arg5;
155 syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
157 if((syscall == __NR_waitpid) || (syscall == __NR_wait4)){
158 debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
159 parent_normal_return, parent_wait_return);
161 else ptrace(PTRACE_SYSCALL, pid, 0, 0);
165 int debugger_normal_return(debugger_state *debugger, pid_t unused)
167 debugger->handle_trace = debugger_syscall;
168 syscall_continue(debugger->pid);
172 void debugger_cancelled_return(debugger_state *debugger, int result)
174 debugger->handle_trace = debugger_syscall;
175 syscall_set_result(debugger->pid, result);
176 syscall_continue(debugger->pid);
179 /* Used by the tracing thread */
180 static debugger_state debugger;
181 static debugee_state debugee;
183 void init_proxy (pid_t debugger_pid, int stopped, int status)
185 debugger.pid = debugger_pid;
186 debugger.handle_trace = debugger_syscall;
187 debugger.debugee = &debugee;
188 debugger.waiting = 0;
189 debugger.real_wait = 0;
190 debugger.expecting_child = 0;
194 debugee.stopped = stopped;
198 debugee.wait_status = status;
199 debugee.in_context = 1;
202 int debugger_proxy(int status, int pid)
206 if(WIFSTOPPED(status)){
207 sig = WSTOPSIG(status);
209 ret = (*debugger.handle_trace)(&debugger, pid);
211 else if(sig == SIGCHLD){
212 if(debugger.expecting_child){
213 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
214 debugger.expecting_child = 0;
216 else if(debugger.waiting)
217 real_wait_return(&debugger);
219 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
220 debugger.real_wait = 1;
223 else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
225 else if(WIFEXITED(status)){
226 tracer_panic("debugger (pid %d) exited with status %d",
227 debugger.pid, WEXITSTATUS(status));
229 else if(WIFSIGNALED(status)){
230 tracer_panic("debugger (pid %d) exited with signal %d",
231 debugger.pid, WTERMSIG(status));
234 tracer_panic("proxy got unknown status (0x%x) on debugger "
235 "(pid %d)", status, debugger.pid);
240 void child_proxy(pid_t pid, int status)
243 debugee.wait_status = status;
245 if(WIFSTOPPED(status)){
247 debugger.expecting_child = 1;
248 kill(debugger.pid, SIGCHLD);
250 else if(WIFEXITED(status) || WIFSIGNALED(status)){
252 debugger.expecting_child = 1;
253 kill(debugger.pid, SIGCHLD);
255 else panic("proxy got unknown status (0x%x) on child (pid %d)",
259 void debugger_parent_signal(int status, int pid)
263 if(WIFSTOPPED(status)){
264 sig = WSTOPSIG(status);
265 if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
266 else ptrace(PTRACE_SYSCALL, pid, 0, sig);
270 void fake_child_exit(void)
274 child_proxy(1, W_EXITCODE(0, 0));
275 while(debugger.waiting == 1){
276 pid = waitpid(debugger.pid, &status, WUNTRACED);
277 if(pid != debugger.pid){
278 printk("fake_child_exit - waitpid failed, "
279 "errno = %d\n", errno);
282 debugger_proxy(status, debugger.pid);
284 pid = waitpid(debugger.pid, &status, WUNTRACED);
285 if(pid != debugger.pid){
286 printk("fake_child_exit - waitpid failed, "
287 "errno = %d\n", errno);
290 if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
291 printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
295 char gdb_init_string[] =
299 handle SIGWINCH nostop noprint pass
302 int start_debugger(char *prog, int startup, int stop, int *fd_out)
306 slave = open_gdb_chan();
307 if((child = fork()) == 0){
308 char *tempname = NULL;
311 if(setsid() < 0) perror("setsid");
312 if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
313 (dup2(slave, 2) < 0)){
314 printk("start_debugger : dup2 failed, errno = %d\n",
318 if(ioctl(0, TIOCSCTTY, 0) < 0){
319 printk("start_debugger : TIOCSCTTY failed, "
320 "errno = %d\n", errno);
323 if(tcsetpgrp (1, os_getpid()) < 0){
324 printk("start_debugger : tcsetpgrp failed, "
325 "errno = %d\n", errno);
330 if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){
331 printk("start_debugger : make_tempfile failed, errno = %d\n",
335 write(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
338 write(fd, "b start_kernel\n",
339 strlen("b start_kernel\n"));
341 write(fd, "c\n", strlen("c\n"));
343 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
344 printk("start_debugger : PTRACE_TRACEME failed, "
345 "errno = %d\n", errno);
348 execlp("gdb", "gdb", "--command", tempname, prog, NULL);
349 printk("start_debugger : exec of gdb failed, errno = %d\n",
353 printk("start_debugger : fork for gdb failed, errno = %d\n",
362 * Overrides for Emacs so that we follow Linus's tabbing style.
363 * Emacs will notice this stuff at the end of the file and automatically
364 * adjust the settings for this buffer only. This must remain at the end
366 * ---------------------------------------------------------------------------
368 * c-file-style: "linux"