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"