events.c revision 9a5420c82a2fd81681572a2e3859ea1671c3bded
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
16static enum pcb_status
17first (Process * proc, void * data)
18{
19	return pcb_stop;
20}
21
22Event *
23next_event(void)
24{
25	pid_t pid;
26	int status;
27	int tmp;
28	int stop_signal;
29
30	debug(DEBUG_FUNCTION, "next_event()");
31	if (!each_process(NULL, &first, NULL)) {
32		debug(DEBUG_EVENT, "event: No more traced programs: exiting");
33		exit(0);
34	}
35	pid = waitpid(-1, &status, __WALL);
36	if (pid == -1) {
37		if (errno == ECHILD) {
38			debug(DEBUG_EVENT, "event: No more traced programs: exiting");
39			exit(0);
40		} else if (errno == EINTR) {
41			debug(DEBUG_EVENT, "event: none (wait received EINTR?)");
42			event.type = EVENT_NONE;
43			return &event;
44		}
45		perror("wait");
46		exit(1);
47	}
48	event.proc = pid2proc(pid);
49	if (!event.proc || event.proc->state == STATE_BEING_CREATED) {
50		event.type = EVENT_NEW;
51		event.e_un.newpid = pid;
52		debug(DEBUG_EVENT, "event: NEW: pid=%d", pid);
53		return &event;
54	}
55	get_arch_dep(event.proc);
56	debug(3, "event from pid %u", pid);
57	if (event.proc->breakpoints_enabled == -1)
58		trace_set_options(event.proc, event.proc->pid);
59	Process *leader = event.proc->leader;
60	if (leader == event.proc) {
61		if (event.proc->breakpoints_enabled == -1) {
62			event.type = EVENT_NONE;
63			enable_all_breakpoints(event.proc);
64			continue_process(event.proc->pid);
65			debug(DEBUG_EVENT,
66			      "event: NONE: pid=%d (enabling breakpoints)",
67			      pid);
68			return &event;
69		} else if (!event.proc->libdl_hooked) {
70			/* debug struct may not have been written yet.. */
71			if (linkmap_init(event.proc, &main_lte) == 0) {
72				event.proc->libdl_hooked = 1;
73			}
74		}
75	}
76
77	event.proc->instruction_pointer = (void *)(uintptr_t)-1;
78
79	event.proc->instruction_pointer = get_instruction_pointer(event.proc);
80	if (event.proc->instruction_pointer == (void *)(uintptr_t)-1) {
81		if (errno != 0)
82			perror("get_instruction_pointer");
83	}
84
85	switch (syscall_p(event.proc, status, &tmp)) {
86		case 1:
87			event.type = EVENT_SYSCALL;
88			event.e_un.sysnum = tmp;
89			debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp);
90			return &event;
91		case 2:
92			event.type = EVENT_SYSRET;
93			event.e_un.sysnum = tmp;
94			debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp);
95			return &event;
96		case 3:
97			event.type = EVENT_ARCH_SYSCALL;
98			event.e_un.sysnum = tmp;
99			debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp);
100			return &event;
101		case 4:
102			event.type = EVENT_ARCH_SYSRET;
103			event.e_un.sysnum = tmp;
104			debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp);
105			return &event;
106		case -1:
107			event.type = EVENT_NONE;
108			continue_process(event.proc->pid);
109			debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid);
110			return &event;
111	}
112	if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
113		unsigned long data;
114		ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
115		event.type = EVENT_CLONE;
116		event.e_un.newpid = data;
117		debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data);
118		return &event;
119	}
120	if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
121		event.type = EVENT_EXEC;
122		debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid);
123		return &event;
124	}
125	if (WIFEXITED(status)) {
126		event.type = EVENT_EXIT;
127		event.e_un.ret_val = WEXITSTATUS(status);
128		debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val);
129		return &event;
130	}
131	if (WIFSIGNALED(status)) {
132		event.type = EVENT_EXIT_SIGNAL;
133		event.e_un.signum = WTERMSIG(status);
134		debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum);
135		return &event;
136	}
137	if (!WIFSTOPPED(status)) {
138		/* should never happen */
139		event.type = EVENT_NONE;
140		debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid);
141		return &event;
142	}
143
144	stop_signal = WSTOPSIG(status);
145
146	/* On some targets, breakpoints are signalled not using
147	   SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT.  SIGEMT
148	   is not defined on Linux, but check for the others.
149
150	   N.B. see comments in GDB's infrun.c for details.  I've
151	   actually seen this on an Itanium machine on RHEL 5, I don't
152	   remember the exact kernel version anymore.  ia64-sigill.s
153	   in the test suite tests this.  Petr Machata 2011-06-08.  */
154	void * break_address
155		= event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
156	if ((stop_signal == SIGSEGV || stop_signal == SIGILL)
157	    && leader != NULL
158	    && address2bpstruct(leader, break_address))
159			stop_signal = SIGTRAP;
160
161	if (stop_signal != (SIGTRAP | event.proc->tracesysgood)
162			&& stop_signal != SIGTRAP) {
163		event.type = EVENT_SIGNAL;
164		event.e_un.signum = stop_signal;
165		debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal);
166		return &event;
167	}
168
169	/* last case [by exhaustion] */
170	event.type = EVENT_BREAKPOINT;
171
172	event.e_un.brk_addr = break_address;
173	debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr);
174
175	return &event;
176}
177