handle_event.c revision 161193ff49250bfb819748ec6404e07957dc6ab5
1#include "config.h"
2
3#define _GNU_SOURCE
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7#include <signal.h>
8#include <assert.h>
9#include <sys/time.h>
10
11#include "common.h"
12
13#ifdef __powerpc__
14#include <sys/ptrace.h>
15#endif
16
17static void handle_signal(Event *event);
18static void handle_exit(Event *event);
19static void handle_exit_signal(Event *event);
20static void handle_syscall(Event *event);
21static void handle_arch_syscall(Event *event);
22static void handle_sysret(Event *event);
23static void handle_arch_sysret(Event *event);
24static void handle_clone(Event *event);
25static void handle_exec(Event *event);
26static void handle_breakpoint(Event *event);
27static void handle_new(Event *event);
28static void remove_proc(Process *proc);
29
30static void callstack_push_syscall(Process *proc, int sysnum);
31static void callstack_push_symfunc(Process *proc,
32				   struct library_symbol *sym);
33static void callstack_pop(Process *proc);
34
35static char * shortsignal(Process *proc, int signum);
36static char * sysname(Process *proc, int sysnum);
37static char * arch_sysname(Process *proc, int sysnum);
38
39void
40handle_event(Event *event) {
41	debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type);
42	switch (event->type) {
43	case EVENT_NONE:
44		debug(1, "event: none");
45		return;
46	case EVENT_SIGNAL:
47		debug(1, "event: signal (%s [%d])",
48		      shortsignal(event->proc, event->e_un.signum),
49		      event->e_un.signum);
50		handle_signal(event);
51		return;
52	case EVENT_EXIT:
53		debug(1, "event: exit (%d)", event->e_un.ret_val);
54		handle_exit(event);
55		return;
56	case EVENT_EXIT_SIGNAL:
57		debug(1, "event: exit signal (%s [%d])",
58		      shortsignal(event->proc, event->e_un.signum),
59		      event->e_un.signum);
60		handle_exit_signal(event);
61		return;
62	case EVENT_SYSCALL:
63		debug(1, "event: syscall (%s [%d])",
64		      sysname(event->proc, event->e_un.sysnum),
65		      event->e_un.sysnum);
66		handle_syscall(event);
67		return;
68	case EVENT_SYSRET:
69		debug(1, "event: sysret (%s [%d])",
70		      sysname(event->proc, event->e_un.sysnum),
71		      event->e_un.sysnum);
72		handle_sysret(event);
73		return;
74	case EVENT_ARCH_SYSCALL:
75		debug(1, "event: arch_syscall (%s [%d])",
76				arch_sysname(event->proc, event->e_un.sysnum),
77				event->e_un.sysnum);
78		handle_arch_syscall(event);
79		return;
80	case EVENT_ARCH_SYSRET:
81		debug(1, "event: arch_sysret (%s [%d])",
82				arch_sysname(event->proc, event->e_un.sysnum),
83				event->e_un.sysnum);
84		handle_arch_sysret(event);
85		return;
86	case EVENT_CLONE:
87		debug(1, "event: clone (%u)", event->e_un.newpid);
88		handle_clone(event);
89		return;
90	case EVENT_EXEC:
91		debug(1, "event: exec()");
92		handle_exec(event);
93		return;
94	case EVENT_BREAKPOINT:
95		debug(1, "event: breakpoint");
96		handle_breakpoint(event);
97		return;
98	case EVENT_NEW:
99		debug(1, "event: new process");
100		handle_new(event);
101		return;
102	default:
103		fprintf(stderr, "Error! unknown event?\n");
104		exit(1);
105	}
106}
107
108/* TODO */
109static void *
110address_clone(void * addr) {
111	debug(DEBUG_FUNCTION, "address_clone(%p)", addr);
112	return addr;
113}
114
115static void *
116breakpoint_clone(void * bp) {
117	Breakpoint * b;
118	debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp);
119	b = malloc(sizeof(Breakpoint));
120	if (!b) {
121		perror("malloc()");
122		exit(1);
123	}
124	memcpy(b, bp, sizeof(Breakpoint));
125	return b;
126}
127
128typedef struct Pending_New Pending_New;
129struct Pending_New {
130	pid_t pid;
131	Pending_New * next;
132};
133static Pending_New * pending_news = NULL;
134
135static int
136pending_new(pid_t pid) {
137	Pending_New * p;
138
139	debug(DEBUG_FUNCTION, "pending_new(%d)", pid);
140
141	p = pending_news;
142	while (p) {
143		if (p->pid == pid) {
144			return 1;
145		}
146		p = p->next;
147	}
148	return 0;
149}
150
151static void
152pending_new_insert(pid_t pid) {
153	Pending_New * p;
154
155	debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid);
156
157	p = malloc(sizeof(Pending_New));
158	if (!p) {
159		perror("malloc()");
160		exit(1);
161	}
162	p->pid = pid;
163	p->next = pending_news;
164	pending_news = p;
165}
166
167static void
168pending_new_remove(pid_t pid) {
169	Pending_New *p, *pred;
170
171	debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid);
172
173	p = pending_news;
174	if (p->pid == pid) {
175		pending_news = p->next;
176		free(p);
177	} else {
178		while (p) {
179			if (p->pid == pid) {
180				pred->next = p->next;
181				free(p);
182			}
183			pred = p;
184			p = p->next;
185		}
186	}
187}
188
189static void
190handle_clone(Event * event) {
191	Process *p;
192
193	debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid);
194
195	p = malloc(sizeof(Process));
196	if (!p) {
197		perror("malloc()");
198		exit(1);
199	}
200	memcpy(p, event->proc, sizeof(Process));
201	p->breakpoints = dict_clone(event->proc->breakpoints, address_clone, breakpoint_clone);
202	p->pid = event->e_un.newpid;
203	p->parent = event->proc;
204
205	if (pending_new(p->pid)) {
206		pending_new_remove(p->pid);
207		if (p->breakpoint_being_enabled) {
208			enable_breakpoint(p->pid, p->breakpoint_being_enabled);
209			p->breakpoint_being_enabled = NULL;
210		}
211		if (event->proc->state == STATE_ATTACHED && options.follow) {
212			p->state = STATE_ATTACHED;
213		} else {
214			p->state = STATE_IGNORED;
215		}
216		continue_process(p->pid);
217		p->next = list_of_processes;
218		list_of_processes = p;
219	} else {
220		p->state = STATE_BEING_CREATED;
221		p->next = list_of_processes;
222		list_of_processes = p;
223	}
224	continue_process(event->proc->pid);
225}
226
227static void
228handle_new(Event * event) {
229	Process * proc;
230
231	debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid);
232
233	proc = pid2proc(event->e_un.newpid);
234	if (!proc) {
235		pending_new_insert(event->e_un.newpid);
236	} else {
237		assert(proc->state == STATE_BEING_CREATED);
238		if (proc->breakpoint_being_enabled) {
239			enable_breakpoint(proc->pid, proc->breakpoint_being_enabled);
240			proc->breakpoint_being_enabled = NULL;
241		}
242		if (options.follow) {
243			proc->state = STATE_ATTACHED;
244		} else {
245			proc->state = STATE_IGNORED;
246		}
247		continue_process(proc->pid);
248	}
249}
250
251static char *
252shortsignal(Process *proc, int signum) {
253	static char *signalent0[] = {
254#include "signalent.h"
255	};
256	static char *signalent1[] = {
257#include "signalent1.h"
258	};
259	static char **signalents[] = { signalent0, signalent1 };
260	int nsignals[] = { sizeof signalent0 / sizeof signalent0[0],
261		sizeof signalent1 / sizeof signalent1[0]
262	};
263
264	debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum);
265
266	if (proc->personality > sizeof signalents / sizeof signalents[0])
267		abort();
268	if (signum < 0 || signum >= nsignals[proc->personality]) {
269		return "UNKNOWN_SIGNAL";
270	} else {
271		return signalents[proc->personality][signum];
272	}
273}
274
275static char *
276sysname(Process *proc, int sysnum) {
277	static char result[128];
278	static char *syscalent0[] = {
279#include "syscallent.h"
280	};
281	static char *syscalent1[] = {
282#include "syscallent1.h"
283	};
284	static char **syscalents[] = { syscalent0, syscalent1 };
285	int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0],
286		sizeof syscalent1 / sizeof syscalent1[0]
287	};
288
289	debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
290
291	if (proc->personality > sizeof syscalents / sizeof syscalents[0])
292		abort();
293	if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) {
294		sprintf(result, "SYS_%d", sysnum);
295		return result;
296	} else {
297		sprintf(result, "SYS_%s",
298			syscalents[proc->personality][sysnum]);
299		return result;
300	}
301}
302
303static char *
304arch_sysname(Process *proc, int sysnum) {
305	static char result[128];
306	static char *arch_syscalent[] = {
307#include "arch_syscallent.h"
308	};
309	int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0];
310
311	debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
312
313	if (sysnum < 0 || sysnum >= nsyscals) {
314		sprintf(result, "ARCH_%d", sysnum);
315		return result;
316	} else {
317		sprintf(result, "ARCH_%s",
318				arch_syscalent[sysnum]);
319		return result;
320	}
321}
322
323static void
324handle_signal(Event *event) {
325	debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
326	if (exiting && event->e_un.signum == SIGSTOP) {
327		pid_t pid = event->proc->pid;
328		disable_all_breakpoints(event->proc);
329		untrace_pid(pid);
330		remove_proc(event->proc);
331		return;
332	}
333	if (event->proc->state != STATE_IGNORED) {
334		output_line(event->proc, "--- %s (%s) ---",
335				shortsignal(event->proc, event->e_un.signum),
336				strsignal(event->e_un.signum));
337	}
338	continue_after_signal(event->proc->pid, event->e_un.signum);
339}
340
341static void
342handle_exit(Event *event) {
343	debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
344	if (event->proc->state != STATE_IGNORED) {
345		output_line(event->proc, "+++ exited (status %d) +++",
346				event->e_un.ret_val);
347	}
348	remove_proc(event->proc);
349}
350
351static void
352handle_exit_signal(Event *event) {
353	debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
354	if (event->proc->state != STATE_IGNORED) {
355		output_line(event->proc, "+++ killed by %s +++",
356				shortsignal(event->proc, event->e_un.signum));
357	}
358	remove_proc(event->proc);
359}
360
361static void
362remove_proc(Process *proc) {
363	Process *tmp, *tmp2;
364
365	debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
366
367	if (list_of_processes == proc) {
368		tmp = list_of_processes;
369		list_of_processes = list_of_processes->next;
370		free(tmp);
371		return;
372	}
373	tmp = list_of_processes;
374	while (tmp->next) {
375		if (tmp->next == proc) {
376			tmp2 = tmp->next;
377			tmp->next = tmp->next->next;
378			free(tmp2);
379			continue;
380		}
381		tmp = tmp->next;
382	}
383}
384
385static void
386handle_syscall(Event *event) {
387	debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
388	if (event->proc->state != STATE_IGNORED) {
389		if (options.syscalls) {
390			output_left(LT_TOF_SYSCALL, event->proc,
391					sysname(event->proc, event->e_un.sysnum));
392		}
393		if (event->proc->breakpoints_enabled == 0) {
394			enable_all_breakpoints(event->proc);
395		}
396		callstack_push_syscall(event->proc, event->e_un.sysnum);
397	}
398	continue_process(event->proc->pid);
399}
400
401static void
402handle_exec(Event * event) {
403	Process * proc = event->proc;
404	pid_t saved_pid;
405
406	debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid);
407	if (proc->state == STATE_IGNORED) {
408		untrace_pid(proc->pid);
409		remove_proc(proc);
410		return;
411	}
412	output_line(proc, "--- Called exec() ---");
413	proc->mask_32bit = 0;
414	proc->personality = 0;
415	proc->arch_ptr = NULL;
416	free(proc->filename);
417	proc->filename = pid2name(proc->pid);
418	saved_pid = proc->pid;
419	proc->pid = 0;
420	breakpoints_init(proc);
421	proc->pid = saved_pid;
422	proc->callstack_depth = 0;
423	continue_process(proc->pid);
424}
425
426static void
427handle_arch_syscall(Event *event) {
428	debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
429	if (event->proc->state != STATE_IGNORED) {
430		if (options.syscalls) {
431			output_left(LT_TOF_SYSCALL, event->proc,
432					arch_sysname(event->proc, event->e_un.sysnum));
433		}
434		if (event->proc->breakpoints_enabled == 0) {
435			enable_all_breakpoints(event->proc);
436		}
437		callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
438	}
439	continue_process(event->proc->pid);
440}
441
442struct timeval current_time_spent;
443
444static void
445calc_time_spent(Process *proc) {
446	struct timeval tv;
447	struct timezone tz;
448	struct timeval diff;
449	struct callstack_element *elem;
450
451	debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid);
452	elem = &proc->callstack[proc->callstack_depth - 1];
453
454	gettimeofday(&tv, &tz);
455
456	diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
457	if (tv.tv_usec >= elem->time_spent.tv_usec) {
458		diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
459	} else {
460		diff.tv_sec++;
461		diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
462	}
463	current_time_spent = diff;
464}
465
466static void
467handle_sysret(Event *event) {
468	debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
469	if (event->proc->state != STATE_IGNORED) {
470		if (opt_T || options.summary) {
471			calc_time_spent(event->proc);
472		}
473		callstack_pop(event->proc);
474		if (options.syscalls) {
475			output_right(LT_TOF_SYSCALLR, event->proc,
476					sysname(event->proc, event->e_un.sysnum));
477		}
478	}
479	continue_process(event->proc->pid);
480}
481
482static void
483handle_arch_sysret(Event *event) {
484	debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
485	if (event->proc->state != STATE_IGNORED) {
486		if (opt_T || options.summary) {
487			calc_time_spent(event->proc);
488		}
489		callstack_pop(event->proc);
490		if (options.syscalls) {
491			output_right(LT_TOF_SYSCALLR, event->proc,
492					arch_sysname(event->proc, event->e_un.sysnum));
493		}
494	}
495	continue_process(event->proc->pid);
496}
497
498static void
499handle_breakpoint(Event *event) {
500	int i, j;
501	Breakpoint *sbp;
502
503	debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
504	debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
505
506#ifdef __powerpc__
507	/* Need to skip following NOP's to prevent a fake function from being stacked.  */
508	long stub_addr = (long) get_count_register(event->proc);
509	Breakpoint *stub_bp = NULL;
510	char nop_instruction[] = PPC_NOP;
511
512	stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr);
513
514	if (stub_bp) {
515		unsigned char *bp_instruction = stub_bp->orig_value;
516
517		if (memcmp(bp_instruction, nop_instruction,
518			    PPC_NOP_LENGTH) == 0) {
519			if (stub_addr != (long) event->e_un.brk_addr) {
520				set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
521				continue_process(event->proc->pid);
522				return;
523			}
524		}
525	}
526#endif
527	if ((sbp = event->proc->breakpoint_being_enabled) != 0) {
528		/* Reinsert breakpoint */
529		continue_enabling_breakpoint(event->proc->pid,
530					     event->proc->
531					     breakpoint_being_enabled);
532		event->proc->breakpoint_being_enabled = NULL;
533		return;
534	}
535
536	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
537		if (event->e_un.brk_addr ==
538		    event->proc->callstack[i].return_addr) {
539#ifdef __powerpc__
540			/*
541			 * PPC HACK! (XXX FIXME TODO)
542			 * The PLT gets modified during the first call,
543			 * so be sure to re-enable the breakpoint.
544			 */
545			unsigned long a;
546			struct library_symbol *libsym =
547			    event->proc->callstack[i].c_un.libfunc;
548			void *addr = sym2addr(event->proc, libsym);
549
550			if (libsym->plt_type != LS_TOPLT_POINT) {
551				unsigned char break_insn[] = BREAKPOINT_VALUE;
552
553				sbp = address2bpstruct(event->proc, addr);
554				assert(sbp);
555				a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
556					   addr);
557
558				if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
559					sbp->enabled--;
560					insert_breakpoint(event->proc, addr,
561							  libsym);
562				}
563			} else {
564				sbp = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, libsym));
565				assert(sbp);
566				if (addr != sbp->addr) {
567					insert_breakpoint(event->proc, addr,
568							  libsym);
569				}
570			}
571#elif defined(__mips__)
572			void *addr = NULL;
573			struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
574			struct library_symbol *new_sym;
575			assert(sym);
576			addr=sym2addr(event->proc,sym);
577			sbp = dict_find_entry(event->proc->breakpoints, addr);
578			if (sbp) {
579				if (addr != sbp->addr) {
580					insert_breakpoint(event->proc, addr, sym);
581				}
582			} else {
583				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
584				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
585				new_sym->next=event->proc->list_of_symbols;
586				event->proc->list_of_symbols=new_sym;
587				insert_breakpoint(event->proc, addr, new_sym);
588			}
589#endif
590			for (j = event->proc->callstack_depth - 1; j > i; j--) {
591				callstack_pop(event->proc);
592			}
593			if (event->proc->state != STATE_IGNORED) {
594				if (opt_T || options.summary) {
595					calc_time_spent(event->proc);
596				}
597			}
598			callstack_pop(event->proc);
599			event->proc->return_addr = event->e_un.brk_addr;
600			if (event->proc->state != STATE_IGNORED) {
601				output_right(LT_TOF_FUNCTIONR, event->proc,
602						event->proc->callstack[i].c_un.libfunc->name);
603			}
604			continue_after_breakpoint(event->proc,
605					address2bpstruct(event->proc,
606						event->e_un.brk_addr));
607			return;
608		}
609	}
610
611	if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) {
612		if (event->proc->state != STATE_IGNORED) {
613			event->proc->stack_pointer = get_stack_pointer(event->proc);
614			event->proc->return_addr =
615				get_return_addr(event->proc, event->proc->stack_pointer);
616			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
617			callstack_push_symfunc(event->proc, sbp->libsym);
618		}
619#ifdef PLT_REINITALISATION_BP
620		if (event->proc->need_to_reinitialize_breakpoints
621		    && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
622			0))
623			reinitialize_breakpoints(event->proc);
624#endif
625
626		continue_after_breakpoint(event->proc, sbp);
627		return;
628	}
629
630	if (event->proc->state != STATE_IGNORED) {
631		output_line(event->proc, "unexpected breakpoint at %p",
632				(void *)event->e_un.brk_addr);
633	}
634	continue_process(event->proc->pid);
635}
636
637static void
638callstack_push_syscall(Process *proc, int sysnum) {
639	struct callstack_element *elem;
640
641	debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
642	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
643	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
644		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
645		abort();
646		return;
647	}
648
649	elem = &proc->callstack[proc->callstack_depth];
650	elem->is_syscall = 1;
651	elem->c_un.syscall = sysnum;
652	elem->return_addr = NULL;
653
654	proc->callstack_depth++;
655	if (opt_T || options.summary) {
656		struct timezone tz;
657		gettimeofday(&elem->time_spent, &tz);
658	}
659}
660
661static void
662callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
663	struct callstack_element *elem, *prev;
664
665	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
666	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
667	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
668		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
669		abort();
670		return;
671	}
672
673	prev = &proc->callstack[proc->callstack_depth-1];
674	elem = &proc->callstack[proc->callstack_depth];
675	elem->is_syscall = 0;
676	elem->c_un.libfunc = sym;
677
678	elem->return_addr = proc->return_addr;
679	if (elem->return_addr) {
680		insert_breakpoint(proc, elem->return_addr, 0);
681	}
682
683	/* handle functions like atexit() on mips which have no return */
684	if (elem->return_addr != prev->return_addr)
685		proc->callstack_depth++;
686	if (opt_T || options.summary) {
687		struct timezone tz;
688		gettimeofday(&elem->time_spent, &tz);
689	}
690}
691
692static void
693callstack_pop(Process *proc) {
694	struct callstack_element *elem;
695	assert(proc->callstack_depth > 0);
696
697	debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
698	elem = &proc->callstack[proc->callstack_depth - 1];
699	if (!elem->is_syscall && elem->return_addr) {
700		delete_breakpoint(proc, elem->return_addr);
701	}
702	proc->callstack_depth--;
703}
704