DragonFly.c (6117B)
1 /* 2 * process interface for DragonFly BSD 3 * 4 * we could be a little more careful about not using 5 * ptrace unless absolutely necessary. this would let us 6 * look at processes without stopping them. 7 * 8 * I'd like to make this a bit more generic (there's too much 9 * duplication with Linux and presumably other systems), 10 * but ptrace is too damn system-specific. 11 */ 12 13 #include <u.h> 14 #include <sys/ptrace.h> 15 #include <sys/types.h> 16 #include <sys/wait.h> 17 #include <machine/reg.h> 18 #include <signal.h> 19 #include <errno.h> 20 #include <libc.h> 21 #include <mach.h> 22 #include "ureg386.h" 23 24 Mach *machcpu = &mach386; 25 26 typedef struct PtraceRegs PtraceRegs; 27 struct PtraceRegs 28 { 29 Regs r; 30 int pid; 31 }; 32 33 static int ptracerw(Map*, Seg*, ulong, void*, uint, int); 34 static int ptraceregrw(Regs*, char*, ulong*, int); 35 36 void 37 unmapproc(Map *map) 38 { 39 int i; 40 41 if(map == nil) 42 return; 43 for(i=0; i<map->nseg; i++) 44 while(i<map->nseg && map->seg[i].pid){ 45 map->nseg--; 46 memmove(&map->seg[i], &map->seg[i+1], 47 (map->nseg-i)*sizeof(map->seg[0])); 48 } 49 } 50 51 int 52 mapproc(int pid, Map *map, Regs **rp) 53 { 54 Seg s; 55 PtraceRegs *r; 56 57 if(ptrace(PT_ATTACH, pid, 0, 0) < 0) 58 if(ptrace(PT_READ_I, pid, 0, 0)<0 && errno!=EINVAL) 59 if(ptrace(PT_ATTACH, pid, 0, 0) < 0){ 60 werrstr("ptrace attach %d: %r", pid); 61 return -1; 62 } 63 64 if(ctlproc(pid, "waitanyway") < 0){ 65 ptrace(PT_DETACH, pid, 0, 0); 66 return -1; 67 } 68 69 memset(&s, 0, sizeof s); 70 s.base = 0; 71 s.size = 0xFFFFFFFF; 72 s.offset = 0; 73 s.name = "data"; 74 s.file = nil; 75 s.rw = ptracerw; 76 s.pid = pid; 77 if(addseg(map, s) < 0) 78 return -1; 79 80 if((r = mallocz(sizeof(PtraceRegs), 1)) == nil) 81 return -1; 82 r->r.rw = ptraceregrw; 83 r->pid = pid; 84 *rp = (Regs*)r; 85 return 0; 86 } 87 88 int 89 detachproc(int pid) 90 { 91 return ptrace(PT_DETACH, pid, 0, 0); 92 } 93 94 static int 95 ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr) 96 { 97 int i; 98 u32int u; 99 uchar buf[4]; 100 101 addr += seg->base; 102 for(i=0; i<n; i+=4){ 103 if(isr){ 104 errno = 0; 105 u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0); 106 if(errno) 107 goto ptraceerr; 108 if(n-i >= 4) 109 *(u32int*)((char*)v+i) = u; 110 else{ 111 *(u32int*)buf = u; 112 memmove((char*)v+i, buf, n-i); 113 } 114 }else{ 115 if(n-i >= 4) 116 u = *(u32int*)((char*)v+i); 117 else{ 118 errno = 0; 119 u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0); 120 if(errno) 121 return -1; 122 *(u32int*)buf = u; 123 memmove(buf, (char*)v+i, n-i); 124 u = *(u32int*)buf; 125 } 126 if(ptrace(PT_WRITE_D, seg->pid, (char*)addr+i, u) < 0) 127 goto ptraceerr; 128 } 129 } 130 return 0; 131 132 ptraceerr: 133 werrstr("ptrace: %r"); 134 return -1; 135 } 136 137 static char *freebsdregs[] = { 138 "FS", 139 "ES", 140 "DS", 141 "DI", 142 "SI", 143 "BP", 144 "SP", 145 "BX", 146 "DX", 147 "CX", 148 "AX", 149 "TRAP", 150 "PC", 151 "CS", 152 "EFLAGS", 153 "SP", 154 "SS", 155 "GS", 156 }; 157 158 static ulong 159 reg2freebsd(char *reg) 160 { 161 int i; 162 163 for(i=0; i<nelem(freebsdregs); i++) 164 if(strcmp(freebsdregs[i], reg) == 0) 165 return 4*i; 166 return ~(ulong)0; 167 } 168 169 static int 170 ptraceregrw(Regs *regs, char *name, ulong *val, int isr) 171 { 172 int pid; 173 ulong addr; 174 struct reg mregs; 175 176 addr = reg2freebsd(name); 177 if(~addr == 0){ 178 if(isr){ 179 *val = ~(ulong)0; 180 return 0; 181 } 182 werrstr("register not available"); 183 return -1; 184 } 185 186 pid = ((PtraceRegs*)regs)->pid; 187 if(ptrace(PT_GETREGS, pid, (char*)&mregs, 0) < 0) 188 return -1; 189 if(isr) 190 *val = *(u32int*)((char*)&mregs+addr); 191 else{ 192 *(u32int*)((char*)&mregs+addr) = *val; 193 if(ptrace(PT_SETREGS, pid, (char*)&mregs, 0) < 0) 194 return -1; 195 } 196 return 0; 197 } 198 199 char* 200 proctextfile(int pid) 201 { 202 static char buf[1024], pbuf[128]; 203 204 snprint(pbuf, sizeof pbuf, "/proc/%d/file", pid); 205 if(readlink(pbuf, buf, sizeof buf) >= 0) 206 return buf; 207 if(access(pbuf, AEXIST) >= 0) 208 return pbuf; 209 return nil; 210 } 211 212 /* 213 214 status The process status. This file is read-only and returns a single 215 line containing multiple space-separated fields as follows: 216 217 o command name 218 o process id 219 o parent process id 220 o process group id 221 o session id 222 o major,minor of the controlling terminal, or -1,-1 if there is 223 no controlling terminal. 224 o a list of process flags: ctty if there is a controlling ter- 225 minal, sldr if the process is a session leader, noflags if 226 neither of the other two flags are set. 227 o the process start time in seconds and microseconds, comma 228 separated. 229 o the user time in seconds and microseconds, comma separated. 230 o the system time in seconds and microseconds, comma separated. 231 o the wait channel message 232 o the process credentials consisting of the effective user id 233 and the list of groups (whose first member is the effective 234 group id) all comma separated. 235 */ 236 237 int 238 procnotes(int pid, char ***pnotes) 239 { 240 /* figure out the set of pending notes - how? */ 241 *pnotes = nil; 242 return 0; 243 } 244 245 static int 246 isstopped(int pid) 247 { 248 char buf[1024], *f[12]; 249 int fd, n, nf; 250 251 snprint(buf, sizeof buf, "/proc/%d/status", pid); 252 if((fd = open(buf, OREAD)) < 0) 253 return 0; 254 n = read(fd, buf, sizeof buf-1); 255 close(fd); 256 if(n <= 0) 257 return 0; 258 buf[n] = 0; 259 260 if((nf = tokenize(buf, f, nelem(f))) < 11) 261 return 0; 262 if(strcmp(f[10], "nochan") == 0) 263 return 1; 264 return 0; 265 } 266 267 #undef waitpid 268 269 int 270 ctlproc(int pid, char *msg) 271 { 272 int p, status; 273 274 if(strcmp(msg, "hang") == 0){ 275 if(pid == getpid()) 276 return ptrace(PT_TRACE_ME, 0, 0, 0); 277 werrstr("can only hang self"); 278 return -1; 279 } 280 if(strcmp(msg, "kill") == 0) 281 return ptrace(PT_KILL, pid, 0, 0); 282 if(strcmp(msg, "startstop") == 0){ 283 if(ptrace(PT_CONTINUE, pid, 0, 0) < 0) 284 return -1; 285 goto waitstop; 286 } 287 /* 288 if(strcmp(msg, "sysstop") == 0){ 289 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) 290 return -1; 291 goto waitstop; 292 } 293 */ 294 if(strcmp(msg, "stop") == 0){ 295 if(kill(pid, SIGSTOP) < 0) 296 return -1; 297 goto waitstop; 298 } 299 if(strcmp(msg, "waitanyway") == 0) 300 goto waitanyway; 301 if(strcmp(msg, "waitstop") == 0){ 302 waitstop: 303 if(isstopped(pid)) 304 return 0; 305 waitanyway: 306 for(;;){ 307 p = waitpid(pid, &status, WUNTRACED); 308 if(p <= 0) 309 return -1; 310 if(WIFEXITED(status) || WIFSTOPPED(status)) 311 return 0; 312 } 313 } 314 if(strcmp(msg, "start") == 0) 315 return ptrace(PT_CONTINUE, pid, 0, 0); 316 werrstr("unknown control message '%s'", msg); 317 return -1; 318 }