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