events.c revision 393f1d00c582058078cc238547f65202c438fb19
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	if (!list_of_processes) {
29		debug(1, "No more children");
30		exit(0);
31	}
32	pid = wait(&status);
33	if (pid == -1) {
34		if (errno == ECHILD) {
35			debug(1, "No more children");
36			exit(0);
37		} else if (errno == EINTR) {
38			debug(1, "wait received EINTR ?");
39			event.thing = EVENT_NONE;
40			return &event;
41		}
42		perror("wait");
43		exit(1);
44	}
45	event.proc = pid2proc(pid);
46	if (!event.proc) {
47		output_line(NULL, "event from wrong pid %u ?!?\n", pid);
48//		exit(1);
49		event.thing = EVENT_NONE;
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.thing = EVENT_NONE;
58		trace_set_options(event.proc, event.proc->pid);
59		continue_process(event.proc->pid);
60		return &event;
61	}
62	if (opt_i) {
63		event.proc->instruction_pointer =
64		    get_instruction_pointer(event.proc);
65	}
66	switch (syscall_p(event.proc, status, &tmp)) {
67		case 1:
68			event.thing = EVENT_SYSCALL;
69			event.e_un.sysnum = tmp;
70			return &event;
71		case 2:
72			event.thing = EVENT_SYSRET;
73			event.e_un.sysnum = tmp;
74			return &event;
75		case 3:
76			event.thing = EVENT_ARCH_SYSCALL;
77			event.e_un.sysnum = tmp;
78			return &event;
79		case 4:
80			event.thing = EVENT_ARCH_SYSRET;
81			event.e_un.sysnum = tmp;
82			return &event;
83		case -1:
84			event.thing = EVENT_NONE;
85			continue_process(event.proc->pid);
86			return &event;
87	}
88	if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
89		unsigned long data;
90		ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
91		event.thing = EVENT_FORK;
92		event.e_un.newpid = data;
93		return &event;
94	}
95	/* TODO: check for EVENT_CLONE */
96	if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
97		event.thing = EVENT_EXEC;
98		return &event;
99	}
100	if (WIFEXITED(status)) {
101		event.thing = EVENT_EXIT;
102		event.e_un.ret_val = WEXITSTATUS(status);
103		return &event;
104	}
105	if (WIFSIGNALED(status)) {
106		event.thing = EVENT_EXIT_SIGNAL;
107		event.e_un.signum = WTERMSIG(status);
108		return &event;
109	}
110	if (!WIFSTOPPED(status)) {
111		event.thing = EVENT_NONE;
112		return &event;
113	}
114
115	stop_signal = WSTOPSIG(status);
116
117	/* On some targets, breakpoints are signalled not using
118	   SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT.  Check
119	   for these. */
120	if (stop_signal == SIGSEGV
121	    || stop_signal == SIGILL
122#ifdef SIGEMT
123	    || stop_signal == SIGEMT
124#endif
125	    ) {
126		// If we didn't need to know IP so far, get it now.
127		void * addr = opt_i
128		  ? event.proc->instruction_pointer
129		  : (event.proc->instruction_pointer = get_instruction_pointer (event.proc));
130
131		if (address2bpstruct(event.proc, addr))
132			stop_signal = SIGTRAP;
133	}
134
135	if (stop_signal != (SIGTRAP | event.proc->tracesysgood)
136	    && stop_signal != SIGTRAP) {
137		event.thing = EVENT_SIGNAL;
138		event.e_un.signum = stop_signal;
139		return &event;
140	}
141
142	if (was_exec(event.proc, status)) {
143		pid_t saved_pid;
144
145		event.thing = EVENT_NONE;
146		event.e_un.signum = WSTOPSIG(status);
147		debug(1, "Placing breakpoints for the new program");
148		event.proc->mask_32bit = 0;
149		event.proc->personality = 0;
150		event.proc->arch_ptr = NULL;
151		event.proc->filename = pid2name(event.proc->pid);
152		saved_pid = event.proc->pid;
153		event.proc->pid = 0;
154		breakpoints_init(event.proc);
155		event.proc->pid = saved_pid;
156		continue_process(event.proc->pid);
157		return &event;
158	}
159
160	event.thing = EVENT_BREAKPOINT;
161	if (!event.proc->instruction_pointer) {
162		event.proc->instruction_pointer =
163		    get_instruction_pointer(event.proc);
164	}
165	event.e_un.brk_addr =
166	    event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
167	return &event;
168}
169