blob: 909fbf2d3c8703d36f7a210bae6244435d38cff8 [file] [log] [blame]
Juan Cespedesd44c6b81998-09-25 14:48:42 +02001#include "config.h"
Juan Cespedesd44c6b81998-09-25 14:48:42 +02002
Juan Cespedes5e01f651998-03-08 22:31:44 +01003#define _GNU_SOURCE 1
Juan Cespedes1cd999a2001-07-03 00:46:04 +02004#include <stdlib.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +01005#include <sys/types.h>
6#include <sys/wait.h>
7#include <errno.h>
8#include <signal.h>
9#include <string.h>
Juan Cespedes1e583132009-04-07 18:17:11 +020010#include <sys/ptrace.h>
Petr Machata69a03e62011-07-09 11:29:12 +020011#include <assert.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +010012
Juan Cespedesf7281232009-06-25 16:11:21 +020013#include "common.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010014
Juan Cespedes393f1d02009-05-07 11:13:54 +020015static Event event;
Juan Cespedes5e01f651998-03-08 22:31:44 +010016
Petr Machata69a03e62011-07-09 11:29:12 +020017/* A queue of events that we missed while enabling the
18 * breakpoint in one of tasks. */
19static Event * delayed_events = NULL;
20static Event * end_delayed_events = NULL;
21
Petr Machatacebb8842011-07-09 11:14:11 +020022static enum pcb_status
23first (Process * proc, void * data)
24{
25 return pcb_stop;
26}
27
Petr Machata69a03e62011-07-09 11:29:12 +020028void
29enque_event(Event * event)
30{
31 debug(DEBUG_FUNCTION, "%d: queuing event %d for later",
32 event->proc->pid, event->type);
33 Event * ne = malloc(sizeof(*ne));
34 if (ne == NULL) {
35 perror("event will be missed: malloc");
36 return;
37 }
38
39 *ne = *event;
40 ne->next = NULL;
41 if (end_delayed_events == NULL) {
42 assert(delayed_events == NULL);
43 end_delayed_events = delayed_events = ne;
44 }
45 else {
46 assert(delayed_events != NULL);
47 end_delayed_events = end_delayed_events->next = ne;
48 }
49}
50
51Event *
52each_qd_event(enum ecb_status (*pred)(Event *, void *), void * data)
53{
54 Event * prev = delayed_events;
55 Event * event;
56 for (event = prev; event != NULL; ) {
57 switch ((*pred)(event, data)) {
58 case ecb_cont:
59 prev = event;
60 event = event->next;
61 continue;
62
63 case ecb_deque:
64 debug(DEBUG_FUNCTION, "dequeuing event %d for %d",
65 event->type,
66 event->proc != NULL ? event->proc->pid : -1);
67 /*
68 printf("dequeuing event %d for %d\n", event->type,
69 event->proc != NULL ? event->proc->pid : -1) ;
70 */
71 if (end_delayed_events == event)
72 end_delayed_events = prev;
73 if (delayed_events == event)
74 delayed_events = event->next;
75 else
76 prev->next = event->next;
77 if (delayed_events == NULL)
78 end_delayed_events = NULL;
79 /* fall-through */
80
81 case ecb_yield:
82 return event;
83 }
84 }
85
86 return NULL;
87}
88
89static enum ecb_status
90event_process_not_reenabling(Event * event, void * data)
91{
Petr Machata4007d742011-07-09 11:29:42 +020092 if (event->proc == NULL
93 || event->proc->leader == NULL
94 || event->proc->leader->event_handler == NULL)
95 return ecb_deque;
96 else
97 return ecb_cont;
Petr Machata69a03e62011-07-09 11:29:12 +020098}
99
100static Event *
101next_qd_event(void)
102{
103 return each_qd_event(&event_process_not_reenabling, NULL);
104}
105
Juan Cespedes393f1d02009-05-07 11:13:54 +0200106Event *
Petr Machata26627682011-07-08 18:15:32 +0200107next_event(void)
108{
Juan Cespedes5e01f651998-03-08 22:31:44 +0100109 pid_t pid;
110 int status;
111 int tmp;
Petr Machataef46b3e2007-05-09 19:21:42 +0200112 int stop_signal;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100113
Juan Cespedescd8976d2009-05-14 13:47:58 +0200114 debug(DEBUG_FUNCTION, "next_event()");
Petr Machata69a03e62011-07-09 11:29:12 +0200115 Event * ev;
116 if ((ev = next_qd_event()) != NULL) {
117 event = *ev;
118 free(ev);
119 return &event;
120 }
121
Petr Machatacebb8842011-07-09 11:14:11 +0200122 if (!each_process(NULL, &first, NULL)) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200123 debug(DEBUG_EVENT, "event: No more traced programs: exiting");
Juan Cespedes28f60191998-04-12 00:04:39 +0200124 exit(0);
125 }
Juan Cespedes6be80282009-05-28 19:06:00 +0200126 pid = waitpid(-1, &status, __WALL);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100127 if (pid == -1) {
128 if (errno == ECHILD) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200129 debug(DEBUG_EVENT, "event: No more traced programs: exiting");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100130 exit(0);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100131 } else if (errno == EINTR) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200132 debug(DEBUG_EVENT, "event: none (wait received EINTR?)");
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200133 event.type = EVENT_NONE;
Juan Cespedes28f60191998-04-12 00:04:39 +0200134 return &event;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100135 }
136 perror("wait");
137 exit(1);
138 }
139 event.proc = pid2proc(pid);
Juan Cespedes2721e6a2009-05-21 15:15:40 +0200140 if (!event.proc || event.proc->state == STATE_BEING_CREATED) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200141 event.type = EVENT_NEW;
Juan Cespedes2721e6a2009-05-21 15:15:40 +0200142 event.e_un.newpid = pid;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200143 debug(DEBUG_EVENT, "event: NEW: pid=%d", pid);
Juan Cespedesa8909f72009-04-28 20:02:41 +0200144 return &event;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100145 }
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200146 get_arch_dep(event.proc);
Juan Cespedes1e583132009-04-07 18:17:11 +0200147 debug(3, "event from pid %u", pid);
Petr Machata9a5420c2011-07-09 11:21:23 +0200148 if (event.proc->breakpoints_enabled == -1)
Ian Wienand9a2ad352006-02-20 22:44:45 +0100149 trace_set_options(event.proc, event.proc->pid);
Petr Machata9a5420c2011-07-09 11:21:23 +0200150 Process *leader = event.proc->leader;
151 if (leader == event.proc) {
152 if (event.proc->breakpoints_enabled == -1) {
153 event.type = EVENT_NONE;
154 enable_all_breakpoints(event.proc);
155 continue_process(event.proc->pid);
156 debug(DEBUG_EVENT,
157 "event: NONE: pid=%d (enabling breakpoints)",
158 pid);
159 return &event;
160 } else if (!event.proc->libdl_hooked) {
161 /* debug struct may not have been written yet.. */
162 if (linkmap_init(event.proc, &main_lte) == 0) {
163 event.proc->libdl_hooked = 1;
164 }
Joe Damatof0bd98b2010-11-08 15:47:42 -0800165 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100166 }
Joe Damatof0bd98b2010-11-08 15:47:42 -0800167
Petr Machata9a5420c2011-07-09 11:21:23 +0200168 event.proc->instruction_pointer = (void *)(uintptr_t)-1;
Petr Machata6901b7e2011-07-09 11:00:33 +0200169
170 event.proc->instruction_pointer = get_instruction_pointer(event.proc);
171 if (event.proc->instruction_pointer == (void *)(uintptr_t)-1) {
172 if (errno != 0)
173 perror("get_instruction_pointer");
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100174 }
Petr Machata6901b7e2011-07-09 11:00:33 +0200175
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100176 switch (syscall_p(event.proc, status, &tmp)) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100177 case 1:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200178 event.type = EVENT_SYSCALL;
Juan Cespedes63184be2008-12-10 13:30:12 +0100179 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200180 debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +0100181 return &event;
182 case 2:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200183 event.type = EVENT_SYSRET;
Juan Cespedes63184be2008-12-10 13:30:12 +0100184 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200185 debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +0100186 return &event;
187 case 3:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200188 event.type = EVENT_ARCH_SYSCALL;
Juan Cespedes63184be2008-12-10 13:30:12 +0100189 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200190 debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +0100191 return &event;
192 case 4:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200193 event.type = EVENT_ARCH_SYSRET;
Juan Cespedes63184be2008-12-10 13:30:12 +0100194 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200195 debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +0100196 return &event;
197 case -1:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200198 event.type = EVENT_NONE;
Juan Cespedes63184be2008-12-10 13:30:12 +0100199 continue_process(event.proc->pid);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200200 debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid);
Juan Cespedes63184be2008-12-10 13:30:12 +0100201 return &event;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100202 }
Juan Cespedes1e583132009-04-07 18:17:11 +0200203 if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
204 unsigned long data;
205 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200206 event.type = EVENT_CLONE;
Juan Cespedes1e583132009-04-07 18:17:11 +0200207 event.e_un.newpid = data;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200208 debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data);
Juan Cespedes1e583132009-04-07 18:17:11 +0200209 return &event;
210 }
Juan Cespedes1e583132009-04-07 18:17:11 +0200211 if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200212 event.type = EVENT_EXEC;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200213 debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid);
Juan Cespedes1e583132009-04-07 18:17:11 +0200214 return &event;
215 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100216 if (WIFEXITED(status)) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200217 event.type = EVENT_EXIT;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100218 event.e_un.ret_val = WEXITSTATUS(status);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200219 debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100220 return &event;
221 }
222 if (WIFSIGNALED(status)) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200223 event.type = EVENT_EXIT_SIGNAL;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100224 event.e_un.signum = WTERMSIG(status);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200225 debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100226 return &event;
227 }
228 if (!WIFSTOPPED(status)) {
Juan Cespedes427b7812009-07-06 23:05:30 +0200229 /* should never happen */
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200230 event.type = EVENT_NONE;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200231 debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100232 return &event;
233 }
Petr Machataef46b3e2007-05-09 19:21:42 +0200234
235 stop_signal = WSTOPSIG(status);
236
237 /* On some targets, breakpoints are signalled not using
Petr Machata6901b7e2011-07-09 11:00:33 +0200238 SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT. SIGEMT
239 is not defined on Linux, but check for the others.
Petr Machataef46b3e2007-05-09 19:21:42 +0200240
Petr Machata6901b7e2011-07-09 11:00:33 +0200241 N.B. see comments in GDB's infrun.c for details. I've
242 actually seen this on an Itanium machine on RHEL 5, I don't
243 remember the exact kernel version anymore. ia64-sigill.s
244 in the test suite tests this. Petr Machata 2011-06-08. */
245 void * break_address
246 = event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
247 if ((stop_signal == SIGSEGV || stop_signal == SIGILL)
Petr Machata9a5420c2011-07-09 11:21:23 +0200248 && leader != NULL
249 && address2bpstruct(leader, break_address))
Petr Machataef46b3e2007-05-09 19:21:42 +0200250 stop_signal = SIGTRAP;
Petr Machataef46b3e2007-05-09 19:21:42 +0200251
252 if (stop_signal != (SIGTRAP | event.proc->tracesysgood)
Juan Cespedes427b7812009-07-06 23:05:30 +0200253 && stop_signal != SIGTRAP) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200254 event.type = EVENT_SIGNAL;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200255 event.e_un.signum = stop_signal;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200256 debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100257 return &event;
258 }
Petr Machata55ed83b2007-05-17 16:24:15 +0200259
Juan Cespedes427b7812009-07-06 23:05:30 +0200260 /* last case [by exhaustion] */
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200261 event.type = EVENT_BREAKPOINT;
Juan Cespedes427b7812009-07-06 23:05:30 +0200262
Petr Machata6901b7e2011-07-09 11:00:33 +0200263 event.e_un.brk_addr = break_address;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200264 debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr);
Petr Machata6901b7e2011-07-09 11:00:33 +0200265
Juan Cespedes5e01f651998-03-08 22:31:44 +0100266 return &event;
267}