aboutsummaryrefslogtreecommitdiff
path: root/src/libmach
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmach')
-rw-r--r--src/libmach/Linux.c265
-rw-r--r--src/libmach/crackelf.c13
-rw-r--r--src/libmach/elf.h4
-rw-r--r--src/libmach/elfcorefreebsd386.c47
-rw-r--r--src/libmach/elfcorelinux386.c91
-rw-r--r--src/libmach/frame.c2
-rw-r--r--src/libmach/mach386.c119
-rw-r--r--src/libmach/machpower.c2
-rw-r--r--src/libmach/mkfile9
-rw-r--r--src/libmach/sym.c23
-rw-r--r--src/libmach/symdwarf.c4
-rw-r--r--src/libmach/symelf.c18
-rw-r--r--src/libmach/ureg386.h3
13 files changed, 493 insertions, 107 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;
+}
diff --git a/src/libmach/crackelf.c b/src/libmach/crackelf.c
index eb99947d..f0f84230 100644
--- a/src/libmach/crackelf.c
+++ b/src/libmach/crackelf.c
@@ -40,11 +40,18 @@ static struct
uint mtype;
uint atype;
int (*coreregs)(Elf*, ElfNote*, uchar**);
+ int (*corecmd)(Elf*, ElfNote*, char**);
} ctab[] =
{ /* Font Tab 4 */
- M386, ALINUX, coreregslinux386,
- M386, ANONE, coreregslinux386, /* [sic] */
- M386, AFREEBSD, coreregsfreebsd386,
+ M386, ALINUX,
+ coreregslinux386,
+ corecmdlinux386,
+ M386, ANONE,
+ coreregslinux386, /* [sic] */
+ corecmdlinux386, /* [sic] */
+ M386, AFREEBSD,
+ coreregsfreebsd386,
+ corecmdfreebsd386,
};
int
diff --git a/src/libmach/elf.h b/src/libmach/elf.h
index 6ed239bc..d4b459e1 100644
--- a/src/libmach/elf.h
+++ b/src/libmach/elf.h
@@ -218,6 +218,7 @@ struct Elf
ElfSect *dynsym;
ElfSect *dynstr;
ElfSect *bss;
+ ulong dynamic; /* offset to elf dynamic crap */
int (*coreregs)(Elf*, ElfNote*, uchar**);
};
@@ -227,7 +228,10 @@ Elf* elfinit(int);
ElfSect *elfsection(Elf*, char*);
void elfclose(Elf*);
int elfsym(Elf*, int, ElfSym*);
+int elfsymlookup(Elf*, char*, ulong*);
int elfmap(Elf*, ElfSect*);
int coreregslinux386(Elf*, ElfNote*, uchar**);
int coreregsfreebsd386(Elf*, ElfNote*, uchar**);
+int corecmdlinux386(Elf*, ElfNote*, char**);
+int corecmdfreebsd386(Elf*, ElfNote*, char**);
diff --git a/src/libmach/elfcorefreebsd386.c b/src/libmach/elfcorefreebsd386.c
index 2ff746de..84f6c0fd 100644
--- a/src/libmach/elfcorefreebsd386.c
+++ b/src/libmach/elfcorefreebsd386.c
@@ -6,6 +6,7 @@
typedef struct Lreg Lreg;
typedef struct Status Status;
+typedef struct Psinfo Psinfo;
struct Lreg
{
@@ -32,14 +33,22 @@ struct Lreg
struct Status
{
- u32int version; /* Version number of struct (1) */
- u32int statussz; /* sizeof(prstatus_t) (1) */
- u32int gregsetsz; /* sizeof(gregset_t) (1) */
- u32int fpregsetsz; /* sizeof(fpregset_t) (1) */
- u32int osreldate; /* Kernel version (1) */
- u32int cursig; /* Current signal (1) */
- u32int pid; /* Process ID (1) */
- Lreg reg; /* General purpose registers (1) */
+ u32int version; /* Version number of struct (1) */
+ u32int statussz; /* sizeof(prstatus_t) (1) */
+ u32int gregsetsz; /* sizeof(gregset_t) (1) */
+ u32int fpregsetsz; /* sizeof(fpregset_t) (1) */
+ u32int osreldate; /* Kernel version (1) */
+ u32int cursig; /* Current signal (1) */
+ u32int pid; /* Process ID (1) */
+ Lreg reg; /* General purpose registers (1) */
+};
+
+struct Psinfo
+{
+ u32int version;
+ u32int size;
+ char name[17];
+ char psargs[81];
};
int
@@ -87,3 +96,25 @@ coreregsfreebsd386(Elf *elf, ElfNote *note, uchar **up)
return sizeof(Ureg);
}
+int
+corecmdfreebsd386(Elf *elf, ElfNote *note, char **pp)
+{
+ char *t;
+ Psinfo *p;
+
+ *pp = nil;
+ if(note->descsz < sizeof(Psinfo)){
+ werrstr("elf psinfo note too small");
+ return -1;
+ }
+ p = (Psinfo*)note->desc;
+ print("elf name %s\nelf args %s\n", p->name, p->psargs);
+ t = malloc(80+1);
+ if(t == nil)
+ return -1;
+ memmove(t, p->psargs, 80);
+ t[80] = 0;
+ *pp = t;
+ return 0;
+}
+
diff --git a/src/libmach/elfcorelinux386.c b/src/libmach/elfcorelinux386.c
index f6a0234c..18f8bdfe 100644
--- a/src/libmach/elfcorelinux386.c
+++ b/src/libmach/elfcorelinux386.c
@@ -6,30 +6,10 @@
typedef struct Lreg Lreg;
typedef struct Status Status;
-
-struct Lreg
-{
- u32int ebx;
- u32int ecx;
- u32int edx;
- u32int esi;
- u32int edi;
- u32int ebp;
- u32int eax;
- u32int ds;
- u32int es;
- u32int fs;
- u32int gs;
- u32int origeax;
- u32int eip;
- u32int cs;
- u32int eflags;
- u32int esp;
- u32int ss;
-};
+typedef struct Psinfo Psinfo;
/*
- * Lreg is 64-bit aligned within status, so we shouldn't
+ * UregLinux386 is 64-bit aligned within status, so we shouldn't
* have any packing problems.
*/
struct Status
@@ -48,15 +28,32 @@ struct Status
u32int stime[2];
u32int cutime[2];
u32int cstime[2];
- Lreg reg;
+ UregLinux386 reg;
u32int fpvalid;
};
+struct Psinfo
+{
+ char state;
+ char sname;
+ char zomb;
+ char nice;
+ u32int flag;
+ u16int uid;
+ u16int gid;
+ u32int pid;
+ u32int ppid;
+ u32int pgrp;
+ u32int sid;
+ char fname[16];
+ char psargs[80];
+};
+
int
coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
{
Status *s;
- Lreg *l;
+ UregLinux386 *l;
Ureg *u;
if(note->descsz < sizeof(Status)){
@@ -65,31 +62,31 @@ coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
}
s = (Status*)note->desc;
l = &s->reg;
- u = malloc(sizeof(Ureg));
- if(u == nil)
+ if((u = _linux2ureg386(l)) == nil)
return -1;
-
- /* no byte order problems - just copying and rearranging */
- 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->gs;
- u->fs = l->fs;
- u->es = l->es;
- u->ds = l->ds;
- u->trap = ~0; // l->trapno;
- u->ecode = ~0; // l->err;
- u->pc = l->eip;
- u->cs = l->cs;
- u->flags = l->eflags;
- u->sp = l->esp;
- u->ss = l->ss;
*up = (uchar*)u;
return sizeof(Ureg);
}
+int
+corecmdlinux386(Elf *elf, ElfNote *note, char **pp)
+{
+ char *t;
+ Psinfo *p;
+
+ *pp = nil;
+ if(note->descsz < sizeof(Psinfo)){
+ werrstr("elf psinfo note too small");
+ return -1;
+ }
+ p = (Psinfo*)note->desc;
+ print("elf name %s\nelf args %s\n", p->fname, p->psargs);
+ t = malloc(80+1);
+ if(t == nil)
+ return -1;
+ memmove(t, p->psargs, 80);
+ t[80] = 0;
+ *pp = t;
+ return 0;
+}
+
diff --git a/src/libmach/frame.c b/src/libmach/frame.c
index 6e448519..035c6a52 100644
--- a/src/libmach/frame.c
+++ b/src/libmach/frame.c
@@ -79,7 +79,7 @@ stacktrace(Map *map, Regs *regs, Tracer trace)
lr.oldregs = regs;
lr.val = cur;
lr.map = map;
- if((i = unwindframe(map, &lr.r, next)) >= 0)
+ if((i = unwindframe(map, &lr.r, next, sp)) >= 0)
nextpc = next[ipc];
else
nextpc = ~(ulong)0;
diff --git a/src/libmach/mach386.c b/src/libmach/mach386.c
index 4b43683e..b47fcd55 100644
--- a/src/libmach/mach386.c
+++ b/src/libmach/mach386.c
@@ -29,7 +29,7 @@ static int i386hexinst(Map*, ulong, char*, int);
static int i386das(Map*, ulong, char, char*, int);
static int i386instlen(Map*, ulong);
static char *i386windregs[];
-static int i386unwind(Map*, Regs*, ulong*);
+static int i386unwind(Map*, Regs*, ulong*, Symbol*);
static Regdesc i386reglist[] = {
{"DI", REGOFF(di), RINT, 'X'},
@@ -128,14 +128,37 @@ static char *i386windregs[] = {
0,
};
+/*
+ * The wrapper code around Linux system calls
+ * saves AX on the stack before calling some calls
+ * (at least, __libc_nanosleep), when running in
+ * threaded programs.
+ */
+static void
+syscallhack(Map *map, Regs *regs, int *spoff)
+{
+ ulong pc;
+ char buf[60];
+
+ rget(regs, "PC", &pc);
+ if(i386das(map, pc-2, 0, buf, sizeof buf) != 2 || strncmp(buf, "INTB\t$", 6) != 0)
+ return;
+ if(i386das(map, pc, 0, buf, sizeof buf) != 2 || strcmp(buf, "MOVL\tDX,BX") != 0)
+ return;
+ if(i386das(map, pc+2, 0, buf, sizeof buf) != 3 || strcmp(buf, "XCHGL\tAX,0(SP)") != 0)
+ return;
+ *spoff += 4;
+}
+
static int
-i386unwind(Map *map, Regs *regs, ulong *next)
+i386unwind(Map *map, Regs *regs, ulong *next, Symbol *sym)
{
- int isp, ipc, ibp;
- ulong bp;
+ int i, isp, ipc, ibp, havebp, n, spoff, off[9];
+ ulong pc;
u32int v;
+ char buf[60], *p;
- /* No symbol information, use frame pointer and do the best we can. */
+//print("i386unwind %s\n", sym ? sym->name : nil);
isp = windindex("SP");
ipc = windindex("PC");
ibp = windindex("BP");
@@ -144,19 +167,85 @@ i386unwind(Map *map, Regs *regs, ulong *next)
return -1;
}
- bp = next[ibp];
+ /*
+ * Disassemble entry to figure out
+ * where values have been saved.
+ * Perhaps should disassemble exit path
+ * instead -- a random walk on the code
+ * should suffice to get us to a RET.
+ */
+ if(sym){
+ pc = sym->loc.addr;
+//print("startpc %lux\n", pc);
+ memset(off, 0xff, sizeof off);
+ spoff = 0;
+ havebp = 0;
+ for(;;){
+ if((n = i386das(map, pc, 0, buf, sizeof buf)) < 0)
+ break;
+//print("%s\n", buf);
+ pc += n;
+ if(strncmp(buf, "PUSHL\t", 6) == 0){
+ spoff += 4;
+ if((i = windindex(buf+6)) >= 0)
+ off[i] = spoff;
+ }else if(strcmp(buf, "MOVL\tSP,BP") == 0 && spoff == 4 && off[ibp] == 4){
+ havebp = 1;
+ }else if(strncmp(buf, "SUBL\t$", 6) == 0){
+ if((p = strrchr(buf, ',')) && strcmp(p, ",SP") == 0){
+//print("spoff %s\n", buf+6);
+ spoff += strtol(buf+6, 0, 16);
+ }
+ break;
+ }else if(strncmp(buf, "XORL\t", 5) == 0 || strncmp(buf, "MOVL\t", 5) == 0){
+ /*
+ * Hope these are rescheduled non-prologue instructions
+ * like XORL AX, AX or MOVL $0x3, AX and thus ignorable.
+ */
+ }else
+ break;
+ }
- if(get4(map, bp, &v) < 0)
- return -1;
- next[ibp] = v;
+ syscallhack(map, regs, &spoff);
+
+ if(havebp){
+//print("havebp\n");
+ rget(regs, "BP", &next[isp]);
+ get4(map, next[isp], &v);
+ next[ibp] = v;
+ next[isp] += 4;
+ }else{
+ rget(regs, "SP", &next[isp]);
+//print("old sp %lux + %d\n", next[isp], spoff);
+ next[isp] += spoff;
+ }
+ for(i=0; i<nelem(off); i++)
+ if(off[i] != -1){
+ get4(map, next[isp]-off[i], &v);
+ next[i] = v;
+ }
- next[isp] = bp+4;
+ if(get4(map, next[isp], &v) < 0)
+ return -1;
+//print("new pc %lux => %lux\n", next[isp], v);
+ next[ipc] = v;
+ next[isp] += 4;
+ return 0;
+ }
- if(get4(map, bp+4, &v) < 0)
+ /*
+ * Rely on bp chaining
+ */
+ if(rget(regs, "BP", &next[isp]) < 0
+ || get4(map, next[isp], &v) < 0)
+ return -1;
+ next[ibp] = v;
+ next[isp] += 4;
+ if(get4(map, next[isp], &v) < 0)
return -1;
next[ipc] = v;
-
- return 0;
+ next[isp] += 4;
+ return 0;
}
//static char STARTSYM[] = "_main";
@@ -1766,8 +1855,10 @@ pea(Instr *ip)
else {
if (ip->base < 0)
immediate(ip, ip->disp);
- else
+ else {
+ bprint(ip, "%lux", ip->disp);
bprint(ip,"(%s%s)", ANAME(ip), reg[(uchar)ip->base]);
+ }
}
if (ip->index >= 0)
bprint(ip,"(%s%s*%d)", ANAME(ip), reg[(uchar)ip->index], 1<<ip->ss);
diff --git a/src/libmach/machpower.c b/src/libmach/machpower.c
index c704be7f..61917216 100644
--- a/src/libmach/machpower.c
+++ b/src/libmach/machpower.c
@@ -1337,7 +1337,7 @@ static char *powerwindregs[] =
};
static int
-powerunwind(Map *map, Regs *regs, ulong *next)
+powerunwind(Map *map, Regs *regs, ulong *next, Symbol *sym)
{
/*
* This is tremendously hard. The best we're going to
diff --git a/src/libmach/mkfile b/src/libmach/mkfile
index 77426436..8ebe0374 100644
--- a/src/libmach/mkfile
+++ b/src/libmach/mkfile
@@ -4,6 +4,7 @@ LIB=libmach.a
OFILES=\
$SYSNAME.$O\
+ cmdline.$O\
crack.$O\
crackelf.$O\
crackmacho.$O\
@@ -17,6 +18,7 @@ OFILES=\
dwarfpc.$O\
dwarfpubnames.$O\
elf.$O\
+ elfdl386.$O\
elfcorefreebsd386.$O\
elfcorelinux386.$O\
frame.$O\
@@ -57,6 +59,13 @@ dwarfdump: dwarfdump.o $LIBDIR/$LIB
nm: nm.o $LIBDIR/$LIB
$LD -o $target $prereq -l9
+t: t.o $LIBDIR/$LIB
+ $LD -o $target $prereq -l9 -lthread_db
+
+elfnm: elfnm.o $LIBDIR/$LIB
+ $LD -o $target $prereq -l9
+
+
SunOS.$O: nosys.c
Darwin.$O: nosys.c
OpenBSD.$O: nosys.c
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
index b734957f..a5cf0314 100644
--- a/src/libmach/sym.c
+++ b/src/libmach/sym.c
@@ -50,6 +50,23 @@ _delhdr(Fhdr *h)
h->next = nil;
}
+Fhdr*
+findhdr(char *name)
+{
+ int len, plen;
+ Fhdr *p;
+
+ len = strlen(name);
+ for(p=fhdrlist; p; p=p->next){
+ plen = strlen(p->filename);
+ if(plen >= len)
+ if(strcmp(p->filename+plen-len, name) == 0)
+ if(plen == len || p->filename[plen-len-1] == '/')
+ return p;
+ }
+ return nil;
+}
+
int
pc2file(ulong pc, char *file, uint nfile, ulong *line)
{
@@ -354,14 +371,14 @@ findlsym(Symbol *s1, Loc loc, Symbol *s2)
}
int
-unwindframe(Map *map, Regs *regs, ulong *next)
+unwindframe(Map *map, Regs *regs, ulong *next, Symbol *sym)
{
Fhdr *p;
for(p=fhdrlist; p; p=p->next)
- if(p->unwind && p->unwind(p, map, regs, next) >= 0)
+ if(p->unwind && p->unwind(p, map, regs, next, sym) >= 0)
return 0;
- if(mach->unwind && mach->unwind(map, regs, next) >= 0)
+ if(mach->unwind && mach->unwind(map, regs, next, sym) >= 0)
return 0;
return -1;
}
diff --git a/src/libmach/symdwarf.c b/src/libmach/symdwarf.c
index eeafa8dc..3ac12577 100644
--- a/src/libmach/symdwarf.c
+++ b/src/libmach/symdwarf.c
@@ -13,7 +13,7 @@ static int dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
static int dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
static void dwarfsyminit(Fhdr*);
static int dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
-static int _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next);
+static int _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next, Symbol*);
int
symdwarf(Fhdr *hdr)
@@ -396,7 +396,7 @@ dwarfexprfmt(Fmt *fmt)
#endif
static int
-_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next)
+_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next, Symbol *sym)
{
char *name;
int i, j;
diff --git a/src/libmach/symelf.c b/src/libmach/symelf.c
index 7babbd49..0b9f410e 100644
--- a/src/libmach/symelf.c
+++ b/src/libmach/symelf.c
@@ -53,6 +53,7 @@ elfsyminit(Fhdr *fp)
p = &elf->prog[i];
if(p->type != ElfProgDynamic)
continue;
+ elf->dynamic = p->vaddr;
memset(&sym, 0, sizeof sym);
sym.name = "_DYNAMIC";
sym.loc = locaddr(p->vaddr);
@@ -65,6 +66,23 @@ elfsyminit(Fhdr *fp)
}
int
+elfsymlookup(Elf *elf, char *name, ulong *addr)
+{
+ int i;
+ ElfSym esym;
+
+ for(i=0; elfsym(elf, i, &esym) >= 0; i++){
+ if(esym.name == nil)
+ continue;
+ if(strcmp(esym.name, name) == 0){
+ *addr = esym.value;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
symelf(Fhdr *fhdr)
{
int ret;
diff --git a/src/libmach/ureg386.h b/src/libmach/ureg386.h
index 961ef6d0..f5f9a474 100644
--- a/src/libmach/ureg386.h
+++ b/src/libmach/ureg386.h
@@ -29,6 +29,7 @@ struct UregLinux386
ulong ecx;
ulong edx;
ulong esi;
+ ulong edi;
ulong ebp;
ulong eax;
ulong xds;
@@ -43,3 +44,5 @@ struct UregLinux386
ulong xss;
};
+Ureg *_linux2ureg386(UregLinux386*);
+