blob: 71daae24e48a8b8125b203fafc74ee40ea39c81d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#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"
Jeff Dikecd2ee4a2005-05-05 16:15:32 -070028#include "irq_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#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{
Jeff Dikecd2ee4a2005-05-05 16:15:32 -070036 if(pid != os_getpgrp())
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 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{
Bodo Stroesserc5784552005-05-05 16:15:31 -070092 struct faultinfo fi;
93 GET_FAULTINFO_FROM_SC(fi, &sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
Bodo Stroesserc5784552005-05-05 16:15:31 -070095 FAULT_ADDRESS(fi), SC_IP(&sc));
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 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());
Jeff Dikecd2ee4a2005-05-05 16:15:32 -0700122 init_irq_signals(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 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;
191#ifdef UML_CONFIG_SYSCALL_DEBUG
192 unsigned long eip = 0;
193 int last_index;
194#endif
195 signal(SIGPIPE, SIG_IGN);
196 setup_tracer_winch();
197 tracing_pid = os_getpid();
198 printf("tracing thread pid = %d\n", tracing_pid);
199
200 pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
201 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
202 if(n < 0){
203 printf("waitpid on idle thread failed, errno = %d\n", errno);
204 exit(1);
205 }
206 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
207 printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
208 exit(1);
209 }
210 if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
211 printf("Failed to continue idle thread, errno = %d\n", errno);
212 exit(1);
213 }
214
215 signal(SIGSEGV, (sighandler_t) tracer_segv);
216 signal(SIGUSR1, signal_usr1);
217 if(debug_trace){
218 printf("Tracing thread pausing to be attached\n");
219 stop();
220 }
221 if(debug){
222 if(gdb_pid != -1)
223 debugger_pid = attach_debugger(pid, gdb_pid, 1);
224 else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
225 if(debug_parent){
226 debugger_parent = os_process_parent(debugger_pid);
227 init_parent_proxy(debugger_parent);
228 err = attach(debugger_parent);
229 if(err){
230 printf("Failed to attach debugger parent %d, "
231 "errno = %d\n", debugger_parent, -err);
232 debugger_parent = -1;
233 }
234 else {
235 if(ptrace(PTRACE_SYSCALL, debugger_parent,
236 0, 0) < 0){
237 printf("Failed to continue debugger "
238 "parent, errno = %d\n", errno);
239 debugger_parent = -1;
240 }
241 }
242 }
243 }
244 set_cmdline("(tracing thread)");
245 while(1){
246 CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
247 if(pid <= 0){
248 if(errno != ECHILD){
249 printf("wait failed - errno = %d\n", errno);
250 }
251 continue;
252 }
253 if(pid == debugger_pid){
254 int cont = 0;
255
256 if(WIFEXITED(status) || WIFSIGNALED(status))
257 debugger_pid = -1;
258 /* XXX Figure out how to deal with gdb and SMP */
259 else cont = debugger_signal(status, cpu_tasks[0].pid);
260 if(cont == PTRACE_SYSCALL) strace = 1;
261 continue;
262 }
263 else if(pid == debugger_parent){
264 debugger_parent_signal(status, pid);
265 continue;
266 }
267 nsignals++;
268 if(WIFEXITED(status)) ;
269#ifdef notdef
270 {
271 printf("Child %d exited with status %d\n", pid,
272 WEXITSTATUS(status));
273 }
274#endif
275 else if(WIFSIGNALED(status)){
276 sig = WTERMSIG(status);
277 if(sig != 9){
278 printf("Child %d exited with signal %d\n", pid,
279 sig);
280 }
281 }
282 else if(WIFSTOPPED(status)){
283 proc_id = pid_to_processor_id(pid);
284 sig = WSTOPSIG(status);
285#ifdef UML_CONFIG_SYSCALL_DEBUG
286 if(signal_index[proc_id] == 1024){
287 signal_index[proc_id] = 0;
288 last_index = 1023;
289 }
290 else last_index = signal_index[proc_id] - 1;
291 if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
292 (sig == SIGALRM)) &&
293 (signal_record[proc_id][last_index].signal == sig)&&
294 (signal_record[proc_id][last_index].pid == pid))
295 signal_index[proc_id] = last_index;
296 signal_record[proc_id][signal_index[proc_id]].pid = pid;
297 gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
298 eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
299 signal_record[proc_id][signal_index[proc_id]].addr = eip;
300 signal_record[proc_id][signal_index[proc_id]++].signal = sig;
301#endif
302 if(proc_id == -1){
303 sleeping_process_signal(pid, sig);
304 continue;
305 }
306
307 task = cpu_tasks[proc_id].task;
308 tracing = is_tracing(task);
309 old_tracing = tracing;
310
311 /* Assume: no syscall, when coming from user */
312 if ( tracing )
313 do_sigtrap(task);
314
315 switch(sig){
316 case SIGUSR1:
317 sig = 0;
318 op = do_proc_op(task, proc_id);
319 switch(op){
320 /*
321 * This is called when entering user mode; after
322 * this, we start intercepting syscalls.
323 *
324 * In fact, a process is started in kernel mode,
325 * so with is_tracing() == 0 (and that is reset
326 * when executing syscalls, since UML kernel has
327 * the right to do syscalls);
328 */
329 case OP_TRACE_ON:
330 arch_leave_kernel(task, pid);
331 tracing = 1;
332 break;
333 case OP_REBOOT:
334 case OP_HALT:
335 unmap_physmem();
336 kmalloc_ok = 0;
337 os_kill_ptraced_process(pid, 0);
338 /* Now let's reap remaining zombies */
339 errno = 0;
340 do {
341 waitpid(-1, &status,
342 WUNTRACED);
343 } while (errno != ECHILD);
344 return(op == OP_REBOOT);
345 case OP_NONE:
346 printf("Detaching pid %d\n", pid);
347 detach(pid, SIGSTOP);
348 continue;
349 default:
350 break;
351 }
352 /* OP_EXEC switches host processes on us,
353 * we want to continue the new one.
354 */
355 pid = cpu_tasks[proc_id].pid;
356 break;
357 case (SIGTRAP + 0x80):
358 if(!tracing && (debugger_pid != -1)){
359 child_signal(pid, status & 0x7fff);
360 continue;
361 }
362 tracing = 0;
363 /* local_using_sysemu has been already set
364 * below, since if we are here, is_tracing() on
365 * the traced task was 1, i.e. the process had
366 * already run through one iteration of the
367 * loop which executed a OP_TRACE_ON request.*/
368 do_syscall(task, pid, local_using_sysemu);
369 sig = SIGUSR2;
370 break;
371 case SIGTRAP:
372 if(!tracing && (debugger_pid != -1)){
373 child_signal(pid, status);
374 continue;
375 }
376 tracing = 0;
377 break;
378 case SIGPROF:
379 if(tracing) sig = 0;
380 break;
381 case SIGCHLD:
382 case SIGHUP:
383 sig = 0;
384 break;
385 case SIGSEGV:
386 case SIGIO:
387 case SIGALRM:
388 case SIGVTALRM:
389 case SIGFPE:
390 case SIGBUS:
391 case SIGILL:
392 case SIGWINCH:
393
394 default:
395 tracing = 0;
396 break;
397 }
398 set_tracing(task, tracing);
399
400 if(!tracing && old_tracing)
401 arch_enter_kernel(task, pid);
402
403 if(!tracing && (debugger_pid != -1) && (sig != 0) &&
404 (sig != SIGALRM) && (sig != SIGVTALRM) &&
405 (sig != SIGSEGV) && (sig != SIGTRAP) &&
406 (sig != SIGUSR2) && (sig != SIGIO) &&
407 (sig != SIGFPE)){
408 child_signal(pid, status);
409 continue;
410 }
411
412 local_using_sysemu = get_using_sysemu();
413
414 if(tracing)
415 cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
416 singlestepping(task));
417 else if((debugger_pid != -1) && strace)
418 cont_type = PTRACE_SYSCALL;
419 else
420 cont_type = PTRACE_CONT;
421
422 if(ptrace(cont_type, pid, 0, sig) != 0){
423 tracer_panic("ptrace failed to continue "
424 "process - errno = %d\n",
425 errno);
426 }
427 }
428 }
429 return(0);
430}
431
432static int __init uml_debug_setup(char *line, int *add)
433{
434 char *next;
435
436 debug = 1;
437 *add = 0;
438 if(*line != '=') return(0);
439 line++;
440
441 while(line != NULL){
442 next = strchr(line, ',');
443 if(next) *next++ = '\0';
444
445 if(!strcmp(line, "go")) debug_stop = 0;
446 else if(!strcmp(line, "parent")) debug_parent = 1;
447 else printf("Unknown debug option : '%s'\n", line);
448
449 line = next;
450 }
451 return(0);
452}
453
454__uml_setup("debug", uml_debug_setup,
455"debug\n"
456" Starts up the kernel under the control of gdb. See the \n"
457" kernel debugging tutorial and the debugging session pages\n"
458" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
459);
460
461static int __init uml_debugtrace_setup(char *line, int *add)
462{
463 debug_trace = 1;
464 return 0;
465}
466__uml_setup("debugtrace", uml_debugtrace_setup,
467"debugtrace\n"
468" Causes the tracing thread to pause until it is attached by a\n"
469" debugger and continued. This is mostly for debugging crashes\n"
470" early during boot, and should be pretty much obsoleted by\n"
471" the debug switch.\n\n"
472);
473
474/*
475 * Overrides for Emacs so that we follow Linus's tabbing style.
476 * Emacs will notice this stuff at the end of the file and automatically
477 * adjust the settings for this buffer only. This must remain at the end
478 * of the file.
479 * ---------------------------------------------------------------------------
480 * Local variables:
481 * c-file-style: "linux"
482 * End:
483 */