events.c revision f670eea50e959eeb9da53d70cad8d43c19494ef0
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		enable_all_breakpoints(event.proc);
53		event.type = EVENT_NONE;
54		trace_set_options(event.proc, event.proc->pid);
55		continue_process(event.proc->pid);
56		debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling breakpoints)", pid);
57		return &event;
58	}
59	if (opt_i) {
60		event.proc->instruction_pointer =
61			get_instruction_pointer(event.proc);
62	}
63	switch (syscall_p(event.proc, status, &tmp)) {
64		case 1:
65			event.type = EVENT_SYSCALL;
66			event.e_un.sysnum = tmp;
67			debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp);
68			return &event;
69		case 2:
70			event.type = EVENT_SYSRET;
71			event.e_un.sysnum = tmp;
72			debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp);
73			return &event;
74		case 3:
75			event.type = EVENT_ARCH_SYSCALL;
76			event.e_un.sysnum = tmp;
77			debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp);
78			return &event;
79		case 4:
80			event.type = EVENT_ARCH_SYSRET;
81			event.e_un.sysnum = tmp;
82			debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp);
83			return &event;
84		case -1:
85			event.type = EVENT_NONE;
86			continue_process(event.proc->pid);
87			debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid);
88			return &event;
89	}
90	if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
91		unsigned long data;
92		ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
93		event.type = EVENT_CLONE;
94		event.e_un.newpid = data;
95		debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data);
96		return &event;
97	}
98	if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
99		event.type = EVENT_EXEC;
100		debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid);
101		return &event;
102	}
103	if (WIFEXITED(status)) {
104		event.type = EVENT_EXIT;
105		event.e_un.ret_val = WEXITSTATUS(status);
106		debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val);
107		return &event;
108	}
109	if (WIFSIGNALED(status)) {
110		event.type = EVENT_EXIT_SIGNAL;
111		event.e_un.signum = WTERMSIG(status);
112		debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum);
113		return &event;
114	}
115	if (!WIFSTOPPED(status)) {
116		/* should never happen */
117		event.type = EVENT_NONE;
118		debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid);
119		return &event;
120	}
121
122	stop_signal = WSTOPSIG(status);
123
124	/* On some targets, breakpoints are signalled not using
125	   SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT.  Check
126	   for these. (TODO: is this true?) */
127	if (stop_signal == SIGSEGV
128			|| stop_signal == SIGILL
129#ifdef SIGEMT
130			|| stop_signal == SIGEMT
131#endif
132	   ) {
133		if (!event.proc->instruction_pointer) {
134			event.proc->instruction_pointer =
135				get_instruction_pointer(event.proc);
136		}
137
138		if (address2bpstruct(event.proc, event.proc->instruction_pointer))
139			stop_signal = SIGTRAP;
140	}
141
142	if (stop_signal != (SIGTRAP | event.proc->tracesysgood)
143			&& stop_signal != SIGTRAP) {
144		event.type = EVENT_SIGNAL;
145		event.e_un.signum = stop_signal;
146		debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal);
147		return &event;
148	}
149
150	/* last case [by exhaustion] */
151	event.type = EVENT_BREAKPOINT;
152
153	if (!event.proc->instruction_pointer) {
154		event.proc->instruction_pointer =
155			get_instruction_pointer(event.proc);
156	}
157	event.e_un.brk_addr =
158		event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
159	debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr);
160	return &event;
161}
162