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