blob: b944cd614534000b14a07bec0bd62b7a0d7c21b4 [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>
Juan Cespedes5e01f651998-03-08 22:31:44 +010011
Juan Cespedesf7281232009-06-25 16:11:21 +020012#include "common.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010013
Juan Cespedes393f1d02009-05-07 11:13:54 +020014static Event event;
Juan Cespedes5e01f651998-03-08 22:31:44 +010015
Petr Machatacebb8842011-07-09 11:14:11 +020016static enum pcb_status
17first (Process * proc, void * data)
18{
19 return pcb_stop;
20}
21
Juan Cespedes393f1d02009-05-07 11:13:54 +020022Event *
Petr Machata26627682011-07-08 18:15:32 +020023next_event(void)
24{
Juan Cespedes5e01f651998-03-08 22:31:44 +010025 pid_t pid;
26 int status;
27 int tmp;
Petr Machataef46b3e2007-05-09 19:21:42 +020028 int stop_signal;
Juan Cespedes5e01f651998-03-08 22:31:44 +010029
Juan Cespedescd8976d2009-05-14 13:47:58 +020030 debug(DEBUG_FUNCTION, "next_event()");
Petr Machatacebb8842011-07-09 11:14:11 +020031 if (!each_process(NULL, &first, NULL)) {
Juan Cespedescd8976d2009-05-14 13:47:58 +020032 debug(DEBUG_EVENT, "event: No more traced programs: exiting");
Juan Cespedes28f60191998-04-12 00:04:39 +020033 exit(0);
34 }
Juan Cespedes6be80282009-05-28 19:06:00 +020035 pid = waitpid(-1, &status, __WALL);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010036 if (pid == -1) {
37 if (errno == ECHILD) {
Juan Cespedescd8976d2009-05-14 13:47:58 +020038 debug(DEBUG_EVENT, "event: No more traced programs: exiting");
Juan Cespedes5e01f651998-03-08 22:31:44 +010039 exit(0);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010040 } else if (errno == EINTR) {
Juan Cespedescd8976d2009-05-14 13:47:58 +020041 debug(DEBUG_EVENT, "event: none (wait received EINTR?)");
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +020042 event.type = EVENT_NONE;
Juan Cespedes28f60191998-04-12 00:04:39 +020043 return &event;
Juan Cespedes5e01f651998-03-08 22:31:44 +010044 }
45 perror("wait");
46 exit(1);
47 }
48 event.proc = pid2proc(pid);
Juan Cespedes2721e6a2009-05-21 15:15:40 +020049 if (!event.proc || event.proc->state == STATE_BEING_CREATED) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +020050 event.type = EVENT_NEW;
Juan Cespedes2721e6a2009-05-21 15:15:40 +020051 event.e_un.newpid = pid;
Juan Cespedescd8976d2009-05-14 13:47:58 +020052 debug(DEBUG_EVENT, "event: NEW: pid=%d", pid);
Juan Cespedesa8909f72009-04-28 20:02:41 +020053 return &event;
Juan Cespedes5e01f651998-03-08 22:31:44 +010054 }
Juan Cespedes5c3fe062004-06-14 18:08:37 +020055 get_arch_dep(event.proc);
Juan Cespedes1e583132009-04-07 18:17:11 +020056 debug(3, "event from pid %u", pid);
Petr Machata9a5420c2011-07-09 11:21:23 +020057 if (event.proc->breakpoints_enabled == -1)
Ian Wienand9a2ad352006-02-20 22:44:45 +010058 trace_set_options(event.proc, event.proc->pid);
Petr Machata9a5420c2011-07-09 11:21:23 +020059 Process *leader = event.proc->leader;
60 if (leader == event.proc) {
61 if (event.proc->breakpoints_enabled == -1) {
62 event.type = EVENT_NONE;
63 enable_all_breakpoints(event.proc);
64 continue_process(event.proc->pid);
65 debug(DEBUG_EVENT,
66 "event: NONE: pid=%d (enabling breakpoints)",
67 pid);
68 return &event;
69 } else if (!event.proc->libdl_hooked) {
70 /* debug struct may not have been written yet.. */
71 if (linkmap_init(event.proc, &main_lte) == 0) {
72 event.proc->libdl_hooked = 1;
73 }
Joe Damatof0bd98b2010-11-08 15:47:42 -080074 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010075 }
Joe Damatof0bd98b2010-11-08 15:47:42 -080076
Petr Machata9a5420c2011-07-09 11:21:23 +020077 event.proc->instruction_pointer = (void *)(uintptr_t)-1;
Petr Machata6901b7e2011-07-09 11:00:33 +020078
79 event.proc->instruction_pointer = get_instruction_pointer(event.proc);
80 if (event.proc->instruction_pointer == (void *)(uintptr_t)-1) {
81 if (errno != 0)
82 perror("get_instruction_pointer");
Juan Cespedesf0fdae91998-03-11 00:03:00 +010083 }
Petr Machata6901b7e2011-07-09 11:00:33 +020084
Ian Wienand2d45b1a2006-02-20 22:48:07 +010085 switch (syscall_p(event.proc, status, &tmp)) {
Juan Cespedes63184be2008-12-10 13:30:12 +010086 case 1:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +020087 event.type = EVENT_SYSCALL;
Juan Cespedes63184be2008-12-10 13:30:12 +010088 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +020089 debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +010090 return &event;
91 case 2:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +020092 event.type = EVENT_SYSRET;
Juan Cespedes63184be2008-12-10 13:30:12 +010093 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +020094 debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +010095 return &event;
96 case 3:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +020097 event.type = EVENT_ARCH_SYSCALL;
Juan Cespedes63184be2008-12-10 13:30:12 +010098 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +020099 debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +0100100 return &event;
101 case 4:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200102 event.type = EVENT_ARCH_SYSRET;
Juan Cespedes63184be2008-12-10 13:30:12 +0100103 event.e_un.sysnum = tmp;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200104 debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp);
Juan Cespedes63184be2008-12-10 13:30:12 +0100105 return &event;
106 case -1:
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200107 event.type = EVENT_NONE;
Juan Cespedes63184be2008-12-10 13:30:12 +0100108 continue_process(event.proc->pid);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200109 debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid);
Juan Cespedes63184be2008-12-10 13:30:12 +0100110 return &event;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100111 }
Juan Cespedes1e583132009-04-07 18:17:11 +0200112 if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
113 unsigned long data;
114 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200115 event.type = EVENT_CLONE;
Juan Cespedes1e583132009-04-07 18:17:11 +0200116 event.e_un.newpid = data;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200117 debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data);
Juan Cespedes1e583132009-04-07 18:17:11 +0200118 return &event;
119 }
Juan Cespedes1e583132009-04-07 18:17:11 +0200120 if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200121 event.type = EVENT_EXEC;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200122 debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid);
Juan Cespedes1e583132009-04-07 18:17:11 +0200123 return &event;
124 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100125 if (WIFEXITED(status)) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200126 event.type = EVENT_EXIT;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100127 event.e_un.ret_val = WEXITSTATUS(status);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200128 debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100129 return &event;
130 }
131 if (WIFSIGNALED(status)) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200132 event.type = EVENT_EXIT_SIGNAL;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100133 event.e_un.signum = WTERMSIG(status);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200134 debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100135 return &event;
136 }
137 if (!WIFSTOPPED(status)) {
Juan Cespedes427b7812009-07-06 23:05:30 +0200138 /* should never happen */
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200139 event.type = EVENT_NONE;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200140 debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100141 return &event;
142 }
Petr Machataef46b3e2007-05-09 19:21:42 +0200143
144 stop_signal = WSTOPSIG(status);
145
146 /* On some targets, breakpoints are signalled not using
Petr Machata6901b7e2011-07-09 11:00:33 +0200147 SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT. SIGEMT
148 is not defined on Linux, but check for the others.
Petr Machataef46b3e2007-05-09 19:21:42 +0200149
Petr Machata6901b7e2011-07-09 11:00:33 +0200150 N.B. see comments in GDB's infrun.c for details. I've
151 actually seen this on an Itanium machine on RHEL 5, I don't
152 remember the exact kernel version anymore. ia64-sigill.s
153 in the test suite tests this. Petr Machata 2011-06-08. */
154 void * break_address
155 = event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
156 if ((stop_signal == SIGSEGV || stop_signal == SIGILL)
Petr Machata9a5420c2011-07-09 11:21:23 +0200157 && leader != NULL
158 && address2bpstruct(leader, break_address))
Petr Machataef46b3e2007-05-09 19:21:42 +0200159 stop_signal = SIGTRAP;
Petr Machataef46b3e2007-05-09 19:21:42 +0200160
161 if (stop_signal != (SIGTRAP | event.proc->tracesysgood)
Juan Cespedes427b7812009-07-06 23:05:30 +0200162 && stop_signal != SIGTRAP) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200163 event.type = EVENT_SIGNAL;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200164 event.e_un.signum = stop_signal;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200165 debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100166 return &event;
167 }
Petr Machata55ed83b2007-05-17 16:24:15 +0200168
Juan Cespedes427b7812009-07-06 23:05:30 +0200169 /* last case [by exhaustion] */
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200170 event.type = EVENT_BREAKPOINT;
Juan Cespedes427b7812009-07-06 23:05:30 +0200171
Petr Machata6901b7e2011-07-09 11:00:33 +0200172 event.e_un.brk_addr = break_address;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200173 debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr);
Petr Machata6901b7e2011-07-09 11:00:33 +0200174
Juan Cespedes5e01f651998-03-08 22:31:44 +0100175 return &event;
176}