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