blob: f7b1753a025c9a15bae6ccc0a41e6af16f1d7046 [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"
22#include "signal_user.h"
23#include "user_util.h"
24#include "mem_user.h"
25#include "process.h"
26#include "kern_util.h"
27#include "chan_user.h"
28#include "ptrace_user.h"
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{
36 if(pid != tracing_pid)
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{
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());
122 proc = arg;
123 return((*proc)(NULL));
124}
125
126static void sleeping_process_signal(int pid, int sig)
127{
128 switch(sig){
129 /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
130 * right because the process must be in the kernel already.
131 */
132 case SIGCONT:
133 case SIGTSTP:
134 if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
135 tracer_panic("sleeping_process_signal : Failed to "
136 "continue pid %d, signal = %d, "
137 "errno = %d\n", pid, sig, errno);
138 break;
139
140 /* This happens when the debugger (e.g. strace) is doing system call
141 * tracing on the kernel. During a context switch, the current task
142 * will be set to the incoming process and the outgoing process will
143 * hop into write and then read. Since it's not the current process
144 * any more, the trace of those will land here. So, we need to just
145 * PTRACE_SYSCALL it.
146 */
147 case (SIGTRAP + 0x80):
148 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
149 tracer_panic("sleeping_process_signal : Failed to "
150 "PTRACE_SYSCALL pid %d, errno = %d\n",
151 pid, errno);
152 break;
153 case SIGSTOP:
154 break;
155 default:
156 tracer_panic("sleeping process %d got unexpected "
157 "signal : %d\n", pid, sig);
158 break;
159 }
160}
161
162/* Accessed only by the tracing thread */
163int debugger_pid = -1;
164int debugger_parent = -1;
165int debugger_fd = -1;
166int gdb_pid = -1;
167
168struct {
169 int pid;
170 int signal;
171 unsigned long addr;
172 struct timeval time;
173} signal_record[1024][32];
174
175int signal_index[32];
176int nsignals = 0;
177int debug_trace = 0;
178extern int io_nsignals, io_count, intr_count;
179
180extern void signal_usr1(int sig);
181
182int tracing_pid = -1;
183
184int tracer(int (*init_proc)(void *), void *sp)
185{
186 void *task = NULL;
187 int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
188 int proc_id = 0, n, err, old_tracing = 0, strace = 0;
189 int local_using_sysemu = 0;
190#ifdef UML_CONFIG_SYSCALL_DEBUG
191 unsigned long eip = 0;
192 int last_index;
193#endif
194 signal(SIGPIPE, SIG_IGN);
195 setup_tracer_winch();
196 tracing_pid = os_getpid();
197 printf("tracing thread pid = %d\n", tracing_pid);
198
199 pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
200 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
201 if(n < 0){
202 printf("waitpid on idle thread failed, errno = %d\n", errno);
203 exit(1);
204 }
205 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
206 printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
207 exit(1);
208 }
209 if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
210 printf("Failed to continue idle thread, errno = %d\n", errno);
211 exit(1);
212 }
213
214 signal(SIGSEGV, (sighandler_t) tracer_segv);
215 signal(SIGUSR1, signal_usr1);
216 if(debug_trace){
217 printf("Tracing thread pausing to be attached\n");
218 stop();
219 }
220 if(debug){
221 if(gdb_pid != -1)
222 debugger_pid = attach_debugger(pid, gdb_pid, 1);
223 else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
224 if(debug_parent){
225 debugger_parent = os_process_parent(debugger_pid);
226 init_parent_proxy(debugger_parent);
227 err = attach(debugger_parent);
228 if(err){
229 printf("Failed to attach debugger parent %d, "
230 "errno = %d\n", debugger_parent, -err);
231 debugger_parent = -1;
232 }
233 else {
234 if(ptrace(PTRACE_SYSCALL, debugger_parent,
235 0, 0) < 0){
236 printf("Failed to continue debugger "
237 "parent, errno = %d\n", errno);
238 debugger_parent = -1;
239 }
240 }
241 }
242 }
243 set_cmdline("(tracing thread)");
244 while(1){
245 CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
246 if(pid <= 0){
247 if(errno != ECHILD){
248 printf("wait failed - errno = %d\n", errno);
249 }
250 continue;
251 }
252 if(pid == debugger_pid){
253 int cont = 0;
254
255 if(WIFEXITED(status) || WIFSIGNALED(status))
256 debugger_pid = -1;
257 /* XXX Figure out how to deal with gdb and SMP */
258 else cont = debugger_signal(status, cpu_tasks[0].pid);
259 if(cont == PTRACE_SYSCALL) strace = 1;
260 continue;
261 }
262 else if(pid == debugger_parent){
263 debugger_parent_signal(status, pid);
264 continue;
265 }
266 nsignals++;
267 if(WIFEXITED(status)) ;
268#ifdef notdef
269 {
270 printf("Child %d exited with status %d\n", pid,
271 WEXITSTATUS(status));
272 }
273#endif
274 else if(WIFSIGNALED(status)){
275 sig = WTERMSIG(status);
276 if(sig != 9){
277 printf("Child %d exited with signal %d\n", pid,
278 sig);
279 }
280 }
281 else if(WIFSTOPPED(status)){
282 proc_id = pid_to_processor_id(pid);
283 sig = WSTOPSIG(status);
284#ifdef UML_CONFIG_SYSCALL_DEBUG
285 if(signal_index[proc_id] == 1024){
286 signal_index[proc_id] = 0;
287 last_index = 1023;
288 }
289 else last_index = signal_index[proc_id] - 1;
290 if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
291 (sig == SIGALRM)) &&
292 (signal_record[proc_id][last_index].signal == sig)&&
293 (signal_record[proc_id][last_index].pid == pid))
294 signal_index[proc_id] = last_index;
295 signal_record[proc_id][signal_index[proc_id]].pid = pid;
296 gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
297 eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
298 signal_record[proc_id][signal_index[proc_id]].addr = eip;
299 signal_record[proc_id][signal_index[proc_id]++].signal = sig;
300#endif
301 if(proc_id == -1){
302 sleeping_process_signal(pid, sig);
303 continue;
304 }
305
306 task = cpu_tasks[proc_id].task;
307 tracing = is_tracing(task);
308 old_tracing = tracing;
309
310 /* Assume: no syscall, when coming from user */
311 if ( tracing )
312 do_sigtrap(task);
313
314 switch(sig){
315 case SIGUSR1:
316 sig = 0;
317 op = do_proc_op(task, proc_id);
318 switch(op){
319 /*
320 * This is called when entering user mode; after
321 * this, we start intercepting syscalls.
322 *
323 * In fact, a process is started in kernel mode,
324 * so with is_tracing() == 0 (and that is reset
325 * when executing syscalls, since UML kernel has
326 * the right to do syscalls);
327 */
328 case OP_TRACE_ON:
329 arch_leave_kernel(task, pid);
330 tracing = 1;
331 break;
332 case OP_REBOOT:
333 case OP_HALT:
334 unmap_physmem();
335 kmalloc_ok = 0;
336 os_kill_ptraced_process(pid, 0);
337 /* Now let's reap remaining zombies */
338 errno = 0;
339 do {
340 waitpid(-1, &status,
341 WUNTRACED);
342 } while (errno != ECHILD);
343 return(op == OP_REBOOT);
344 case OP_NONE:
345 printf("Detaching pid %d\n", pid);
346 detach(pid, SIGSTOP);
347 continue;
348 default:
349 break;
350 }
351 /* OP_EXEC switches host processes on us,
352 * we want to continue the new one.
353 */
354 pid = cpu_tasks[proc_id].pid;
355 break;
356 case (SIGTRAP + 0x80):
357 if(!tracing && (debugger_pid != -1)){
358 child_signal(pid, status & 0x7fff);
359 continue;
360 }
361 tracing = 0;
362 /* local_using_sysemu has been already set
363 * below, since if we are here, is_tracing() on
364 * the traced task was 1, i.e. the process had
365 * already run through one iteration of the
366 * loop which executed a OP_TRACE_ON request.*/
367 do_syscall(task, pid, local_using_sysemu);
368 sig = SIGUSR2;
369 break;
370 case SIGTRAP:
371 if(!tracing && (debugger_pid != -1)){
372 child_signal(pid, status);
373 continue;
374 }
375 tracing = 0;
376 break;
377 case SIGPROF:
378 if(tracing) sig = 0;
379 break;
380 case SIGCHLD:
381 case SIGHUP:
382 sig = 0;
383 break;
384 case SIGSEGV:
385 case SIGIO:
386 case SIGALRM:
387 case SIGVTALRM:
388 case SIGFPE:
389 case SIGBUS:
390 case SIGILL:
391 case SIGWINCH:
392
393 default:
394 tracing = 0;
395 break;
396 }
397 set_tracing(task, tracing);
398
399 if(!tracing && old_tracing)
400 arch_enter_kernel(task, pid);
401
402 if(!tracing && (debugger_pid != -1) && (sig != 0) &&
403 (sig != SIGALRM) && (sig != SIGVTALRM) &&
404 (sig != SIGSEGV) && (sig != SIGTRAP) &&
405 (sig != SIGUSR2) && (sig != SIGIO) &&
406 (sig != SIGFPE)){
407 child_signal(pid, status);
408 continue;
409 }
410
411 local_using_sysemu = get_using_sysemu();
412
413 if(tracing)
414 cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
415 singlestepping(task));
416 else if((debugger_pid != -1) && strace)
417 cont_type = PTRACE_SYSCALL;
418 else
419 cont_type = PTRACE_CONT;
420
421 if(ptrace(cont_type, pid, 0, sig) != 0){
422 tracer_panic("ptrace failed to continue "
423 "process - errno = %d\n",
424 errno);
425 }
426 }
427 }
428 return(0);
429}
430
431static int __init uml_debug_setup(char *line, int *add)
432{
433 char *next;
434
435 debug = 1;
436 *add = 0;
437 if(*line != '=') return(0);
438 line++;
439
440 while(line != NULL){
441 next = strchr(line, ',');
442 if(next) *next++ = '\0';
443
444 if(!strcmp(line, "go")) debug_stop = 0;
445 else if(!strcmp(line, "parent")) debug_parent = 1;
446 else printf("Unknown debug option : '%s'\n", line);
447
448 line = next;
449 }
450 return(0);
451}
452
453__uml_setup("debug", uml_debug_setup,
454"debug\n"
455" Starts up the kernel under the control of gdb. See the \n"
456" kernel debugging tutorial and the debugging session pages\n"
457" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
458);
459
460static int __init uml_debugtrace_setup(char *line, int *add)
461{
462 debug_trace = 1;
463 return 0;
464}
465__uml_setup("debugtrace", uml_debugtrace_setup,
466"debugtrace\n"
467" Causes the tracing thread to pause until it is attached by a\n"
468" debugger and continued. This is mostly for debugging crashes\n"
469" early during boot, and should be pretty much obsoleted by\n"
470" the debug switch.\n\n"
471);
472
473/*
474 * Overrides for Emacs so that we follow Linus's tabbing style.
475 * Emacs will notice this stuff at the end of the file and automatically
476 * adjust the settings for this buffer only. This must remain at the end
477 * of the file.
478 * ---------------------------------------------------------------------------
479 * Local variables:
480 * c-file-style: "linux"
481 * End:
482 */