events.c revision 1e583132c95aa211fab9e0e0869b237adfa78304
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 "debug.h" 17 18static struct event event; 19 20struct event * 21next_event(void) { 22 pid_t pid; 23 int status; 24 int tmp; 25 int stop_signal; 26 27 if (!list_of_processes) { 28 debug(1, "No more children"); 29 exit(0); 30 } 31 pid = wait(&status); 32 if (pid == -1) { 33 if (errno == ECHILD) { 34 debug(1, "No more children"); 35 exit(0); 36 } else if (errno == EINTR) { 37 debug(1, "wait received EINTR ?"); 38 event.thing = EVENT_NONE; 39 return &event; 40 } 41 perror("wait"); 42 exit(1); 43 } 44 event.proc = pid2proc(pid); 45 if (!event.proc) { 46 fprintf(stderr, "event from wrong pid %u ?!?\n", pid); 47 exit(1); 48 } 49 get_arch_dep(event.proc); 50 event.proc->instruction_pointer = NULL; 51 debug(3, "event from pid %u", pid); 52 if (event.proc->breakpoints_enabled == -1) { 53 enable_all_breakpoints(event.proc); 54 event.thing = EVENT_NONE; 55 trace_set_options(event.proc, event.proc->pid); 56 continue_process(event.proc->pid); 57 return &event; 58 } 59 if (opt_i) { 60 event.proc->instruction_pointer = 61 get_instruction_pointer(event.proc); 62 } 63 switch (syscall_p(event.proc, status, &tmp)) { 64 case 1: 65 event.thing = EVENT_SYSCALL; 66 event.e_un.sysnum = tmp; 67 return &event; 68 case 2: 69 event.thing = EVENT_SYSRET; 70 event.e_un.sysnum = tmp; 71 return &event; 72 case 3: 73 event.thing = EVENT_ARCH_SYSCALL; 74 event.e_un.sysnum = tmp; 75 return &event; 76 case 4: 77 event.thing = EVENT_ARCH_SYSRET; 78 event.e_un.sysnum = tmp; 79 return &event; 80 case -1: 81 event.thing = EVENT_NONE; 82 continue_process(event.proc->pid); 83 return &event; 84 } 85 if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) { 86 unsigned long data; 87 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data); 88 event.thing = EVENT_FORK; 89 event.e_un.newpid = data; 90 return &event; 91 } 92 /* TODO: check for EVENT_CLONE */ 93 if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) { 94 event.thing = EVENT_EXEC; 95 return &event; 96 } 97 if (WIFEXITED(status)) { 98 event.thing = EVENT_EXIT; 99 event.e_un.ret_val = WEXITSTATUS(status); 100 return &event; 101 } 102 if (WIFSIGNALED(status)) { 103 event.thing = EVENT_EXIT_SIGNAL; 104 event.e_un.signum = WTERMSIG(status); 105 return &event; 106 } 107 if (!WIFSTOPPED(status)) { 108 event.thing = 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.thing = 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.thing = 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.thing = 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