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