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>
27 Mach *machcpu = &mach386;
29 typedef struct PtraceRegs PtraceRegs;
37 static int ptracerw(Map*, Seg*, ulong, void*, uint, int);
38 static int ptraceregrw(Regs*, char*, ulong*, int);
40 static int attachedpids[1000];
50 for(i=0; i<map->nseg; i++)
51 while(i<map->nseg && map->seg[i].pid){
53 memmove(&map->seg[i], &map->seg[i+1],
54 (map->nseg-i)*sizeof(map->seg[0]));
59 mapproc(int pid, Map *map, Regs **rp)
65 if(nattached==1 && attachedpids[0] == pid)
68 detachproc(attachedpids[0]);
70 for(i=0; i<nattached; i++)
71 if(attachedpids[i]==pid)
73 if(nattached == nelem(attachedpids)){
74 werrstr("attached to too many processes");
78 if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0){
79 werrstr("ptrace attach %d: %r", pid);
83 if(ctlproc(pid, "waitstop") < 0){
84 fprint(2, "waitstop: %r");
85 ptrace(PTRACE_DETACH, pid, 0, 0);
88 attachedpids[nattached++] = pid;
91 memset(&s, 0, sizeof s);
99 if(addseg(map, s) < 0){
100 fprint(2, "addseg: %r\n");
104 if((r = mallocz(sizeof(PtraceRegs), 1)) == nil){
105 fprint(2, "mallocz: %r\n");
108 r->r.rw = ptraceregrw;
119 for(i=0; i<nattached; i++){
120 if(attachedpids[i] == pid){
121 attachedpids[i] = attachedpids[--nattached];
125 return ptrace(PTRACE_DETACH, pid, 0, 0);
129 ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
139 u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
143 *(u32int*)((char*)v+i) = u;
146 memmove((char*)v+i, buf, n-i);
150 u = *(u32int*)((char*)v+i);
153 u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
157 memmove(buf, (char*)v+i, n-i);
160 if(ptrace(PTRACE_POKEDATA, seg->pid, addr+i, &u) < 0)
167 werrstr("ptrace: %r");
171 static char* linuxregs[] = {
196 for(i=0; i<nelem(linuxregs); i++)
197 if(strcmp(linuxregs[i], reg) == 0)
203 ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
209 pid = ((PtraceRegs*)regs)->pid;
210 addr = reg2linux(name);
216 werrstr("register not available");
221 u = ptrace(PTRACE_PEEKUSER, pid, addr, 0);
227 if(ptrace(PTRACE_POKEUSER, pid, addr, &u) < 0)
233 werrstr("ptrace: %r");
244 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
245 if((fd = open(buf, OREAD)) < 0)
247 n = read(fd, buf, sizeof buf-1);
253 /* command name is in parens, no parens afterward */
254 p = strrchr(buf, ')');
255 if(p == nil || *++p != ' ')
259 /* next is state - T is stopped for tracing */
263 /* /proc/pid/stat contains
272 6. flags (math=4, traced=10)
294 28. pending signal bitmap
295 29. blocked signal bitmap
296 30. ignored signal bitmap
297 31. caught signal bitmap
307 procnotes(int pid, char ***pnotes)
309 char buf[1024], *f[40];
311 char *p, *s, **notes;
313 extern char *_p9sigstr(int, char*);
316 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
317 if((fd = open(buf, OREAD)) < 0){
318 fprint(2, "open %s: %r\n", buf);
321 n = read(fd, buf, sizeof buf-1);
324 fprint(2, "read %s: %r\n", buf);
329 /* command name is in parens, no parens afterward */
330 p = strrchr(buf, ')');
331 if(p == nil || *++p != ' '){
332 fprint(2, "bad format in /proc/%d/stat\n", pid);
337 nf = tokenize(p, f, nelem(f));
338 if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
339 strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
340 strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
344 sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
350 notes = mallocz(32*sizeof(char*), 0);
355 if((sigs&(1<<i)) == 0)
357 if((s = _p9sigstr(i, nil)) == nil)
368 ctlproc(int pid, char *msg)
372 if(strcmp(msg, "hang") == 0){
374 return ptrace(PTRACE_TRACEME, 0, 0, 0);
375 werrstr("can only hang self");
378 if(strcmp(msg, "kill") == 0)
379 return ptrace(PTRACE_KILL, pid, 0, 0);
380 if(strcmp(msg, "startstop") == 0){
381 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
385 if(strcmp(msg, "sysstop") == 0){
386 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
390 if(strcmp(msg, "stop") == 0){
391 if(kill(pid, SIGSTOP) < 0)
395 if(strcmp(msg, "waitstop") == 0){
400 p = waitpid(pid, &status, WUNTRACED|__WALL);
408 if(WIFEXITED(status) || WIFSTOPPED(status))
412 if(strcmp(msg, "start") == 0)
413 return ptrace(PTRACE_CONT, pid, 0, 0);
414 werrstr("unknown control message '%s'", msg);
419 proctextfile(int pid)
421 static char buf[1024], pbuf[128];
423 snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
424 if(readlink(pbuf, buf, sizeof buf) >= 0)
426 if(access(pbuf, AEXIST) >= 0)
433 snprint(buf, sizeof buf, "/proc/%d/maps", pid);
434 if((b = Bopen(buf, OREAD)) == nil){
435 werrstr("open %s: %r", buf);
440 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
441 08056000-08058000 rw-p 0000d000 03:0c 64593 /usr/sbin/gpm
442 08058000-0805b000 rwxp 00000000 00:00 0
443 40000000-40013000 r-xp 00000000 03:0c 4165 /lib/ld-2.2.4.so
444 40013000-40015000 rw-p 00012000 03:0c 4165 /lib/ld-2.2.4.so
445 4001f000-40135000 r-xp 00000000 03:0c 45494 /lib/libc-2.2.4.so
446 40135000-4013e000 rw-p 00115000 03:0c 45494 /lib/libc-2.2.4.so
447 4013e000-40142000 rw-p 00000000 00:00 0
448 bffff000-c0000000 rwxp 00000000 00:00 0
452 while((p = Brdline(b, '\n')) != nil){
453 p[Blinelen(b)-1] = 0;
454 memset(f, 0, sizeof f);
455 if((nf = getfields(p, f, 6, 1, " ")) < 5)
457 base = strtoul(f[0], &p, 16);
460 end = strtoul(p+1, &p, 16);
463 offset = strtoul(f[2], &p, 16);
468 zero = atoi(f[4]) == 0;
469 print("%lux-%lux %lux %s %s\n", base, end, offset, zero ? "data" : "text", file ? file : "");
473 s.name = zero ? "data" : "text";
474 s.file = strdup(file);
477 if(addseg(map, s) < 0){
479 ptrace(PTRACE_DETACH, pid, 0, 0);