trace.c revision 55ed83b24df9c6d671091a8c75caab33ffecd40e
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 11#include "ltrace.h" 12#include "options.h" 13#include "sysdep.h" 14#include "debug.h" 15 16/* If the system headers did not provide the constants, hard-code the normal 17 values. */ 18#ifndef PTRACE_EVENT_FORK 19 20#define PTRACE_OLDSETOPTIONS 21 21#define PTRACE_SETOPTIONS 0x4200 22#define PTRACE_GETEVENTMSG 0x4201 23 24/* options set using PTRACE_SETOPTIONS */ 25#define PTRACE_O_TRACESYSGOOD 0x00000001 26#define PTRACE_O_TRACEFORK 0x00000002 27#define PTRACE_O_TRACEVFORK 0x00000004 28#define PTRACE_O_TRACECLONE 0x00000008 29#define PTRACE_O_TRACEEXEC 0x00000010 30#define PTRACE_O_TRACEVFORKDONE 0x00000020 31#define PTRACE_O_TRACEEXIT 0x00000040 32 33/* Wait extended result codes for the above trace options. */ 34#define PTRACE_EVENT_FORK 1 35#define PTRACE_EVENT_VFORK 2 36#define PTRACE_EVENT_CLONE 3 37#define PTRACE_EVENT_EXEC 4 38#define PTRACE_EVENT_VFORK_DONE 5 39#define PTRACE_EVENT_EXIT 6 40 41#endif /* PTRACE_EVENT_FORK */ 42 43static int fork_exec_syscalls[][5] = { 44 { 45#ifdef __NR_fork 46 __NR_fork, 47#else 48 -1, 49#endif 50#ifdef __NR_clone 51 __NR_clone, 52#else 53 -1, 54#endif 55#ifdef __NR_clone2 56 __NR_clone2, 57#else 58 -1, 59#endif 60#ifdef __NR_vfork 61 __NR_vfork, 62#else 63 -1, 64#endif 65#ifdef __NR_execve 66 __NR_execve, 67#else 68 -1, 69#endif 70 } 71#ifdef FORK_EXEC_SYSCALLS 72 FORK_EXEC_SYSCALLS 73#endif 74}; 75 76/* Returns 1 if the sysnum may make a new child to be created 77 * (ie, with fork() or clone()) 78 * Returns 0 otherwise. 79 */ 80int fork_p(struct process *proc, int sysnum) 81{ 82 unsigned int i; 83 if (proc->personality 84 >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0])) 85 return 0; 86 for (i = 0; i < sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1; ++i) 87 if (sysnum == fork_exec_syscalls[proc->personality][i]) 88 return 1; 89 return 0; 90} 91 92/* Returns 1 if the sysnum may make the process exec other program 93 */ 94int exec_p(struct process *proc, int sysnum) 95{ 96 int i; 97 if (proc->personality 98 >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0])) 99 return 0; 100 i = sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1; 101 if (sysnum == fork_exec_syscalls[proc->personality][i]) 102 return 1; 103 return 0; 104} 105 106/* Check that we just hit an exec. 107 */ 108int was_exec(struct process *proc, int status) 109{ 110 if (!WIFSTOPPED (status)) 111 return 0; 112 113 if (WSTOPSIG (status) == SIGTRAP 114 && (status >> 16) == PTRACE_EVENT_EXEC) { 115 debug (1, "detected exec (PTRACE_EVENT_EXEC)"); 116 return 1; 117 } 118 119 if (WSTOPSIG (status) == SIGTRAP 120 && proc->callstack_depth > 0) { 121 /* Check whether this SIGTRAP is received just after 122 execve is called for this process. Ideally we'd 123 like to check that the exec succeeded, but e.g. on 124 s390 we have no way of knowing, because return 125 value is not set to -1 (as it should). Never mind, 126 reseting breakpoints for current process doesn't 127 hurt. */ 128 struct callstack_element *elem; 129 elem = &proc->callstack[proc->callstack_depth - 1]; 130 if (elem && elem->is_syscall && exec_p(proc, elem->c_un.syscall)) { 131 debug (1, "detected exec (callstack)"); 132 return 1; 133 } 134 } 135 136 return 0; 137} 138 139void trace_me(void) 140{ 141 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { 142 perror("PTRACE_TRACEME"); 143 exit(1); 144 } 145} 146 147int trace_pid(pid_t pid) 148{ 149 if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) { 150 return -1; 151 } 152 153 /* man ptrace: PTRACE_ATTACH attaches to the process specified 154 in pid. The child is sent a SIGSTOP, but will not 155 necessarily have stopped by the completion of this call; 156 use wait() to wait for the child to stop. */ 157 if (waitpid (pid, NULL, 0) != pid) { 158 perror ("trace_pid: waitpid"); 159 exit (1); 160 } 161 162 return 0; 163} 164 165void trace_set_options(struct process *proc, pid_t pid) 166{ 167 if (proc->tracesysgood & 0x80) 168 return; 169 170 long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC; 171 if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 && 172 ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) { 173 perror("PTRACE_SETOPTIONS"); 174 return; 175 } 176 proc->tracesysgood |= 0x80; 177} 178 179void untrace_pid(pid_t pid) 180{ 181 ptrace(PTRACE_DETACH, pid, 1, 0); 182} 183 184void continue_after_signal(pid_t pid, int signum) 185{ 186 /* We should always trace syscalls to be able to control fork(), clone(), execve()... */ 187 ptrace(PTRACE_SYSCALL, pid, 0, signum); 188} 189 190void continue_process(pid_t pid) 191{ 192 continue_after_signal(pid, 0); 193} 194 195void continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp) 196{ 197 enable_breakpoint(pid, sbp); 198 continue_process(pid); 199} 200 201void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp) 202{ 203 if (sbp->enabled) 204 disable_breakpoint(proc->pid, sbp); 205 set_instruction_pointer(proc, sbp->addr); 206 if (sbp->enabled == 0) { 207 continue_process(proc->pid); 208 } else { 209 proc->breakpoint_being_enabled = sbp; 210#if defined __sparc__ || defined __ia64___ 211 /* we don't want to singlestep here */ 212 continue_process(proc->pid); 213#else 214 ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0); 215#endif 216 } 217} 218 219/* Read a single long from the process's memory address 'addr' */ 220int umovelong(struct process *proc, void *addr, long *result) 221{ 222 long pointed_to; 223 224 errno = 0; 225 pointed_to = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); 226 if (pointed_to == -1 && errno) 227 return -errno; 228 229 *result = pointed_to; 230 return 0; 231} 232 233/* Read a series of bytes starting at the process's memory address 234 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes 235 have been read. 236*/ 237int umovestr(struct process *proc, void *addr, int len, void *laddr) 238{ 239 union { 240 long a; 241 char c[sizeof(long)]; 242 } a; 243 int i; 244 int offset = 0; 245 246 while (offset < len) { 247 a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0); 248 for (i = 0; i < sizeof(long); i++) { 249 if (a.c[i] && offset + (signed)i < len) { 250 *(char *)(laddr + offset + i) = a.c[i]; 251 } else { 252 *(char *)(laddr + offset + i) = '\0'; 253 return 0; 254 } 255 } 256 offset += sizeof(long); 257 } 258 *(char *)(laddr + offset) = '\0'; 259 return 0; 260} 261