diff options
Diffstat (limited to 'src/libmach/Linux.c')
-rw-r--r-- | src/libmach/Linux.c | 265 |
1 files changed, 237 insertions, 28 deletions
diff --git a/src/libmach/Linux.c b/src/libmach/Linux.c index 12b0f9b8..def8925e 100644 --- a/src/libmach/Linux.c +++ b/src/libmach/Linux.c @@ -18,10 +18,12 @@ #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> +#include <sys/procfs.h> #include <signal.h> #include <errno.h> #include <libc.h> #include <mach.h> +#include <elf.h> #include "ureg386.h" Mach *machcpu = &mach386; @@ -34,42 +36,27 @@ struct PtraceRegs int pid; }; -static int ptracerw(Map*, Seg*, ulong, void*, uint, int); +static int ptracesegrw(Map*, Seg*, ulong, void*, uint, int); static int ptraceregrw(Regs*, char*, ulong*, int); static int attachedpids[1000]; static int nattached; -void -unmapproc(Map *map) -{ - int i; - - if(map == nil) - return; - for(i=0; i<map->nseg; i++) - while(i<map->nseg && map->seg[i].pid){ - map->nseg--; - memmove(&map->seg[i], &map->seg[i+1], - (map->nseg-i)*sizeof(map->seg[0])); - } -} - int -mapproc(int pid, Map *map, Regs **rp) +ptraceattach(int pid) { int i; - Seg s; - PtraceRegs *r; + /* if(nattached==1 && attachedpids[0] == pid) goto already; if(nattached) detachproc(attachedpids[0]); - + */ + for(i=0; i<nattached; i++) if(attachedpids[i]==pid) - goto already; + return 0; if(nattached == nelem(attachedpids)){ werrstr("attached to too many processes"); return -1; @@ -86,15 +73,42 @@ mapproc(int pid, Map *map, Regs **rp) return -1; } attachedpids[nattached++] = pid; + return 0; +} + +void +unmapproc(Map *map) +{ + int i; + + if(map == nil) + return; + for(i=0; i<map->nseg; i++) + while(i<map->nseg && map->seg[i].pid){ + map->nseg--; + memmove(&map->seg[i], &map->seg[i+1], + (map->nseg-i)*sizeof(map->seg[0])); + } +} + + + +int +mapproc(int pid, Map *map, Regs **rp) +{ + Seg s; + PtraceRegs *r; + + if(ptraceattach(pid) < 0) + return -1; -already: memset(&s, 0, sizeof s); s.base = 0; s.size = 0xFFFFFFFF; s.offset = 0; s.name = "data"; s.file = nil; - s.rw = ptracerw; + s.rw = ptracesegrw; s.pid = pid; if(addseg(map, s) < 0){ fprint(2, "addseg: %r\n"); @@ -126,17 +140,16 @@ detachproc(int pid) } static int -ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr) +ptracerw(int type, int xtype, int isr, int pid, ulong addr, void *v, uint n) { int i; u32int u; uchar buf[4]; - addr += seg->base; for(i=0; i<n; i+=4){ if(isr){ errno = 0; - u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0); + u = ptrace(type, pid, addr+i, 0); if(errno) goto ptraceerr; if(n-i >= 4) @@ -150,14 +163,14 @@ ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr) u = *(u32int*)((char*)v+i); else{ errno = 0; - u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0); + u = ptrace(xtype, pid, addr+i, 0); if(errno) return -1; *(u32int*)buf = u; memmove(buf, (char*)v+i, n-i); u = *(u32int*)buf; } - if(ptrace(PTRACE_POKEDATA, seg->pid, addr+i, &u) < 0) + if(ptrace(type, pid, addr+i, &u) < 0) goto ptraceerr; } } @@ -168,6 +181,14 @@ ptraceerr: return -1; } +static int +ptracesegrw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr) +{ + addr += seg->base; + return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA, + isr, seg->pid, addr, v, n); +} + static char* linuxregs[] = { "BX", "CX", @@ -483,3 +504,191 @@ proctextfile(int pid) Bterm(b); #endif +/* + * bottom-end functions for libthread_db to call + */ +enum +{ + PS_OK, + PS_ERR, + PS_BADPID, + PS_BADLWPID, + PS_BADADDR, + PS_NOSYM, + PS_NOFPREGS, +}; + +pid_t +ps_getpid(struct ps_prochandle *ph) +{ + return ph->pid; +} + +int +ps_pstop(const struct ps_prochandle *ph) +{ + return PS_ERR; +} + +int +ps_pcontinue(const struct ps_prochandle *ph) +{ + return PS_ERR; +} + +int +ps_lstop(const struct ps_prochandle *ph) +{ + return PS_ERR; +} + +int +ps_lcontinue(const struct ps_prochandle *ph) +{ + return PS_ERR; +} + +/* read/write data or text memory */ +int +ps_pdread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) +{ +//print("read %d %p %d\n", ph->pid, addr, sz); + if(ptracerw(PTRACE_PEEKDATA, 0, 1, ph->pid, (ulong)addr, v, sz) < 0) + return PS_ERR; +//print(" => 0x%lux\n", *(ulong*)v); + return PS_OK; +} + +int +ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) +{ +//print("write %d %p\n", ph->pid, addr); + if(ptracerw(PTRACE_POKEDATA, PTRACE_PEEKDATA, 0, ph->pid, (ulong)addr, v, sz) < 0) + return PS_ERR; + return PS_OK; +} + +int +ps_ptread(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) +{ +//print("read %d %p\n", ph->pid, addr); + if(ptracerw(PTRACE_PEEKTEXT, 0, 1, ph->pid, (ulong)addr, v, sz) < 0) + return PS_ERR; + return PS_OK; +} + +int +ps_ptwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz) +{ +//print("write %d %p\n", ph->pid, addr); + if(ptracerw(PTRACE_POKETEXT, PTRACE_PEEKTEXT, 0, ph->pid, (ulong)addr, v, sz) < 0) + return PS_ERR; + return PS_OK; +} + +int +ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs) +{ + if(lwp == 0){ + memset(regs, 0xfe, sizeof(regs[0])*nelem(linuxregs)); + return PS_OK; + } +//print("getregs %d %p (%d)\n", lwp, regs, sizeof(regs[0])*nelem(linuxregs)); + + if(ptraceattach(lwp) < 0){ + fprint(2, "ptrace attach: %r\n"); + return PS_ERR; + } + + if(ptracerw(PTRACE_PEEKUSER, 0, 1, lwp, 0, regs, sizeof(regs[0])*nelem(linuxregs)) < 0){ + fprint(2, "ptrace: %r\n"); + return PS_ERR; + } + return PS_OK; +} + +int +ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs) +{ +print("setregs %d\n", lwp); + if(ptracerw(PTRACE_POKEUSER, PTRACE_PEEKUSER, 1, lwp, 0, regs, sizeof(regs[0])*nelem(linuxregs)) < 0) + return PS_ERR; + return PS_OK; +} + +int +ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs) +{ + if(ptracerw(PTRACE_PEEKUSER, 0, 1, lwp, 18*4, fpregs, sizeof *fpregs) < 0) + return PS_ERR; + return PS_OK; +} + +int +ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs) +{ + if(ptracerw(PTRACE_POKEUSER, PTRACE_PEEKUSER, 1, lwp, 18*4, fpregs, sizeof *fpregs) < 0) + return PS_ERR; + return PS_OK; +} + +/* Fetch the special per-thread address associated with the given LWP. + This call is only used on a few platforms (most use a normal register). + The meaning of the `int' parameter is machine-dependent. */ +int +ps_get_thread_area(struct ps_prochandle *ph, lwpid_t lwp, int xxx, psaddr_t *addr) +{ + return PS_NOSYM; +} + +/* Look up the named symbol in the named DSO in the symbol tables + associated with the process being debugged, filling in *SYM_ADDR + with the corresponding run-time address. */ +int +ps_pglobal_lookup(struct ps_prochandle *ph, char *object_name, char *sym_name, psaddr_t *sym_addr) +{ + Fhdr *fp; + ulong addr; + + if((fp = findhdr(object_name)) == nil){ +print("lookup %d %s %s => no such hdr\n", ph->pid, object_name, sym_name); + return PS_NOSYM; + } + if(elfsymlookup(fp->elf, sym_name, &addr) < 0){ +print("lookup %d %s %s => name not found\n", ph->pid, object_name, sym_name); + return PS_NOSYM; + } +print("lookup %d %s %s => 0x%lux\n", ph->pid, object_name, sym_name, addr); + *sym_addr = (void*)(addr+fp->base); + return PS_OK; +} + +Ureg* +_linux2ureg386(UregLinux386 *l) +{ + Ureg *u; + + u = malloc(sizeof(Ureg)); + if(u == nil) + return nil; + u->di = l->edi; + u->si = l->esi; + u->bp = l->ebp; + u->nsp = l->esp; + u->bx = l->ebx; + u->dx = l->edx; + u->cx = l->ecx; + u->ax = l->eax; + u->gs = l->xgs; + u->fs = l->xfs; + u->es = l->xes; + u->ds = l->xds; + u->trap = ~0; // l->trapno; + u->ecode = ~0; // l->err; + u->pc = l->eip; + u->cs = l->xcs; + u->flags = l->eflags; + u->sp = l->esp; + u->ss = l->xss; + return u; +} |