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]));
97 mapproc(int pid, Map *map, Regs **rp)
102 if(ptraceattach(pid) < 0)
105 memset(&s, 0, sizeof s);
113 if(addseg(map, s) < 0){
114 fprint(2, "addseg: %r\n");
118 if((r = mallocz(sizeof(PtraceRegs), 1)) == nil){
119 fprint(2, "mallocz: %r\n");
122 r->r.rw = ptraceregrw;
133 for(i=0; i<nattached; i++){
134 if(attachedpids[i] == pid){
135 attachedpids[i] = attachedpids[--nattached];
139 return ptrace(PTRACE_DETACH, pid, 0, 0);
143 ptracerw(int type, int xtype, int isr, int pid, ulong addr, void *v, uint n)
152 u = ptrace(type, pid, addr+i, 0);
156 *(u32int*)((char*)v+i) = u;
159 memmove((char*)v+i, buf, n-i);
163 u = *(u32int*)((char*)v+i);
166 u = ptrace(xtype, pid, addr+i, 0);
170 memmove(buf, (char*)v+i, n-i);
173 if(ptrace(type, pid, addr+i, &u) < 0)
180 werrstr("ptrace: %r");
185 ptracesegrw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
188 return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
189 isr, seg->pid, addr, v, n);
192 static char* linuxregs[] = {
217 for(i=0; i<nelem(linuxregs); i++)
218 if(strcmp(linuxregs[i], reg) == 0)
224 ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
230 pid = ((PtraceRegs*)regs)->pid;
231 addr = reg2linux(name);
237 werrstr("register not available");
242 u = ptrace(PTRACE_PEEKUSER, pid, addr, 0);
248 if(ptrace(PTRACE_POKEUSER, pid, addr, &u) < 0)
254 werrstr("ptrace: %r");
265 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
266 if((fd = open(buf, OREAD)) < 0)
268 n = read(fd, buf, sizeof buf-1);
274 /* command name is in parens, no parens afterward */
275 p = strrchr(buf, ')');
276 if(p == nil || *++p != ' ')
280 /* next is state - T is stopped for tracing */
284 /* /proc/pid/stat contains
293 6. flags (math=4, traced=10)
315 28. pending signal bitmap
316 29. blocked signal bitmap
317 30. ignored signal bitmap
318 31. caught signal bitmap
328 procnotes(int pid, char ***pnotes)
330 char buf[1024], *f[40];
332 char *p, *s, **notes;
334 extern char *_p9sigstr(int, char*);
337 snprint(buf, sizeof buf, "/proc/%d/stat", pid);
338 if((fd = open(buf, OREAD)) < 0){
339 fprint(2, "open %s: %r\n", buf);
342 n = read(fd, buf, sizeof buf-1);
345 fprint(2, "read %s: %r\n", buf);
350 /* command name is in parens, no parens afterward */
351 p = strrchr(buf, ')');
352 if(p == nil || *++p != ' '){
353 fprint(2, "bad format in /proc/%d/stat\n", pid);
358 nf = tokenize(p, f, nelem(f));
359 if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
360 strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
361 strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
365 sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
371 notes = mallocz(32*sizeof(char*), 0);
376 if((sigs&(1<<i)) == 0)
378 if((s = _p9sigstr(i, nil)) == nil)
389 ctlproc(int pid, char *msg)
393 if(strcmp(msg, "hang") == 0){
395 return ptrace(PTRACE_TRACEME, 0, 0, 0);
396 werrstr("can only hang self");
399 if(strcmp(msg, "kill") == 0)
400 return ptrace(PTRACE_KILL, pid, 0, 0);
401 if(strcmp(msg, "startstop") == 0){
402 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
406 if(strcmp(msg, "sysstop") == 0){
407 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
411 if(strcmp(msg, "stop") == 0){
412 if(kill(pid, SIGSTOP) < 0)
416 if(strcmp(msg, "waitstop") == 0){
421 p = waitpid(pid, &status, WUNTRACED|__WALL);
429 if(WIFEXITED(status) || WIFSTOPPED(status))
433 if(strcmp(msg, "start") == 0)
434 return ptrace(PTRACE_CONT, pid, 0, 0);
435 werrstr("unknown control message '%s'", msg);
440 proctextfile(int pid)
442 static char buf[1024], pbuf[128];
444 snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
445 if(readlink(pbuf, buf, sizeof buf) >= 0)
447 if(access(pbuf, AEXIST) >= 0)
454 snprint(buf, sizeof buf, "/proc/%d/maps", pid);
455 if((b = Bopen(buf, OREAD)) == nil){
456 werrstr("open %s: %r", buf);
461 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
462 08056000-08058000 rw-p 0000d000 03:0c 64593 /usr/sbin/gpm
463 08058000-0805b000 rwxp 00000000 00:00 0
464 40000000-40013000 r-xp 00000000 03:0c 4165 /lib/ld-2.2.4.so
465 40013000-40015000 rw-p 00012000 03:0c 4165 /lib/ld-2.2.4.so
466 4001f000-40135000 r-xp 00000000 03:0c 45494 /lib/libc-2.2.4.so
467 40135000-4013e000 rw-p 00115000 03:0c 45494 /lib/libc-2.2.4.so
468 4013e000-40142000 rw-p 00000000 00:00 0
469 bffff000-c0000000 rwxp 00000000 00:00 0
473 while((p = Brdline(b, '\n')) != nil){
474 p[Blinelen(b)-1] = 0;
475 memset(f, 0, sizeof f);
476 if((nf = getfields(p, f, 6, 1, " ")) < 5)
478 base = strtoul(f[0], &p, 16);
481 end = strtoul(p+1, &p, 16);
484 offset = strtoul(f[2], &p, 16);
489 zero = atoi(f[4]) == 0;
490 print("%lux-%lux %lux %s %s\n", base, end, offset, zero ? "data" : "text", file ? file : "");
494 s.name = zero ? "data" : "text";
495 s.file = strdup(file);
498 if(addseg(map, s) < 0){
500 ptrace(PTRACE_DETACH, pid, 0, 0);
508 * bottom-end functions for libthread_db to call
522 ps_getpid(struct ps_prochandle *ph)
528 ps_pstop(const struct ps_prochandle *ph)
534 ps_pcontinue(const struct ps_prochandle *ph)
540 ps_lstop(const struct ps_prochandle *ph)
546 ps_lcontinue(const struct ps_prochandle *ph)
551 /* read/write data or text memory */
553 ps_pdread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
555 //print("read %d %p %d\n", ph->pid, addr, sz);
556 if(ptracerw(PTRACE_PEEKDATA, 0, 1, ph->pid, (ulong)addr, v, sz) < 0)
558 //print(" => 0x%lux\n", *(ulong*)v);
563 ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
565 //print("write %d %p\n", ph->pid, addr);
566 if(ptracerw(PTRACE_POKEDATA, PTRACE_PEEKDATA, 0, ph->pid, (ulong)addr, v, sz) < 0)
572 ps_ptread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
574 //print("read %d %p\n", ph->pid, addr);
575 if(ptracerw(PTRACE_PEEKTEXT, 0, 1, ph->pid, (ulong)addr, v, sz) < 0)
581 ps_ptwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
583 //print("write %d %p\n", ph->pid, addr);
584 if(ptracerw(PTRACE_POKETEXT, PTRACE_PEEKTEXT, 0, ph->pid, (ulong)addr, v, sz) < 0)
590 ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs)
593 memset(regs, 0xfe, sizeof(regs[0])*nelem(linuxregs));
596 //print("getregs %d %p (%d)\n", lwp, regs, sizeof(regs[0])*nelem(linuxregs));
598 if(ptraceattach(lwp) < 0){
599 fprint(2, "ptrace attach: %r\n");
603 if(ptracerw(PTRACE_PEEKUSER, 0, 1, lwp, 0, regs, sizeof(regs[0])*nelem(linuxregs)) < 0){
604 fprint(2, "ptrace: %r\n");
611 ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs)
613 print("setregs %d\n", lwp);
614 if(ptracerw(PTRACE_POKEUSER, PTRACE_PEEKUSER, 1, lwp, 0, regs, sizeof(regs[0])*nelem(linuxregs)) < 0)
620 ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs)
622 if(ptracerw(PTRACE_PEEKUSER, 0, 1, lwp, 18*4, fpregs, sizeof *fpregs) < 0)
628 ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs)
630 if(ptracerw(PTRACE_POKEUSER, PTRACE_PEEKUSER, 1, lwp, 18*4, fpregs, sizeof *fpregs) < 0)
635 /* Fetch the special per-thread address associated with the given LWP.
636 This call is only used on a few platforms (most use a normal register).
637 The meaning of the `int' parameter is machine-dependent. */
639 ps_get_thread_area(struct ps_prochandle *ph, lwpid_t lwp, int xxx, psaddr_t *addr)
644 /* Look up the named symbol in the named DSO in the symbol tables
645 associated with the process being debugged, filling in *SYM_ADDR
646 with the corresponding run-time address. */
648 ps_pglobal_lookup(struct ps_prochandle *ph, char *object_name, char *sym_name, psaddr_t *sym_addr)
653 if((fp = findhdr(object_name)) == nil){
654 print("lookup %d %s %s => no such hdr\n", ph->pid, object_name, sym_name);
657 if(elfsymlookup(fp->elf, sym_name, &addr) < 0){
658 print("lookup %d %s %s => name not found\n", ph->pid, object_name, sym_name);
661 print("lookup %d %s %s => 0x%lux\n", ph->pid, object_name, sym_name, addr);
662 *sym_addr = (void*)(addr+fp->base);
667 _linux2ureg386(UregLinux386 *l)
671 u = malloc(sizeof(Ureg));
686 u->trap = ~0; // l->trapno;
687 u->ecode = ~0; // l->err;
690 u->flags = l->eflags;