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