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