events.c revision f0bd98b3e6753d8609a3054a61f2df6f9cdac10a
1#include "config.h"
2
3#define	_GNU_SOURCE	1
4#include <stdlib.h>
5#include <sys/types.h>
6#include <sys/wait.h>
7#include <errno.h>
8#include <signal.h>
9#include <string.h>
10#include <sys/ptrace.h>
11
12#include "common.h"
13
14static Event event;
15
16Event *
17next_event(void) {
18	pid_t pid;
19	int status;
20	int tmp;
21	int stop_signal;
22
23	debug(DEBUG_FUNCTION, "next_event()");
24	if (!list_of_processes) {
25		debug(DEBUG_EVENT, "event: No more traced programs: exiting");
26		exit(0);
27	}
28	pid = waitpid(-1, &status, __WALL);
29	if (pid == -1) {
30		if (errno == ECHILD) {
31			debug(DEBUG_EVENT, "event: No more traced programs: exiting");
32			exit(0);
33		} else if (errno == EINTR) {
34			debug(DEBUG_EVENT, "event: none (wait received EINTR?)");
35			event.type = EVENT_NONE;
36			return &event;
37		}
38		perror("wait");
39		exit(1);
40	}
41	event.proc = pid2proc(pid);
42	if (!event.proc || event.proc->state == STATE_BEING_CREATED) {
43		event.type = EVENT_NEW;
44		event.e_un.newpid = pid;
45		debug(DEBUG_EVENT, "event: NEW: pid=%d", pid);
46		return &event;
47	}
48	get_arch_dep(event.proc);
49	event.proc->instruction_pointer = NULL;
50	debug(3, "event from pid %u", pid);
51	if (event.proc->breakpoints_enabled == -1) {
52		event.type = EVENT_NONE;
53		trace_set_options(event.proc, event.proc->pid);
54		enable_all_breakpoints(event.proc);
55		continue_process(event.proc->pid);
56		debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling breakpoints)", pid);
57		return &event;
58	} else if (!event.proc->libdl_hooked) {
59		/* debug struct may not have been written yet.. */
60		if (linkmap_init(event.proc, &main_lte) == 0) {
61			event.proc->libdl_hooked = 1;
62		}
63	}
64
65	if (opt_i) {
66		event.proc->instruction_pointer =
67			get_instruction_pointer(event.proc);
68	}
69	switch (syscall_p(event.proc, status, &tmp)) {
70		case 1:
71			event.type = EVENT_SYSCALL;
72			event.e_un.sysnum = tmp;
73			debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp);
74			return &event;
75		case 2:
76			event.type = EVENT_SYSRET;
77			event.e_un.sysnum = tmp;
78			debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp);
79			return &event;
80		case 3:
81			event.type = EVENT_ARCH_SYSCALL;
82			event.e_un.sysnum = tmp;
83			debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp);
84			return &event;
85		case 4:
86			event.type = EVENT_ARCH_SYSRET;
87			event.e_un.sysnum = tmp;
88			debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp);
89			return &event;
90		case -1:
91			event.type = EVENT_NONE;
92			continue_process(event.proc->pid);
93			debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid);
94			return &event;
95	}
96	if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
97		unsigned long data;
98		ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
99		event.type = EVENT_CLONE;
100		event.e_un.newpid = data;
101		debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data);
102		return &event;
103	}
104	if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
105		event.type = EVENT_EXEC;
106		debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid);
107		return &event;
108	}
109	if (WIFEXITED(status)) {
110		event.type = EVENT_EXIT;
111		event.e_un.ret_val = WEXITSTATUS(status);
112		debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val);
113		return &event;
114	}
115	if (WIFSIGNALED(status)) {
116		event.type = EVENT_EXIT_SIGNAL;
117		event.e_un.signum = WTERMSIG(status);
118		debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum);
119		return &event;
120	}
121	if (!WIFSTOPPED(status)) {
122		/* should never happen */
123		event.type = EVENT_NONE;
124		debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid);
125		return &event;
126	}
127
128	stop_signal = WSTOPSIG(status);
129
130	/* On some targets, breakpoints are signalled not using
131	   SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT.  Check
132	   for these. (TODO: is this true?) */
133	if (stop_signal == SIGSEGV
134			|| stop_signal == SIGILL
135#ifdef SIGEMT
136			|| stop_signal == SIGEMT
137#endif
138	   ) {
139		if (!event.proc->instruction_pointer) {
140			event.proc->instruction_pointer =
141				get_instruction_pointer(event.proc);
142		}
143
144		if (address2bpstruct(event.proc, event.proc->instruction_pointer))
145			stop_signal = SIGTRAP;
146	}
147
148	if (stop_signal != (SIGTRAP | event.proc->tracesysgood)
149			&& stop_signal != SIGTRAP) {
150		event.type = EVENT_SIGNAL;
151		event.e_un.signum = stop_signal;
152		debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal);
153		return &event;
154	}
155
156	/* last case [by exhaustion] */
157	event.type = EVENT_BREAKPOINT;
158
159	if (!event.proc->instruction_pointer) {
160		event.proc->instruction_pointer =
161			get_instruction_pointer(event.proc);
162	}
163	event.e_un.brk_addr =
164		event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
165	debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr);
166	return &event;
167}
168