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)
452 snprint(buf, sizeof buf, "/proc/%d/maps", pid);
453 if((b = Bopen(buf, OREAD)) == nil){
454 werrstr("open %s: %r", buf);
459 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
460 08056000-08058000 rw-p 0000d000 03:0c 64593 /usr/sbin/gpm
461 08058000-0805b000 rwxp 00000000 00:00 0
462 40000000-40013000 r-xp 00000000 03:0c 4165 /lib/ld-2.2.4.so
463 40013000-40015000 rw-p 00012000 03:0c 4165 /lib/ld-2.2.4.so
464 4001f000-40135000 r-xp 00000000 03:0c 45494 /lib/libc-2.2.4.so
465 40135000-4013e000 rw-p 00115000 03:0c 45494 /lib/libc-2.2.4.so
466 4013e000-40142000 rw-p 00000000 00:00 0
467 bffff000-c0000000 rwxp 00000000 00:00 0
471 while((p = Brdline(b, '\n')) != nil){
472 p[Blinelen(b)-1] = 0;
473 memset(f, 0, sizeof f);
474 if((nf = getfields(p, f, 6, 1, " ")) < 5)
476 base = strtoul(f[0], &p, 16);
479 end = strtoul(p+1, &p, 16);
482 offset = strtoul(f[2], &p, 16);
487 zero = atoi(f[4]) == 0;
488 print("%lux-%lux %lux %s %s\n", base, end, offset, zero ? "data" : "text", file ? file : "");
492 s.name = zero ? "data" : "text";
493 s.file = strdup(file);
496 if(addseg(map, s) < 0){
498 ptrace(PTRACE_DETACH, pid, 0, 0);
506 * bottom-end functions for libthread_db to call
520 ps_getpid(struct ps_prochandle *ph)
526 ps_pstop(const struct ps_prochandle *ph)
532 ps_pcontinue(const struct ps_prochandle *ph)
538 ps_lstop(const struct ps_prochandle *ph)
544 ps_lcontinue(const struct ps_prochandle *ph)
549 /* read/write data or text memory */
551 ps_pdread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
553 //print("read %d %p %d\n", ph->pid, addr, sz);
554 if(ptracerw(PTRACE_PEEKDATA, 0, 1, ph->pid, (ulong)addr, v, sz) < 0)
556 //print(" => 0x%lux\n", *(ulong*)v);
561 ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
563 //print("write %d %p\n", ph->pid, addr);
564 if(ptracerw(PTRACE_POKEDATA, PTRACE_PEEKDATA, 0, ph->pid, (ulong)addr, v, sz) < 0)
570 ps_ptread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
572 //print("read %d %p\n", ph->pid, addr);
573 if(ptracerw(PTRACE_PEEKTEXT, 0, 1, ph->pid, (ulong)addr, v, sz) < 0)
579 ps_ptwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
581 //print("write %d %p\n", ph->pid, addr);
582 if(ptracerw(PTRACE_POKETEXT, PTRACE_PEEKTEXT, 0, ph->pid, (ulong)addr, v, sz) < 0)
588 ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs)
591 memset(regs, 0xfe, sizeof(regs[0])*nelem(linuxregs));
594 //print("getregs %d %p (%d)\n", lwp, regs, sizeof(regs[0])*nelem(linuxregs));
596 if(ptraceattach(lwp) < 0){
597 fprint(2, "ptrace attach: %r\n");
601 if(ptracerw(PTRACE_PEEKUSER, 0, 1, lwp, 0, regs, sizeof(regs[0])*nelem(linuxregs)) < 0){
602 fprint(2, "ptrace: %r\n");
609 ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs)
611 print("setregs %d\n", lwp);
612 if(ptracerw(PTRACE_POKEUSER, PTRACE_PEEKUSER, 1, lwp, 0, regs, sizeof(regs[0])*nelem(linuxregs)) < 0)
618 ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs)
620 if(ptracerw(PTRACE_PEEKUSER, 0, 1, lwp, 18*4, fpregs, sizeof *fpregs) < 0)
626 ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs)
628 if(ptracerw(PTRACE_POKEUSER, PTRACE_PEEKUSER, 1, lwp, 18*4, fpregs, sizeof *fpregs) < 0)
633 /* Fetch the special per-thread address associated with the given LWP.
634 This call is only used on a few platforms (most use a normal register).
635 The meaning of the `int' parameter is machine-dependent. */
637 ps_get_thread_area(struct ps_prochandle *ph, lwpid_t lwp, int xxx, psaddr_t *addr)
642 /* Look up the named symbol in the named DSO in the symbol tables
643 associated with the process being debugged, filling in *SYM_ADDR
644 with the corresponding run-time address. */
646 ps_pglobal_lookup(struct ps_prochandle *ph, char *object_name, char *sym_name, psaddr_t *sym_addr)
651 if((fp = findhdr(object_name)) == nil){
652 print("lookup %d %s %s => no such hdr\n", ph->pid, object_name, sym_name);
655 if(elfsymlookup(fp->elf, sym_name, &addr) < 0){
656 print("lookup %d %s %s => name not found\n", ph->pid, object_name, sym_name);
659 print("lookup %d %s %s => 0x%lux\n", ph->pid, object_name, sym_name, addr);
660 *sym_addr = (void*)(addr+fp->base);
665 _linux2ureg386(UregLinux386 *l)
669 u = malloc(sizeof(Ureg));
684 u->trap = ~0; // l->trapno;
685 u->ecode = ~0; // l->err;
688 u->flags = l->eflags;