mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
better unwinding for 386.
command-line extraction from core files on linux and freebsd. move linux ureg into ureg386.h (used in many places).
This commit is contained in:
parent
cdf1805191
commit
1cc215aaf9
13 changed files with 495 additions and 109 deletions
|
@ -18,10 +18,12 @@
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <sys/procfs.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <mach.h>
|
#include <mach.h>
|
||||||
|
#include <elf.h>
|
||||||
#include "ureg386.h"
|
#include "ureg386.h"
|
||||||
|
|
||||||
Mach *machcpu = &mach386;
|
Mach *machcpu = &mach386;
|
||||||
|
@ -34,42 +36,27 @@ struct PtraceRegs
|
||||||
int pid;
|
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 ptraceregrw(Regs*, char*, ulong*, int);
|
||||||
|
|
||||||
static int attachedpids[1000];
|
static int attachedpids[1000];
|
||||||
static int nattached;
|
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
|
int
|
||||||
mapproc(int pid, Map *map, Regs **rp)
|
ptraceattach(int pid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Seg s;
|
|
||||||
PtraceRegs *r;
|
|
||||||
|
|
||||||
|
/*
|
||||||
if(nattached==1 && attachedpids[0] == pid)
|
if(nattached==1 && attachedpids[0] == pid)
|
||||||
goto already;
|
goto already;
|
||||||
if(nattached)
|
if(nattached)
|
||||||
detachproc(attachedpids[0]);
|
detachproc(attachedpids[0]);
|
||||||
|
*/
|
||||||
|
|
||||||
for(i=0; i<nattached; i++)
|
for(i=0; i<nattached; i++)
|
||||||
if(attachedpids[i]==pid)
|
if(attachedpids[i]==pid)
|
||||||
goto already;
|
return 0;
|
||||||
if(nattached == nelem(attachedpids)){
|
if(nattached == nelem(attachedpids)){
|
||||||
werrstr("attached to too many processes");
|
werrstr("attached to too many processes");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -86,15 +73,42 @@ mapproc(int pid, Map *map, Regs **rp)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
attachedpids[nattached++] = pid;
|
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);
|
memset(&s, 0, sizeof s);
|
||||||
s.base = 0;
|
s.base = 0;
|
||||||
s.size = 0xFFFFFFFF;
|
s.size = 0xFFFFFFFF;
|
||||||
s.offset = 0;
|
s.offset = 0;
|
||||||
s.name = "data";
|
s.name = "data";
|
||||||
s.file = nil;
|
s.file = nil;
|
||||||
s.rw = ptracerw;
|
s.rw = ptracesegrw;
|
||||||
s.pid = pid;
|
s.pid = pid;
|
||||||
if(addseg(map, s) < 0){
|
if(addseg(map, s) < 0){
|
||||||
fprint(2, "addseg: %r\n");
|
fprint(2, "addseg: %r\n");
|
||||||
|
@ -126,17 +140,16 @@ detachproc(int pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
int i;
|
||||||
u32int u;
|
u32int u;
|
||||||
uchar buf[4];
|
uchar buf[4];
|
||||||
|
|
||||||
addr += seg->base;
|
|
||||||
for(i=0; i<n; i+=4){
|
for(i=0; i<n; i+=4){
|
||||||
if(isr){
|
if(isr){
|
||||||
errno = 0;
|
errno = 0;
|
||||||
u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
|
u = ptrace(type, pid, addr+i, 0);
|
||||||
if(errno)
|
if(errno)
|
||||||
goto ptraceerr;
|
goto ptraceerr;
|
||||||
if(n-i >= 4)
|
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);
|
u = *(u32int*)((char*)v+i);
|
||||||
else{
|
else{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
|
u = ptrace(xtype, pid, addr+i, 0);
|
||||||
if(errno)
|
if(errno)
|
||||||
return -1;
|
return -1;
|
||||||
*(u32int*)buf = u;
|
*(u32int*)buf = u;
|
||||||
memmove(buf, (char*)v+i, n-i);
|
memmove(buf, (char*)v+i, n-i);
|
||||||
u = *(u32int*)buf;
|
u = *(u32int*)buf;
|
||||||
}
|
}
|
||||||
if(ptrace(PTRACE_POKEDATA, seg->pid, addr+i, &u) < 0)
|
if(ptrace(type, pid, addr+i, &u) < 0)
|
||||||
goto ptraceerr;
|
goto ptraceerr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +181,14 @@ ptraceerr:
|
||||||
return -1;
|
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[] = {
|
static char* linuxregs[] = {
|
||||||
"BX",
|
"BX",
|
||||||
"CX",
|
"CX",
|
||||||
|
@ -483,3 +504,191 @@ proctextfile(int pid)
|
||||||
Bterm(b);
|
Bterm(b);
|
||||||
#endif
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -40,11 +40,18 @@ static struct
|
||||||
uint mtype;
|
uint mtype;
|
||||||
uint atype;
|
uint atype;
|
||||||
int (*coreregs)(Elf*, ElfNote*, uchar**);
|
int (*coreregs)(Elf*, ElfNote*, uchar**);
|
||||||
|
int (*corecmd)(Elf*, ElfNote*, char**);
|
||||||
} ctab[] =
|
} ctab[] =
|
||||||
{ /* Font Tab 4 */
|
{ /* Font Tab 4 */
|
||||||
M386, ALINUX, coreregslinux386,
|
M386, ALINUX,
|
||||||
M386, ANONE, coreregslinux386, /* [sic] */
|
coreregslinux386,
|
||||||
M386, AFREEBSD, coreregsfreebsd386,
|
corecmdlinux386,
|
||||||
|
M386, ANONE,
|
||||||
|
coreregslinux386, /* [sic] */
|
||||||
|
corecmdlinux386, /* [sic] */
|
||||||
|
M386, AFREEBSD,
|
||||||
|
coreregsfreebsd386,
|
||||||
|
corecmdfreebsd386,
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -218,6 +218,7 @@ struct Elf
|
||||||
ElfSect *dynsym;
|
ElfSect *dynsym;
|
||||||
ElfSect *dynstr;
|
ElfSect *dynstr;
|
||||||
ElfSect *bss;
|
ElfSect *bss;
|
||||||
|
ulong dynamic; /* offset to elf dynamic crap */
|
||||||
|
|
||||||
int (*coreregs)(Elf*, ElfNote*, uchar**);
|
int (*coreregs)(Elf*, ElfNote*, uchar**);
|
||||||
};
|
};
|
||||||
|
@ -227,7 +228,10 @@ Elf* elfinit(int);
|
||||||
ElfSect *elfsection(Elf*, char*);
|
ElfSect *elfsection(Elf*, char*);
|
||||||
void elfclose(Elf*);
|
void elfclose(Elf*);
|
||||||
int elfsym(Elf*, int, ElfSym*);
|
int elfsym(Elf*, int, ElfSym*);
|
||||||
|
int elfsymlookup(Elf*, char*, ulong*);
|
||||||
int elfmap(Elf*, ElfSect*);
|
int elfmap(Elf*, ElfSect*);
|
||||||
|
|
||||||
int coreregslinux386(Elf*, ElfNote*, uchar**);
|
int coreregslinux386(Elf*, ElfNote*, uchar**);
|
||||||
int coreregsfreebsd386(Elf*, ElfNote*, uchar**);
|
int coreregsfreebsd386(Elf*, ElfNote*, uchar**);
|
||||||
|
int corecmdlinux386(Elf*, ElfNote*, char**);
|
||||||
|
int corecmdfreebsd386(Elf*, ElfNote*, char**);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
typedef struct Lreg Lreg;
|
typedef struct Lreg Lreg;
|
||||||
typedef struct Status Status;
|
typedef struct Status Status;
|
||||||
|
typedef struct Psinfo Psinfo;
|
||||||
|
|
||||||
struct Lreg
|
struct Lreg
|
||||||
{
|
{
|
||||||
|
@ -32,14 +33,22 @@ struct Lreg
|
||||||
|
|
||||||
struct Status
|
struct Status
|
||||||
{
|
{
|
||||||
u32int version; /* Version number of struct (1) */
|
u32int version; /* Version number of struct (1) */
|
||||||
u32int statussz; /* sizeof(prstatus_t) (1) */
|
u32int statussz; /* sizeof(prstatus_t) (1) */
|
||||||
u32int gregsetsz; /* sizeof(gregset_t) (1) */
|
u32int gregsetsz; /* sizeof(gregset_t) (1) */
|
||||||
u32int fpregsetsz; /* sizeof(fpregset_t) (1) */
|
u32int fpregsetsz; /* sizeof(fpregset_t) (1) */
|
||||||
u32int osreldate; /* Kernel version (1) */
|
u32int osreldate; /* Kernel version (1) */
|
||||||
u32int cursig; /* Current signal (1) */
|
u32int cursig; /* Current signal (1) */
|
||||||
u32int pid; /* Process ID (1) */
|
u32int pid; /* Process ID (1) */
|
||||||
Lreg reg; /* General purpose registers (1) */
|
Lreg reg; /* General purpose registers (1) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Psinfo
|
||||||
|
{
|
||||||
|
u32int version;
|
||||||
|
u32int size;
|
||||||
|
char name[17];
|
||||||
|
char psargs[81];
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -87,3 +96,25 @@ coreregsfreebsd386(Elf *elf, ElfNote *note, uchar **up)
|
||||||
return sizeof(Ureg);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,30 +6,10 @@
|
||||||
|
|
||||||
typedef struct Lreg Lreg;
|
typedef struct Lreg Lreg;
|
||||||
typedef struct Status Status;
|
typedef struct Status Status;
|
||||||
|
typedef struct Psinfo Psinfo;
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
* have any packing problems.
|
||||||
*/
|
*/
|
||||||
struct Status
|
struct Status
|
||||||
|
@ -48,15 +28,32 @@ struct Status
|
||||||
u32int stime[2];
|
u32int stime[2];
|
||||||
u32int cutime[2];
|
u32int cutime[2];
|
||||||
u32int cstime[2];
|
u32int cstime[2];
|
||||||
Lreg reg;
|
UregLinux386 reg;
|
||||||
u32int fpvalid;
|
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
|
int
|
||||||
coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
|
coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
|
||||||
{
|
{
|
||||||
Status *s;
|
Status *s;
|
||||||
Lreg *l;
|
UregLinux386 *l;
|
||||||
Ureg *u;
|
Ureg *u;
|
||||||
|
|
||||||
if(note->descsz < sizeof(Status)){
|
if(note->descsz < sizeof(Status)){
|
||||||
|
@ -65,31 +62,31 @@ coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
|
||||||
}
|
}
|
||||||
s = (Status*)note->desc;
|
s = (Status*)note->desc;
|
||||||
l = &s->reg;
|
l = &s->reg;
|
||||||
u = malloc(sizeof(Ureg));
|
if((u = _linux2ureg386(l)) == nil)
|
||||||
if(u == nil)
|
|
||||||
return -1;
|
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;
|
*up = (uchar*)u;
|
||||||
return sizeof(Ureg);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ stacktrace(Map *map, Regs *regs, Tracer trace)
|
||||||
lr.oldregs = regs;
|
lr.oldregs = regs;
|
||||||
lr.val = cur;
|
lr.val = cur;
|
||||||
lr.map = map;
|
lr.map = map;
|
||||||
if((i = unwindframe(map, &lr.r, next)) >= 0)
|
if((i = unwindframe(map, &lr.r, next, sp)) >= 0)
|
||||||
nextpc = next[ipc];
|
nextpc = next[ipc];
|
||||||
else
|
else
|
||||||
nextpc = ~(ulong)0;
|
nextpc = ~(ulong)0;
|
||||||
|
|
|
@ -29,7 +29,7 @@ static int i386hexinst(Map*, ulong, char*, int);
|
||||||
static int i386das(Map*, ulong, char, char*, int);
|
static int i386das(Map*, ulong, char, char*, int);
|
||||||
static int i386instlen(Map*, ulong);
|
static int i386instlen(Map*, ulong);
|
||||||
static char *i386windregs[];
|
static char *i386windregs[];
|
||||||
static int i386unwind(Map*, Regs*, ulong*);
|
static int i386unwind(Map*, Regs*, ulong*, Symbol*);
|
||||||
|
|
||||||
static Regdesc i386reglist[] = {
|
static Regdesc i386reglist[] = {
|
||||||
{"DI", REGOFF(di), RINT, 'X'},
|
{"DI", REGOFF(di), RINT, 'X'},
|
||||||
|
@ -128,14 +128,37 @@ static char *i386windregs[] = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
/*
|
||||||
i386unwind(Map *map, Regs *regs, ulong *next)
|
* 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)
|
||||||
{
|
{
|
||||||
int isp, ipc, ibp;
|
ulong pc;
|
||||||
ulong bp;
|
char buf[60];
|
||||||
u32int v;
|
|
||||||
|
|
||||||
/* No symbol information, use frame pointer and do the best we can. */
|
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, Symbol *sym)
|
||||||
|
{
|
||||||
|
int i, isp, ipc, ibp, havebp, n, spoff, off[9];
|
||||||
|
ulong pc;
|
||||||
|
u32int v;
|
||||||
|
char buf[60], *p;
|
||||||
|
|
||||||
|
//print("i386unwind %s\n", sym ? sym->name : nil);
|
||||||
isp = windindex("SP");
|
isp = windindex("SP");
|
||||||
ipc = windindex("PC");
|
ipc = windindex("PC");
|
||||||
ibp = windindex("BP");
|
ibp = windindex("BP");
|
||||||
|
@ -144,18 +167,84 @@ i386unwind(Map *map, Regs *regs, ulong *next)
|
||||||
return -1;
|
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)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rely on bp chaining
|
||||||
|
*/
|
||||||
|
if(rget(regs, "BP", &next[isp]) < 0
|
||||||
|
|| get4(map, next[isp], &v) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
next[ibp] = v;
|
next[ibp] = v;
|
||||||
|
next[isp] += 4;
|
||||||
next[isp] = bp+4;
|
if(get4(map, next[isp], &v) < 0)
|
||||||
|
|
||||||
if(get4(map, bp+4, &v) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
next[ipc] = v;
|
next[ipc] = v;
|
||||||
|
next[isp] += 4;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1766,8 +1855,10 @@ pea(Instr *ip)
|
||||||
else {
|
else {
|
||||||
if (ip->base < 0)
|
if (ip->base < 0)
|
||||||
immediate(ip, ip->disp);
|
immediate(ip, ip->disp);
|
||||||
else
|
else {
|
||||||
|
bprint(ip, "%lux", ip->disp);
|
||||||
bprint(ip,"(%s%s)", ANAME(ip), reg[(uchar)ip->base]);
|
bprint(ip,"(%s%s)", ANAME(ip), reg[(uchar)ip->base]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ip->index >= 0)
|
if (ip->index >= 0)
|
||||||
bprint(ip,"(%s%s*%d)", ANAME(ip), reg[(uchar)ip->index], 1<<ip->ss);
|
bprint(ip,"(%s%s*%d)", ANAME(ip), reg[(uchar)ip->index], 1<<ip->ss);
|
||||||
|
|
|
@ -1337,7 +1337,7 @@ static char *powerwindregs[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
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
|
* This is tremendously hard. The best we're going to
|
||||||
|
|
|
@ -4,6 +4,7 @@ LIB=libmach.a
|
||||||
|
|
||||||
OFILES=\
|
OFILES=\
|
||||||
$SYSNAME.$O\
|
$SYSNAME.$O\
|
||||||
|
cmdline.$O\
|
||||||
crack.$O\
|
crack.$O\
|
||||||
crackelf.$O\
|
crackelf.$O\
|
||||||
crackmacho.$O\
|
crackmacho.$O\
|
||||||
|
@ -17,6 +18,7 @@ OFILES=\
|
||||||
dwarfpc.$O\
|
dwarfpc.$O\
|
||||||
dwarfpubnames.$O\
|
dwarfpubnames.$O\
|
||||||
elf.$O\
|
elf.$O\
|
||||||
|
elfdl386.$O\
|
||||||
elfcorefreebsd386.$O\
|
elfcorefreebsd386.$O\
|
||||||
elfcorelinux386.$O\
|
elfcorelinux386.$O\
|
||||||
frame.$O\
|
frame.$O\
|
||||||
|
@ -57,6 +59,13 @@ dwarfdump: dwarfdump.o $LIBDIR/$LIB
|
||||||
nm: nm.o $LIBDIR/$LIB
|
nm: nm.o $LIBDIR/$LIB
|
||||||
$LD -o $target $prereq -l9
|
$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
|
SunOS.$O: nosys.c
|
||||||
Darwin.$O: nosys.c
|
Darwin.$O: nosys.c
|
||||||
OpenBSD.$O: nosys.c
|
OpenBSD.$O: nosys.c
|
||||||
|
|
|
@ -50,6 +50,23 @@ _delhdr(Fhdr *h)
|
||||||
h->next = nil;
|
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
|
int
|
||||||
pc2file(ulong pc, char *file, uint nfile, ulong *line)
|
pc2file(ulong pc, char *file, uint nfile, ulong *line)
|
||||||
{
|
{
|
||||||
|
@ -354,14 +371,14 @@ findlsym(Symbol *s1, Loc loc, Symbol *s2)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
unwindframe(Map *map, Regs *regs, ulong *next)
|
unwindframe(Map *map, Regs *regs, ulong *next, Symbol *sym)
|
||||||
{
|
{
|
||||||
Fhdr *p;
|
Fhdr *p;
|
||||||
|
|
||||||
for(p=fhdrlist; p; p=p->next)
|
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;
|
return 0;
|
||||||
if(mach->unwind && mach->unwind(map, regs, next) >= 0)
|
if(mach->unwind && mach->unwind(map, regs, next, sym) >= 0)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ static int dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
|
||||||
static int dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
|
static int dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
|
||||||
static void dwarfsyminit(Fhdr*);
|
static void dwarfsyminit(Fhdr*);
|
||||||
static int dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
|
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
|
int
|
||||||
symdwarf(Fhdr *hdr)
|
symdwarf(Fhdr *hdr)
|
||||||
|
@ -396,7 +396,7 @@ dwarfexprfmt(Fmt *fmt)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next)
|
_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next, Symbol *sym)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
|
@ -53,6 +53,7 @@ elfsyminit(Fhdr *fp)
|
||||||
p = &elf->prog[i];
|
p = &elf->prog[i];
|
||||||
if(p->type != ElfProgDynamic)
|
if(p->type != ElfProgDynamic)
|
||||||
continue;
|
continue;
|
||||||
|
elf->dynamic = p->vaddr;
|
||||||
memset(&sym, 0, sizeof sym);
|
memset(&sym, 0, sizeof sym);
|
||||||
sym.name = "_DYNAMIC";
|
sym.name = "_DYNAMIC";
|
||||||
sym.loc = locaddr(p->vaddr);
|
sym.loc = locaddr(p->vaddr);
|
||||||
|
@ -64,6 +65,23 @@ elfsyminit(Fhdr *fp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
int
|
||||||
symelf(Fhdr *fhdr)
|
symelf(Fhdr *fhdr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,7 @@ struct UregLinux386
|
||||||
ulong ecx;
|
ulong ecx;
|
||||||
ulong edx;
|
ulong edx;
|
||||||
ulong esi;
|
ulong esi;
|
||||||
|
ulong edi;
|
||||||
ulong ebp;
|
ulong ebp;
|
||||||
ulong eax;
|
ulong eax;
|
||||||
ulong xds;
|
ulong xds;
|
||||||
|
@ -43,3 +44,5 @@ struct UregLinux386
|
||||||
ulong xss;
|
ulong xss;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Ureg *_linux2ureg386(UregLinux386*);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue