events.c revision cd8976dbee947f152c3a322503a1063c6359da76
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 "ltrace.h"
15#include "options.h"
16#include "output.h"
17#include "debug.h"
18
19static Event event;
20
21Event *
22next_event(void) {
23	pid_t pid;
24	int status;
25	int tmp;
26	int stop_signal;
27
28	debug(DEBUG_FUNCTION, "next_event()");
29	if (!list_of_processes) {
30		debug(DEBUG_EVENT, "event: No more traced programs: exiting");
31		exit(0);
32	}
33	pid = wait(&status);
34	if (pid == -1) {
35		if (errno == ECHILD) {
36			debug(DEBUG_EVENT, "event: No more traced programs: exiting");
37			exit(0);
38		} else if (errno == EINTR) {
39			debug(DEBUG_EVENT, "event: none (wait received EINTR?)");
40			event.type = EVENT_NONE;
41			return &event;
42		}
43		perror("wait");
44		exit(1);
45	}
46	event.proc = pid2proc(pid);
47	if (!event.proc) {
48		event.type = EVENT_NEW;
49		debug(DEBUG_EVENT, "event: NEW: pid=%d", pid);
50		return &event;
51	}
52	get_arch_dep(event.proc);
53	event.proc->instruction_pointer = NULL;
54	debug(3, "event from pid %u", pid);
55	if (event.proc->breakpoints_enabled == -1) {
56		enable_all_breakpoints(event.proc);
57		event.type = EVENT_NONE;
58		trace_set_options(event.proc, event.proc->pid);
59		continue_process(event.proc->pid);
60		debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling breakpoints)", pid);
61		return &event;
62	}
63	if (opt_i) {
64		event.proc->instruction_pointer =
65		    get_instruction_pointer(event.proc);
66	}
67	switch (syscall_p(event.proc, status, &tmp)) {
68		case 1:
69			event.type = EVENT_SYSCALL;
70			event.e_un.sysnum = tmp;
71			debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp);
72			return &event;
73		case 2:
74			event.type = EVENT_SYSRET;
75			event.e_un.sysnum = tmp;
76			debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp);
77			return &event;
78		case 3:
79			event.type = EVENT_ARCH_SYSCALL;
80			event.e_un.sysnum = tmp;
81			debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp);
82			return &event;
83		case 4:
84			event.type = EVENT_ARCH_SYSRET;
85			event.e_un.sysnum = tmp;
86			debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp);
87			return &event;
88		case -1:
89			event.type = EVENT_NONE;
90			continue_process(event.proc->pid);
91			debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid);
92			return &event;
93	}
94	if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
95		unsigned long data;
96		ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
97		event.type = EVENT_CLONE;
98		event.e_un.newpid = data;
99		debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data);
100		return &event;
101	}
102	if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
103		event.type = EVENT_EXEC;
104		debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid);
105		return &event;
106	}
107	if (WIFEXITED(status)) {
108		event.type = EVENT_EXIT;
109		event.e_un.ret_val = WEXITSTATUS(status);
110		debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val);
111		return &event;
112	}
113	if (WIFSIGNALED(status)) {
114		event.type = EVENT_EXIT_SIGNAL;
115		event.e_un.signum = WTERMSIG(status);
116		debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum);
117		return &event;
118	}
119	if (!WIFSTOPPED(status)) {
120		event.type = EVENT_NONE;
121		debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid);
122		return &event;
123	}
124
125	stop_signal = WSTOPSIG(status);
126
127	/* On some targets, breakpoints are signalled not using
128	   SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT.  Check
129	   for these. */
130	if (stop_signal == SIGSEGV
131	    || stop_signal == SIGILL
132#ifdef SIGEMT
133	    || stop_signal == SIGEMT
134#endif
135	    ) {
136		// If we didn't need to know IP so far, get it now.
137		void * addr = opt_i
138		  ? event.proc->instruction_pointer
139		  : (event.proc->instruction_pointer = get_instruction_pointer (event.proc));
140
141		if (address2bpstruct(event.proc, addr))
142			stop_signal = SIGTRAP;
143	}
144
145	if (stop_signal != (SIGTRAP | event.proc->tracesysgood)
146	    && stop_signal != SIGTRAP) {
147		event.type = EVENT_SIGNAL;
148		event.e_un.signum = stop_signal;
149		debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal);
150		return &event;
151	}
152
153	if (was_exec(event.proc, status)) {
154		pid_t saved_pid;
155
156		event.type = EVENT_NONE;
157		event.e_un.signum = WSTOPSIG(status);
158		debug(1, "Placing breakpoints for the new program");
159		event.proc->mask_32bit = 0;
160		event.proc->personality = 0;
161		event.proc->arch_ptr = NULL;
162		event.proc->filename = pid2name(event.proc->pid);
163		saved_pid = event.proc->pid;
164		event.proc->pid = 0;
165		breakpoints_init(event.proc);
166		event.proc->pid = saved_pid;
167		continue_process(event.proc->pid);
168		debug(DEBUG_EVENT, "event: NONE: pid=%d (was_exec; placed breakpoints)", pid);
169		return &event;
170	}
171
172	event.type = EVENT_BREAKPOINT;
173	if (!event.proc->instruction_pointer) {
174		event.proc->instruction_pointer =
175		    get_instruction_pointer(event.proc);
176	}
177	event.e_un.brk_addr =
178	    event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
179	debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr);
180	return &event;
181}
182