2 * process interface for Linux.
4 * Uses ptrace for registers and data,
5 * /proc for some process status.
6 * There's not much point to worrying about
7 * byte order here -- using ptrace means
8 * we're running on the architecture we're debugging,
9 * unless truly weird stuff is going on.
11 * It is tempting to use /proc/%d/mem along with
12 * the sp and pc in the stat file to get a stack trace
13 * without attaching to the program, but unfortunately
14 * you can't read the mem file unless you've attached.
18 #include <sys/ptrace.h>
19 #include <sys/types.h>
21 #include <sys/procfs.h>
29 Mach *machcpu = &mach386;
31 typedef struct PtraceRegs PtraceRegs;
39 static int ptracesegrw(Map*, Seg*, ulong, void*, uint, int);
40 static int ptraceregrw(Regs*, char*, ulong*, int);
42 static int attachedpids[1000];
51 if(nattached==1 && attachedpids[0] == pid)
54 detachproc(attachedpids[0]);
57 for(i=0; i<nattached; i++)
58 if(attachedpids[i]==pid)
60 if(nattached == nelem(attachedpids)){
61 werrstr("attached to too many processes");
65 if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0){
66 werrstr("ptrace attach %d: %r", pid);
70 if(ctlproc(pid, "waitstop") < 0){
71 fprint(2, "waitstop: %r");
72 ptrace(PTRACE_DETACH, pid, 0, 0);
75 attachedpids[nattached++] = pid;
86 for(i=0; i<map->nseg; i++)
87 while(i<map->nseg && map->seg[i].pid){
89 memmove(&map->seg[i], &map->seg[i+1],
90 (map->nseg-i)*sizeof(map->seg[0]));
95 mapproc(int pid, Map *map, Regs **rp)
100 if(ptraceattach(pid) < 0)
103 memset(&s, 0, sizeof s);
111 if(addseg(map, s) < 0){
112 fprint(2, "addseg: %r\n");
116 if((r = mallocz(sizeof(PtraceRegs), 1)) == nil){
117 fprint(2, "mallocz: %r\n");
120 r->r.rw = ptraceregrw;
131 for(i=0; i<nattached; i++){
132 if(attachedpids[i] == pid){
133 attachedpids[i] = attachedpids[--nattached];
137 return ptrace(PTRACE_DETACH, pid, 0, 0);
141 ptracerw(int type, int xtype, int isr, int pid, ulong addr, void *v, uint n)
150 u = ptrace(type, pid, addr+i, 0);
154 *(u32int*)((char*)v+i) = u;
157 memmove((char*)v+i, buf, n-i);
161 u = *(u32int*)((char*)v+i);
164 u = ptrace(xtype, pid, addr+i, 0);
168 memmove(buf, (char*)v+i, n-i);
171 if(ptrace(type, pid, addr+i, u) < 0)
178 werrstr("ptrace: %r");
183 ptracesegrw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
186 return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
187 isr, seg->pid, addr, v, n);
190 static char* linuxregs[] = {
215 for(i=0; i<nelem(linuxregs); i++)
216 if(strcmp(linuxregs[i], reg) == 0)
222 ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
228 pid = ((PtraceRegs*)regs)->pid;
229 addr = reg2linux(name);
235 werrstr("register not available");
240 u = ptrace(PTRACE_PEEKUSER, pid, addr, 0);
246 if(ptrace(PTRACE_POKEUSER, pid, addr, &u) < 0)
252 werrstr("ptrace: %r");
263 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
264 if((fd = open(buf, OREAD)) < 0)
266 n = read(fd, buf, sizeof buf-1);
272 /* command name is in parens, no parens afterward */
273 p = strrchr(buf, ')');
274 if(p == nil || *++p != ' ')
278 /* next is state - T is stopped for tracing */
282 /* /proc/pid/stat contains
291 6. flags (math=4, traced=10)
313 28. pending signal bitmap
314 29. blocked signal bitmap
315 30. ignored signal bitmap
316 31. caught signal bitmap
326 procnotes(int pid, char ***pnotes)
328 char buf[1024], *f[40];
330 char *p, *s, **notes;
332 extern char *_p9sigstr(int, char*);
335 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
336 if((fd = open(buf, OREAD)) < 0){
337 fprint(2, "open %s: %r\n", buf);
340 n = read(fd, buf, sizeof buf-1);
343 fprint(2, "read %s: %r\n", buf);
348 /* command name is in parens, no parens afterward */
349 p = strrchr(buf, ')');
350 if(p == nil || *++p != ' '){
351 fprint(2, "bad format in /proc/%d/stat\n", pid);
356 nf = tokenize(p, f, nelem(f));
357 if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
358 strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
359 strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
363 sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
369 notes = mallocz(32*sizeof(char*), 0);
374 if((sigs&(1<<i)) == 0)
376 if((s = _p9sigstr(i, nil)) == nil)
387 ctlproc(int pid, char *msg)
391 if(strcmp(msg, "hang") == 0){
393 return ptrace(PTRACE_TRACEME, 0, 0, 0);
394 werrstr("can only hang self");
397 if(strcmp(msg, "kill") == 0)
398 return ptrace(PTRACE_KILL, pid, 0, 0);
399 if(strcmp(msg, "startstop") == 0){
400 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
404 if(strcmp(msg, "sysstop") == 0){
405 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
409 if(strcmp(msg, "stop") == 0){
410 if(kill(pid, SIGSTOP) < 0)
414 if(strcmp(msg, "waitstop") == 0){
419 p = waitpid(pid, &status, WUNTRACED|__WALL);
427 if(WIFEXITED(status) || WIFSTOPPED(status))
431 if(strcmp(msg, "start") == 0)
432 return ptrace(PTRACE_CONT, pid, 0, 0);
433 werrstr("unknown control message '%s'", msg);
438 proctextfile(int pid)
440 static char buf[1024], pbuf[128];
442 snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
443 if(readlink(pbuf, buf, sizeof buf) >= 0)
445 if(access(pbuf, AEXIST) >= 0)