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];
50 for(i=0; i<nattached; i++)
51 if(attachedpids[i]==pid)
53 if(nattached == nelem(attachedpids)){
54 werrstr("attached to too many processes");
58 if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0){
59 werrstr("ptrace attach %d: %r", pid);
63 if(ctlproc(pid, "waitstop") < 0){
64 fprint(2, "waitstop: %r");
65 ptrace(PTRACE_DETACH, pid, 0, 0);
68 attachedpids[nattached++] = pid;
79 for(i=0; i<map->nseg; i++)
80 while(i<map->nseg && map->seg[i].pid){
82 memmove(&map->seg[i], &map->seg[i+1],
83 (map->nseg-i)*sizeof(map->seg[0]));
88 mapproc(int pid, Map *map, Regs **rp)
93 if(ptraceattach(pid) < 0)
96 memset(&s, 0, sizeof s);
104 if(addseg(map, s) < 0){
105 fprint(2, "addseg: %r\n");
109 if((r = mallocz(sizeof(PtraceRegs), 1)) == nil){
110 fprint(2, "mallocz: %r\n");
113 r->r.rw = ptraceregrw;
124 for(i=0; i<nattached; i++){
125 if(attachedpids[i] == pid){
126 attachedpids[i] = attachedpids[--nattached];
130 return ptrace(PTRACE_DETACH, pid, 0, 0);
134 ptracerw(int type, int xtype, int isr, int pid, ulong addr, void *v, uint n)
143 u = ptrace(type, pid, addr+i, 0);
147 *(u32int*)((char*)v+i) = u;
150 memmove((char*)v+i, buf, n-i);
154 u = *(u32int*)((char*)v+i);
157 u = ptrace(xtype, pid, addr+i, 0);
161 memmove(buf, (char*)v+i, n-i);
164 if(ptrace(type, pid, addr+i, u) < 0)
171 werrstr("ptrace: %r");
176 ptracesegrw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
179 return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
180 isr, seg->pid, addr, v, n);
183 static char* linuxregs[] = {
208 for(i=0; i<nelem(linuxregs); i++)
209 if(strcmp(linuxregs[i], reg) == 0)
215 ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
221 pid = ((PtraceRegs*)regs)->pid;
222 addr = reg2linux(name);
228 werrstr("register not available");
233 u = ptrace(PTRACE_PEEKUSER, pid, addr, 0);
239 if(ptrace(PTRACE_POKEUSER, pid, addr, (void*)u) < 0)
245 werrstr("ptrace: %r");
256 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
257 if((fd = open(buf, OREAD)) < 0)
259 n = read(fd, buf, sizeof buf-1);
265 /* command name is in parens, no parens afterward */
266 p = strrchr(buf, ')');
267 if(p == nil || *++p != ' ')
271 /* next is state - T is stopped for tracing */
275 /* /proc/pid/stat contains
284 6. flags (math=4, traced=10)
306 28. pending signal bitmap
307 29. blocked signal bitmap
308 30. ignored signal bitmap
309 31. caught signal bitmap
318 procnotes(int pid, char ***pnotes)
320 char buf[1024], *f[40];
322 char *p, *s, **notes;
324 extern char *_p9sigstr(int, char*);
327 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
328 if((fd = open(buf, OREAD)) < 0){
329 fprint(2, "open %s: %r\n", buf);
332 n = read(fd, buf, sizeof buf-1);
335 fprint(2, "read %s: %r\n", buf);
340 /* command name is in parens, no parens afterward */
341 p = strrchr(buf, ')');
342 if(p == nil || *++p != ' '){
343 fprint(2, "bad format in /proc/%d/stat\n", pid);
348 nf = tokenize(p, f, nelem(f));
349 if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
350 strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
351 strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
355 sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
361 notes = mallocz(32*sizeof(char*), 0);
366 if((sigs&(1<<i)) == 0)
368 if((s = _p9sigstr(i, nil)) == nil)
379 ctlproc(int pid, char *msg)
383 if(strcmp(msg, "attached") == 0){
384 for(i=0; i<nattached; i++)
385 if(attachedpids[i]==pid)
387 if(nattached == nelem(attachedpids)){
388 werrstr("attached to too many processes");
391 attachedpids[nattached++] = pid;
395 if(strcmp(msg, "hang") == 0){
397 return ptrace(PTRACE_TRACEME, 0, 0, 0);
398 werrstr("can only hang self");
401 if(strcmp(msg, "kill") == 0)
402 return ptrace(PTRACE_KILL, pid, 0, 0);
403 if(strcmp(msg, "startstop") == 0){
404 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
408 if(strcmp(msg, "sysstop") == 0){
409 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
413 if(strcmp(msg, "stop") == 0){
414 if(kill(pid, SIGSTOP) < 0)
418 if(strcmp(msg, "step") == 0){
419 if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0)
423 if(strcmp(msg, "waitstop") == 0){
428 p = waitpid(pid, &status, WUNTRACED|__WALL);
436 //fprint(2, "got pid %d status %x\n", pid, status);
437 if(WIFEXITED(status) || WIFSTOPPED(status))
441 if(strcmp(msg, "start") == 0)
442 return ptrace(PTRACE_CONT, pid, 0, 0);
443 werrstr("unknown control message '%s'", msg);
448 proctextfile(int pid)
450 static char buf[1024], pbuf[128];
452 snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
453 if(readlink(pbuf, buf, sizeof buf) >= 0)
455 if(access(pbuf, AEXIST) >= 0)