trace.c revision 89a536028ab3b699b7f953b6b0fd7607917fc303
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 15static int fork_exec_syscalls[][5] = { 16 { 17#ifdef __NR_fork 18 __NR_fork, 19#else 20 -1, 21#endif 22#ifdef __NR_clone 23 __NR_clone, 24#else 25 -1, 26#endif 27#ifdef __NR_clone2 28 __NR_clone2, 29#else 30 -1, 31#endif 32#ifdef __NR_vfork 33 __NR_vfork, 34#else 35 -1, 36#endif 37#ifdef __NR_execve 38 __NR_execve, 39#else 40 -1, 41#endif 42 } 43#ifdef FORK_EXEC_SYSCALLS 44 FORK_EXEC_SYSCALLS 45#endif 46}; 47 48/* Returns 1 if the sysnum may make a new child to be created 49 * (ie, with fork() or clone()) 50 * Returns 0 otherwise. 51 */ 52int fork_p(struct process *proc, int sysnum) 53{ 54 unsigned int i; 55 if (proc->personality 56 >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0])) 57 return 0; 58 for (i = 0; i < sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1; ++i) 59 if (sysnum == fork_exec_syscalls[proc->personality][i]) 60 return 1; 61 return 0; 62} 63 64/* Returns 1 if the sysnum may make the process exec other program 65 */ 66int exec_p(struct process *proc, int sysnum) 67{ 68 int i; 69 if (proc->personality 70 >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0])) 71 return 0; 72 i = sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1; 73 if (sysnum == fork_exec_syscalls[proc->personality][i]) 74 return 1; 75 return 0; 76} 77 78void trace_me(void) 79{ 80 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { 81 perror("PTRACE_TRACEME"); 82 exit(1); 83 } 84} 85 86int trace_pid(pid_t pid) 87{ 88 if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) { 89 return -1; 90 } 91 92 /* man ptrace: PTRACE_ATTACH attaches to the process specified 93 in pid. The child is sent a SIGSTOP, but will not 94 necessarily have stopped by the completion of this call; 95 use wait() to wait for the child to stop. */ 96 if (waitpid (pid, NULL, 0) != pid) { 97 perror ("trace_pid: waitpid"); 98 exit (1); 99 } 100 101 return 0; 102} 103 104void trace_set_options(struct process *proc, pid_t pid) 105{ 106#ifndef PTRACE_SETOPTIONS 107#define PTRACE_SETOPTIONS 0x4200 108#endif 109#ifndef PTRACE_OLDSETOPTIONS 110#define PTRACE_OLDSETOPTIONS 21 111#endif 112#ifndef PTRACE_O_TRACESYSGOOD 113#define PTRACE_O_TRACESYSGOOD 0x00000001 114#endif 115 if (proc->tracesysgood & 0x80) 116 return; 117 if (ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD) < 0 && 118 ptrace(PTRACE_OLDSETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD) < 0) { 119 perror("PTRACE_SETOPTIONS"); 120 return; 121 } 122 proc->tracesysgood |= 0x80; 123} 124 125void untrace_pid(pid_t pid) 126{ 127 ptrace(PTRACE_DETACH, pid, 1, 0); 128} 129 130void continue_after_signal(pid_t pid, int signum) 131{ 132 /* We should always trace syscalls to be able to control fork(), clone(), execve()... */ 133 ptrace(PTRACE_SYSCALL, pid, 0, signum); 134} 135 136void continue_process(pid_t pid) 137{ 138 continue_after_signal(pid, 0); 139} 140 141void continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp) 142{ 143 enable_breakpoint(pid, sbp); 144 continue_process(pid); 145} 146 147void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp) 148{ 149 if (sbp->enabled) 150 disable_breakpoint(proc->pid, sbp); 151 set_instruction_pointer(proc, sbp->addr); 152 if (sbp->enabled == 0) { 153 continue_process(proc->pid); 154 } else { 155 proc->breakpoint_being_enabled = sbp; 156#if defined __sparc__ || defined __ia64___ 157 /* we don't want to singlestep here */ 158 continue_process(proc->pid); 159#else 160 ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0); 161#endif 162 } 163} 164 165/* Read a single long from the process's memory address 'addr' */ 166int umovelong(struct process *proc, void *addr, long *result) 167{ 168 long pointed_to; 169 170 errno = 0; 171 pointed_to = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); 172 if (pointed_to == -1 && errno) 173 return -errno; 174 175 *result = pointed_to; 176 return 0; 177} 178 179/* Read a series of bytes starting at the process's memory address 180 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes 181 have been read. 182*/ 183int umovestr(struct process *proc, void *addr, int len, void *laddr) 184{ 185 union { 186 long a; 187 char c[sizeof(long)]; 188 } a; 189 int i; 190 int offset = 0; 191 192 while (offset < len) { 193 a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0); 194 for (i = 0; i < sizeof(long); i++) { 195 if (a.c[i] && offset + (signed)i < len) { 196 *(char *)(laddr + offset + i) = a.c[i]; 197 } else { 198 *(char *)(laddr + offset + i) = '\0'; 199 return 0; 200 } 201 } 202 offset += sizeof(long); 203 } 204 *(char *)(laddr + offset) = '\0'; 205 return 0; 206} 207