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_* */
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <asm/unistd.h>
23 #include "ptrace_user.h"
29 #include "user_util.h"
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,
38 int (*wait_return)(debugger_state *debugger,
41 if(debugger->real_wait){
42 debugger->handle_trace = normal_return;
43 syscall_continue(debugger->pid);
44 debugger->real_wait = 0;
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,
53 (*wait_return)(debugger, -1);
56 else if(debugger->wait_options & WNOHANG){
57 syscall_cancel(debugger->pid, 0);
58 debugger->handle_trace = syscall;
62 syscall_pause(debugger->pid);
63 debugger->handle_trace = wait_return;
64 debugger->waiting = 1;
70 * Handle debugger trap, i.e. syscall.
73 int debugger_syscall(debugger_state *debugger, pid_t child)
75 long arg1, arg2, arg3, arg4, arg5, result;
78 syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
83 /* execve never returns */
84 debugger->handle_trace = debugger_syscall;
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,
93 syscall_cancel(debugger->pid, result);
94 debugger->handle_trace = debugger_syscall;
101 if(!debugger_wait(debugger, (int *) arg2, arg3,
102 debugger_syscall, debugger_normal_return,
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;
116 else debugger->handle_trace = debugger_normal_return;
120 debugger->handle_trace = debugger_normal_return;
123 syscall_continue(debugger->pid);
127 /* Used by the tracing thread */
128 static debugger_state parent;
129 static int parent_syscall(debugger_state *debugger, int pid);
131 int init_parent_proxy(int pid)
133 parent = ((debugger_state) { .pid = pid,
135 .wait_status_ptr = NULL,
138 .expecting_child = 0,
139 .handle_trace = parent_syscall,
144 int parent_normal_return(debugger_state *debugger, pid_t unused)
146 debugger->handle_trace = parent_syscall;
147 syscall_continue(debugger->pid);
151 static int parent_syscall(debugger_state *debugger, int pid)
153 long arg1, arg2, arg3, arg4, arg5;
156 syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
158 if((syscall == __NR_wait4)
160 || (syscall == __NR_waitpid)
163 debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
164 parent_normal_return, parent_wait_return);
166 else ptrace(PTRACE_SYSCALL, pid, 0, 0);
170 int debugger_normal_return(debugger_state *debugger, pid_t unused)
172 debugger->handle_trace = debugger_syscall;
173 syscall_continue(debugger->pid);
177 void debugger_cancelled_return(debugger_state *debugger, int result)
179 debugger->handle_trace = debugger_syscall;
180 syscall_set_result(debugger->pid, result);
181 syscall_continue(debugger->pid);
184 /* Used by the tracing thread */
185 static debugger_state debugger;
186 static debugee_state debugee;
188 void init_proxy (pid_t debugger_pid, int stopped, int status)
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;
199 debugee.stopped = stopped;
203 debugee.wait_status = status;
204 debugee.in_context = 1;
207 int debugger_proxy(int status, int pid)
211 if(WIFSTOPPED(status)){
212 sig = WSTOPSIG(status);
214 ret = (*debugger.handle_trace)(&debugger, pid);
216 else if(sig == SIGCHLD){
217 if(debugger.expecting_child){
218 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
219 debugger.expecting_child = 0;
221 else if(debugger.waiting)
222 real_wait_return(&debugger);
224 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
225 debugger.real_wait = 1;
228 else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
230 else if(WIFEXITED(status)){
231 tracer_panic("debugger (pid %d) exited with status %d",
232 debugger.pid, WEXITSTATUS(status));
234 else if(WIFSIGNALED(status)){
235 tracer_panic("debugger (pid %d) exited with signal %d",
236 debugger.pid, WTERMSIG(status));
239 tracer_panic("proxy got unknown status (0x%x) on debugger "
240 "(pid %d)", status, debugger.pid);
245 void child_proxy(pid_t pid, int status)
248 debugee.wait_status = status;
250 if(WIFSTOPPED(status)){
252 debugger.expecting_child = 1;
253 kill(debugger.pid, SIGCHLD);
255 else if(WIFEXITED(status) || WIFSIGNALED(status)){
257 debugger.expecting_child = 1;
258 kill(debugger.pid, SIGCHLD);
260 else panic("proxy got unknown status (0x%x) on child (pid %d)",
264 void debugger_parent_signal(int status, int pid)
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);
275 void fake_child_exit(void)
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);
287 debugger_proxy(status, debugger.pid);
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);
295 if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
296 printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
300 char gdb_init_string[] =
304 handle SIGWINCH nostop noprint pass \n\
307 int start_debugger(char *prog, int startup, int stop, int *fd_out)
311 slave = open_gdb_chan();
314 char *tempname = NULL;
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",
324 if(ioctl(0, TIOCSCTTY, 0) < 0){
325 printk("start_debugger : TIOCSCTTY failed, "
326 "errno = %d\n", errno);
329 if(tcsetpgrp (1, os_getpid()) < 0){
330 printk("start_debugger : tcsetpgrp failed, "
331 "errno = %d\n", errno);
336 fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
338 printk("start_debugger : make_tempfile failed,"
342 os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
345 os_write_file(fd, "b start_kernel\n",
346 strlen("b start_kernel\n"));
348 os_write_file(fd, "c\n", strlen("c\n"));
350 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
351 printk("start_debugger : PTRACE_TRACEME failed, "
352 "errno = %d\n", errno);
355 execlp("gdb", "gdb", "--command", tempname, prog, NULL);
356 printk("start_debugger : exec of gdb failed, errno = %d\n",
360 printk("start_debugger : fork for gdb failed, errno = %d\n",
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
373 * ---------------------------------------------------------------------------
375 * c-file-style: "linux"