[PATCH] uml: remove syscall debugging
[deliverable/linux.git] / arch / um / kernel / tt / tracer.c
CommitLineData
1da177e4
LT
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdarg.h>
9#include <unistd.h>
10#include <signal.h>
11#include <errno.h>
12#include <sched.h>
13#include <string.h>
14#include <sys/mman.h>
15#include <sys/time.h>
16#include <sys/wait.h>
17#include "user.h"
18#include "sysdep/ptrace.h"
19#include "sigcontext.h"
20#include "sysdep/sigcontext.h"
21#include "os.h"
1da177e4
LT
22#include "user_util.h"
23#include "mem_user.h"
24#include "process.h"
25#include "kern_util.h"
26#include "chan_user.h"
27#include "ptrace_user.h"
cd2ee4a3 28#include "irq_user.h"
1da177e4
LT
29#include "mode.h"
30#include "tt.h"
31
32static int tracer_winch[2];
33
34int is_tracer_winch(int pid, int fd, void *data)
35{
cd2ee4a3 36 if(pid != os_getpgrp())
1da177e4
LT
37 return(0);
38
39 register_winch_irq(tracer_winch[0], fd, -1, data);
40 return(1);
41}
42
43static void tracer_winch_handler(int sig)
44{
45 int n;
46 char c = 1;
47
48 n = os_write_file(tracer_winch[1], &c, sizeof(c));
49 if(n != sizeof(c))
50 printk("tracer_winch_handler - write failed, err = %d\n", -n);
51}
52
53/* Called only by the tracing thread during initialization */
54
55static void setup_tracer_winch(void)
56{
57 int err;
58
59 err = os_pipe(tracer_winch, 1, 1);
60 if(err < 0){
61 printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
62 return;
63 }
64 signal(SIGWINCH, tracer_winch_handler);
65}
66
67void attach_process(int pid)
68{
69 if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
70 (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
71 tracer_panic("OP_FORK failed to attach pid");
72 wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
73 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
74 tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
75 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
76 tracer_panic("OP_FORK failed to continue process");
77}
78
79void tracer_panic(char *format, ...)
80{
81 va_list ap;
82
83 va_start(ap, format);
84 vprintf(format, ap);
85 va_end(ap);
86 printf("\n");
87 while(1) pause();
88}
89
90static void tracer_segv(int sig, struct sigcontext sc)
91{
c578455a
BS
92 struct faultinfo fi;
93 GET_FAULTINFO_FROM_SC(fi, &sc);
1da177e4 94 printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
c578455a 95 FAULT_ADDRESS(fi), SC_IP(&sc));
1da177e4
LT
96 while(1)
97 pause();
98}
99
100/* Changed early in boot, and then only read */
101int debug = 0;
102int debug_stop = 1;
103int debug_parent = 0;
104int honeypot = 0;
105
106static int signal_tramp(void *arg)
107{
108 int (*proc)(void *);
109
110 if(honeypot && munmap((void *) (host_task_size - 0x10000000),
111 0x10000000))
112 panic("Unmapping stack failed");
113 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
114 panic("ptrace PTRACE_TRACEME failed");
115 os_stop_process(os_getpid());
116 change_sig(SIGWINCH, 0);
117 signal(SIGUSR1, SIG_IGN);
118 change_sig(SIGCHLD, 0);
119 signal(SIGSEGV, (__sighandler_t) sig_handler);
120 set_cmdline("(idle thread)");
121 set_init_pid(os_getpid());
cd2ee4a3 122 init_irq_signals(0);
1da177e4
LT
123 proc = arg;
124 return((*proc)(NULL));
125}
126
127static void sleeping_process_signal(int pid, int sig)
128{
129 switch(sig){
130 /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
131 * right because the process must be in the kernel already.
132 */
133 case SIGCONT:
134 case SIGTSTP:
135 if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
136 tracer_panic("sleeping_process_signal : Failed to "
137 "continue pid %d, signal = %d, "
138 "errno = %d\n", pid, sig, errno);
139 break;
140
141 /* This happens when the debugger (e.g. strace) is doing system call
142 * tracing on the kernel. During a context switch, the current task
143 * will be set to the incoming process and the outgoing process will
144 * hop into write and then read. Since it's not the current process
145 * any more, the trace of those will land here. So, we need to just
146 * PTRACE_SYSCALL it.
147 */
148 case (SIGTRAP + 0x80):
149 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
150 tracer_panic("sleeping_process_signal : Failed to "
151 "PTRACE_SYSCALL pid %d, errno = %d\n",
152 pid, errno);
153 break;
154 case SIGSTOP:
155 break;
156 default:
157 tracer_panic("sleeping process %d got unexpected "
158 "signal : %d\n", pid, sig);
159 break;
160 }
161}
162
163/* Accessed only by the tracing thread */
164int debugger_pid = -1;
165int debugger_parent = -1;
166int debugger_fd = -1;
167int gdb_pid = -1;
168
169struct {
170 int pid;
171 int signal;
172 unsigned long addr;
173 struct timeval time;
174} signal_record[1024][32];
175
176int signal_index[32];
177int nsignals = 0;
178int debug_trace = 0;
179extern int io_nsignals, io_count, intr_count;
180
181extern void signal_usr1(int sig);
182
183int tracing_pid = -1;
184
185int tracer(int (*init_proc)(void *), void *sp)
186{
187 void *task = NULL;
188 int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
189 int proc_id = 0, n, err, old_tracing = 0, strace = 0;
190 int local_using_sysemu = 0;
469226a4 191
1da177e4
LT
192 signal(SIGPIPE, SIG_IGN);
193 setup_tracer_winch();
194 tracing_pid = os_getpid();
195 printf("tracing thread pid = %d\n", tracing_pid);
196
197 pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
198 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
199 if(n < 0){
200 printf("waitpid on idle thread failed, errno = %d\n", errno);
201 exit(1);
202 }
203 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
204 printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
205 exit(1);
206 }
207 if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
208 printf("Failed to continue idle thread, errno = %d\n", errno);
209 exit(1);
210 }
211
212 signal(SIGSEGV, (sighandler_t) tracer_segv);
213 signal(SIGUSR1, signal_usr1);
214 if(debug_trace){
215 printf("Tracing thread pausing to be attached\n");
216 stop();
217 }
218 if(debug){
219 if(gdb_pid != -1)
220 debugger_pid = attach_debugger(pid, gdb_pid, 1);
221 else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
222 if(debug_parent){
223 debugger_parent = os_process_parent(debugger_pid);
224 init_parent_proxy(debugger_parent);
225 err = attach(debugger_parent);
226 if(err){
227 printf("Failed to attach debugger parent %d, "
228 "errno = %d\n", debugger_parent, -err);
229 debugger_parent = -1;
230 }
231 else {
232 if(ptrace(PTRACE_SYSCALL, debugger_parent,
233 0, 0) < 0){
234 printf("Failed to continue debugger "
235 "parent, errno = %d\n", errno);
236 debugger_parent = -1;
237 }
238 }
239 }
240 }
241 set_cmdline("(tracing thread)");
242 while(1){
243 CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
244 if(pid <= 0){
245 if(errno != ECHILD){
246 printf("wait failed - errno = %d\n", errno);
247 }
248 continue;
249 }
250 if(pid == debugger_pid){
251 int cont = 0;
252
253 if(WIFEXITED(status) || WIFSIGNALED(status))
254 debugger_pid = -1;
255 /* XXX Figure out how to deal with gdb and SMP */
256 else cont = debugger_signal(status, cpu_tasks[0].pid);
257 if(cont == PTRACE_SYSCALL) strace = 1;
258 continue;
259 }
260 else if(pid == debugger_parent){
261 debugger_parent_signal(status, pid);
262 continue;
263 }
264 nsignals++;
265 if(WIFEXITED(status)) ;
266#ifdef notdef
267 {
268 printf("Child %d exited with status %d\n", pid,
269 WEXITSTATUS(status));
270 }
271#endif
272 else if(WIFSIGNALED(status)){
273 sig = WTERMSIG(status);
274 if(sig != 9){
275 printf("Child %d exited with signal %d\n", pid,
276 sig);
277 }
278 }
279 else if(WIFSTOPPED(status)){
280 proc_id = pid_to_processor_id(pid);
281 sig = WSTOPSIG(status);
1da177e4
LT
282 if(proc_id == -1){
283 sleeping_process_signal(pid, sig);
284 continue;
285 }
286
287 task = cpu_tasks[proc_id].task;
288 tracing = is_tracing(task);
289 old_tracing = tracing;
290
291 /* Assume: no syscall, when coming from user */
292 if ( tracing )
293 do_sigtrap(task);
294
295 switch(sig){
296 case SIGUSR1:
297 sig = 0;
298 op = do_proc_op(task, proc_id);
299 switch(op){
300 /*
301 * This is called when entering user mode; after
302 * this, we start intercepting syscalls.
303 *
304 * In fact, a process is started in kernel mode,
305 * so with is_tracing() == 0 (and that is reset
306 * when executing syscalls, since UML kernel has
307 * the right to do syscalls);
308 */
309 case OP_TRACE_ON:
310 arch_leave_kernel(task, pid);
311 tracing = 1;
312 break;
313 case OP_REBOOT:
314 case OP_HALT:
315 unmap_physmem();
316 kmalloc_ok = 0;
317 os_kill_ptraced_process(pid, 0);
318 /* Now let's reap remaining zombies */
319 errno = 0;
320 do {
321 waitpid(-1, &status,
322 WUNTRACED);
323 } while (errno != ECHILD);
324 return(op == OP_REBOOT);
325 case OP_NONE:
326 printf("Detaching pid %d\n", pid);
327 detach(pid, SIGSTOP);
328 continue;
329 default:
330 break;
331 }
332 /* OP_EXEC switches host processes on us,
333 * we want to continue the new one.
334 */
335 pid = cpu_tasks[proc_id].pid;
336 break;
337 case (SIGTRAP + 0x80):
338 if(!tracing && (debugger_pid != -1)){
339 child_signal(pid, status & 0x7fff);
340 continue;
341 }
342 tracing = 0;
343 /* local_using_sysemu has been already set
344 * below, since if we are here, is_tracing() on
345 * the traced task was 1, i.e. the process had
346 * already run through one iteration of the
347 * loop which executed a OP_TRACE_ON request.*/
348 do_syscall(task, pid, local_using_sysemu);
349 sig = SIGUSR2;
350 break;
351 case SIGTRAP:
352 if(!tracing && (debugger_pid != -1)){
353 child_signal(pid, status);
354 continue;
355 }
356 tracing = 0;
357 break;
358 case SIGPROF:
359 if(tracing) sig = 0;
360 break;
361 case SIGCHLD:
362 case SIGHUP:
363 sig = 0;
364 break;
365 case SIGSEGV:
366 case SIGIO:
367 case SIGALRM:
368 case SIGVTALRM:
369 case SIGFPE:
370 case SIGBUS:
371 case SIGILL:
372 case SIGWINCH:
373
374 default:
375 tracing = 0;
376 break;
377 }
378 set_tracing(task, tracing);
379
380 if(!tracing && old_tracing)
381 arch_enter_kernel(task, pid);
382
383 if(!tracing && (debugger_pid != -1) && (sig != 0) &&
384 (sig != SIGALRM) && (sig != SIGVTALRM) &&
385 (sig != SIGSEGV) && (sig != SIGTRAP) &&
386 (sig != SIGUSR2) && (sig != SIGIO) &&
387 (sig != SIGFPE)){
388 child_signal(pid, status);
389 continue;
390 }
391
392 local_using_sysemu = get_using_sysemu();
393
394 if(tracing)
395 cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
396 singlestepping(task));
397 else if((debugger_pid != -1) && strace)
398 cont_type = PTRACE_SYSCALL;
399 else
400 cont_type = PTRACE_CONT;
401
402 if(ptrace(cont_type, pid, 0, sig) != 0){
403 tracer_panic("ptrace failed to continue "
404 "process - errno = %d\n",
405 errno);
406 }
407 }
408 }
409 return(0);
410}
411
412static int __init uml_debug_setup(char *line, int *add)
413{
414 char *next;
415
416 debug = 1;
417 *add = 0;
418 if(*line != '=') return(0);
419 line++;
420
421 while(line != NULL){
422 next = strchr(line, ',');
423 if(next) *next++ = '\0';
424
425 if(!strcmp(line, "go")) debug_stop = 0;
426 else if(!strcmp(line, "parent")) debug_parent = 1;
427 else printf("Unknown debug option : '%s'\n", line);
428
429 line = next;
430 }
431 return(0);
432}
433
434__uml_setup("debug", uml_debug_setup,
435"debug\n"
436" Starts up the kernel under the control of gdb. See the \n"
437" kernel debugging tutorial and the debugging session pages\n"
438" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
439);
440
441static int __init uml_debugtrace_setup(char *line, int *add)
442{
443 debug_trace = 1;
444 return 0;
445}
446__uml_setup("debugtrace", uml_debugtrace_setup,
447"debugtrace\n"
448" Causes the tracing thread to pause until it is attached by a\n"
449" debugger and continued. This is mostly for debugging crashes\n"
450" early during boot, and should be pretty much obsoleted by\n"
451" the debug switch.\n\n"
452);
453
454/*
455 * Overrides for Emacs so that we follow Linus's tabbing style.
456 * Emacs will notice this stuff at the end of the file and automatically
457 * adjust the settings for this buffer only. This must remain at the end
458 * of the file.
459 * ---------------------------------------------------------------------------
460 * Local variables:
461 * c-file-style: "linux"
462 * End:
463 */
This page took 0.1472 seconds and 5 git commands to generate.