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