aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/Linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmach/Linux.c')
-rw-r--r--src/libmach/Linux.c265
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;
+}