trace.c revision 9a5420c82a2fd81681572a2e3859ea1671c3bded
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <errno.h> 5#include <unistd.h> 6#include <sys/types.h> 7#include <sys/wait.h> 8#include "ptrace.h" 9#include <asm/unistd.h> 10#include <assert.h> 11 12#include "common.h" 13 14/* If the system headers did not provide the constants, hard-code the normal 15 values. */ 16#ifndef PTRACE_EVENT_FORK 17 18#define PTRACE_OLDSETOPTIONS 21 19#define PTRACE_SETOPTIONS 0x4200 20#define PTRACE_GETEVENTMSG 0x4201 21 22/* options set using PTRACE_SETOPTIONS */ 23#define PTRACE_O_TRACESYSGOOD 0x00000001 24#define PTRACE_O_TRACEFORK 0x00000002 25#define PTRACE_O_TRACEVFORK 0x00000004 26#define PTRACE_O_TRACECLONE 0x00000008 27#define PTRACE_O_TRACEEXEC 0x00000010 28#define PTRACE_O_TRACEVFORKDONE 0x00000020 29#define PTRACE_O_TRACEEXIT 0x00000040 30 31/* Wait extended result codes for the above trace options. */ 32#define PTRACE_EVENT_FORK 1 33#define PTRACE_EVENT_VFORK 2 34#define PTRACE_EVENT_CLONE 3 35#define PTRACE_EVENT_EXEC 4 36#define PTRACE_EVENT_VFORK_DONE 5 37#define PTRACE_EVENT_EXIT 6 38 39#endif /* PTRACE_EVENT_FORK */ 40 41#ifdef ARCH_HAVE_UMOVELONG 42extern int arch_umovelong (Process *, void *, long *, arg_type_info *); 43int 44umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { 45 return arch_umovelong (proc, addr, result, info); 46} 47#else 48/* Read a single long from the process's memory address 'addr' */ 49int 50umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { 51 long pointed_to; 52 53 errno = 0; 54 pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); 55 if (pointed_to == -1 && errno) 56 return -errno; 57 58 *result = pointed_to; 59 if (info) { 60 switch(info->type) { 61 case ARGTYPE_INT: 62 *result &= 0x00000000ffffffffUL; 63 default: 64 break; 65 }; 66 } 67 return 0; 68} 69#endif 70 71void 72trace_me(void) { 73 debug(DEBUG_PROCESS, "trace_me: pid=%d", getpid()); 74 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { 75 perror("PTRACE_TRACEME"); 76 exit(1); 77 } 78} 79 80int 81trace_pid(pid_t pid) { 82 debug(DEBUG_PROCESS, "trace_pid: pid=%d", pid); 83 if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) { 84 return -1; 85 } 86 87 /* man ptrace: PTRACE_ATTACH attaches to the process specified 88 in pid. The child is sent a SIGSTOP, but will not 89 necessarily have stopped by the completion of this call; 90 use wait() to wait for the child to stop. */ 91 if (waitpid (pid, NULL, __WALL) != pid) { 92 perror ("trace_pid: waitpid"); 93 return -1; 94 } 95 96 return 0; 97} 98 99void 100trace_set_options(Process *proc, pid_t pid) { 101 if (proc->tracesysgood & 0x80) 102 return; 103 104 debug(DEBUG_PROCESS, "trace_set_options: pid=%d", pid); 105 106 long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK | 107 PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | 108 PTRACE_O_TRACEEXEC; 109 if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 && 110 ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) { 111 perror("PTRACE_SETOPTIONS"); 112 return; 113 } 114 proc->tracesysgood |= 0x80; 115} 116 117void 118untrace_pid(pid_t pid) { 119 debug(DEBUG_PROCESS, "untrace_pid: pid=%d", pid); 120 ptrace(PTRACE_DETACH, pid, 1, 0); 121} 122 123void 124continue_after_signal(pid_t pid, int signum) { 125 Process *proc; 126 127 debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", pid, signum); 128 129 proc = pid2proc(pid); 130 if (proc && proc->breakpoint_being_enabled) { 131#if defined __sparc__ || defined __ia64___ || defined __mips__ 132 ptrace(PTRACE_SYSCALL, pid, 0, signum); 133#else 134 ptrace(PTRACE_SINGLESTEP, pid, 0, signum); 135#endif 136 } else { 137 ptrace(PTRACE_SYSCALL, pid, 0, signum); 138 } 139} 140 141void 142continue_process(pid_t pid) { 143 /* We always trace syscalls to control fork(), clone(), execve()... */ 144 145 debug(DEBUG_PROCESS, "continue_process: pid=%d", pid); 146 147 ptrace(PTRACE_SYSCALL, pid, 0, 0); 148} 149 150void 151continue_enabling_breakpoint(Process * proc, Breakpoint *sbp) 152{ 153 enable_breakpoint(proc, sbp); 154 continue_process(proc->pid); 155} 156 157void 158continue_after_breakpoint(Process *proc, Breakpoint *sbp) 159{ 160 if (sbp->enabled) 161 disable_breakpoint(proc, sbp); 162 163 set_instruction_pointer(proc, sbp->addr); 164 if (sbp->enabled == 0) { 165 continue_process(proc->pid); 166 } else { 167 debug(DEBUG_PROCESS, 168 "continue_after_breakpoint: pid=%d, addr=%p", 169 proc->pid, sbp->addr); 170 proc->breakpoint_being_enabled = sbp; 171#if defined __sparc__ || defined __ia64___ || defined __mips__ 172 /* we don't want to singlestep here */ 173 continue_process(proc->pid); 174#else 175 ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0); 176#endif 177 } 178} 179 180size_t 181umovebytes(Process *proc, void *addr, void *laddr, size_t len) { 182 183 union { 184 long a; 185 char c[sizeof(long)]; 186 } a; 187 int started = 0; 188 size_t offset = 0, bytes_read = 0; 189 190 while (offset < len) { 191 a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0); 192 if (a.a == -1 && errno) { 193 if (started && errno == EIO) 194 return bytes_read; 195 else 196 return -1; 197 } 198 started = 1; 199 200 if (len - offset >= sizeof(long)) { 201 memcpy(laddr + offset, &a.c[0], sizeof(long)); 202 bytes_read += sizeof(long); 203 } 204 else { 205 memcpy(laddr + offset, &a.c[0], len - offset); 206 bytes_read += (len - offset); 207 } 208 offset += sizeof(long); 209 } 210 211 return bytes_read; 212} 213 214/* Read a series of bytes starting at the process's memory address 215 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes 216 have been read. 217*/ 218int 219umovestr(Process *proc, void *addr, int len, void *laddr) { 220 union { 221 long a; 222 char c[sizeof(long)]; 223 } a; 224 unsigned i; 225 int offset = 0; 226 227 while (offset < len) { 228 a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0); 229 for (i = 0; i < sizeof(long); i++) { 230 if (a.c[i] && offset + (signed)i < len) { 231 *(char *)(laddr + offset + i) = a.c[i]; 232 } else { 233 *(char *)(laddr + offset + i) = '\0'; 234 return 0; 235 } 236 } 237 offset += sizeof(long); 238 } 239 *(char *)(laddr + offset) = '\0'; 240 return 0; 241} 242