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