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