Start working through proper handling of pthreads when
debugging Linux core dumps. Pthreads for active processes is still not supported, nor are other systems.
This commit is contained in:
parent
a0e8d02d09
commit
dd944ec72a
14 changed files with 528 additions and 415 deletions
|
|
@ -168,7 +168,7 @@ ptracerw(int type, int xtype, int isr, int pid, ulong addr, void *v, uint n)
|
|||
memmove(buf, (char*)v+i, n-i);
|
||||
u = *(u32int*)buf;
|
||||
}
|
||||
if(ptrace(type, pid, addr+i, &u) < 0)
|
||||
if(ptrace(type, pid, addr+i, u) < 0)
|
||||
goto ptraceerr;
|
||||
}
|
||||
}
|
||||
|
|
@ -501,192 +501,3 @@ 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ alldigs(char *s)
|
|||
* attach to arguments in argc, argv
|
||||
*/
|
||||
int
|
||||
attachargs(int argc, char **argv, int omode)
|
||||
attachargs(int argc, char **argv, int omode, int verbose)
|
||||
{
|
||||
int i;
|
||||
Fhdr *hdr;
|
||||
char *s;
|
||||
char *s, *t;
|
||||
|
||||
symhdr = nil;
|
||||
corhdr = nil;
|
||||
|
|
@ -56,9 +56,9 @@ attachargs(int argc, char **argv, int omode)
|
|||
fprint(2, "crackhdr %s: %r\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
if(verbose)
|
||||
fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
|
||||
if(hdr->ftype == FCORE){
|
||||
fprint(2, "core cmd: %s\n", hdr->cmd);
|
||||
if(corpid){
|
||||
fprint(2, "already have corpid %d; ignoring core %s\n", corpid, argv[i]);
|
||||
uncrackhdr(hdr);
|
||||
|
|
@ -90,10 +90,21 @@ attachargs(int argc, char **argv, int omode)
|
|||
symfil = s;
|
||||
}
|
||||
}
|
||||
if(corhdr){ /* try from core */
|
||||
if(corhdr->txtfil != nil){
|
||||
fprint(2, "core %s: text %s\n", corfil, corhdr->txtfil);
|
||||
symfil = corhdr->txtfil;
|
||||
if(corhdr && corhdr->cmdline){ /* try from core */
|
||||
/*
|
||||
* prog gives only the basename of the command,
|
||||
* so try the command line for a path.
|
||||
*/
|
||||
if((s = strdup(corhdr->cmdline)) != nil){
|
||||
t = strchr(s, ' ');
|
||||
if(t)
|
||||
*t = 0;
|
||||
if((t = searchpath(s)) != nil){
|
||||
if(verbose)
|
||||
fprint(2, "core: text %s\n", t);
|
||||
symfil = t;
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
if((symhdr = crackhdr(symfil, omode)) == nil){
|
||||
|
|
@ -124,10 +135,10 @@ attachargs(int argc, char **argv, int omode)
|
|||
|
||||
if(corpid)
|
||||
attachproc(corpid);
|
||||
|
||||
if(corhdr)
|
||||
attachcore(corhdr);
|
||||
|
||||
attachdynamic(verbose);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +178,7 @@ int
|
|||
attachcore(Fhdr *hdr)
|
||||
{
|
||||
unattach();
|
||||
if(corhdr == nil)
|
||||
if(hdr == nil)
|
||||
return 0;
|
||||
if(mapfile(hdr, 0, cormap, &correg) < 0){
|
||||
fprint(2, "attachcore %s: %r\n", hdr->filename);
|
||||
|
|
@ -180,10 +191,12 @@ attachcore(Fhdr *hdr)
|
|||
}
|
||||
|
||||
int
|
||||
attachdynamic(void)
|
||||
attachdynamic(int verbose)
|
||||
{
|
||||
extern void elfdl386mapdl(void);
|
||||
elfdl386mapdl();
|
||||
extern void elfdl386mapdl(int);
|
||||
|
||||
if(mach && mach->type == M386 && symhdr && symhdr->elf)
|
||||
elfdl386mapdl(verbose);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <mach.h>
|
||||
#include "elf.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
|
|
@ -50,9 +51,18 @@ crackhdr(char *name, int mode)
|
|||
void
|
||||
uncrackhdr(Fhdr *hdr)
|
||||
{
|
||||
int i;
|
||||
|
||||
symclose(hdr);
|
||||
if(hdr->elf)
|
||||
elfclose(hdr->elf);
|
||||
if(hdr->fd >= 0)
|
||||
close(hdr->fd);
|
||||
_delhdr(hdr);
|
||||
free(hdr->cmd);
|
||||
free(hdr->cmdline);
|
||||
free(hdr->prog);
|
||||
for(i=0; i<hdr->nthread; i++)
|
||||
free(hdr->thread[i].ureg);
|
||||
free(hdr->thread);
|
||||
free(hdr);
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +81,8 @@ mapfile(Fhdr *fp, ulong base, Map *map, Regs **regs)
|
|||
werrstr("cannot load map for this file type");
|
||||
return -1;
|
||||
}
|
||||
if(regs)
|
||||
*regs = nil;
|
||||
return fp->map(fp, base, map, regs);
|
||||
}
|
||||
|
||||
|
|
@ -90,3 +102,23 @@ unmapfile(Fhdr *fp, Map *map)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Regs*
|
||||
coreregs(Fhdr *fp, uint id)
|
||||
{
|
||||
UregRegs *r;
|
||||
int i;
|
||||
|
||||
for(i=0; i<fp->nthread; i++){
|
||||
if(fp->thread[i].id == id){
|
||||
if((r = mallocz(sizeof *r, 1)) == nil)
|
||||
return nil;
|
||||
r->r.rw = _uregrw;
|
||||
r->ureg = fp->thread[i].ureg;
|
||||
return &r->r;
|
||||
}
|
||||
}
|
||||
werrstr("thread not found");
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
#include "dwarf.h"
|
||||
|
||||
static int mapelf(Fhdr *fp, ulong base, Map *map, Regs**);
|
||||
static int mapcoreregs(Fhdr *fp, Map *map, Regs**);
|
||||
static char *getcorecmd(Fhdr *fp);
|
||||
static int unpacknote(Elf *elf, uchar *a, uchar *ea, ElfNote *note, uchar **pa);
|
||||
|
||||
static struct
|
||||
{
|
||||
|
|
@ -40,28 +39,24 @@ static struct
|
|||
{
|
||||
uint mtype;
|
||||
uint atype;
|
||||
int (*coreregs)(Elf*, ElfNote*, uchar**);
|
||||
int (*corecmd)(Elf*, ElfNote*, char**);
|
||||
void (*elfcore)(Fhdr*, Elf*, ElfNote*);
|
||||
} ctab[] =
|
||||
{ /* Font Tab 4 */
|
||||
M386, ALINUX,
|
||||
coreregslinux386,
|
||||
corecmdlinux386,
|
||||
M386, ANONE,
|
||||
coreregslinux386, /* [sic] */
|
||||
corecmdlinux386, /* [sic] */
|
||||
M386, AFREEBSD,
|
||||
coreregsfreebsd386,
|
||||
corecmdfreebsd386,
|
||||
M386, ALINUX, elfcorelinux386,
|
||||
M386, ANONE, elfcorelinux386, /* [sic] */
|
||||
/* M386, AFREEBSD, elfcorefreebsd386, */
|
||||
};
|
||||
|
||||
int
|
||||
crackelf(int fd, Fhdr *fp)
|
||||
{
|
||||
int i, havetext, havedata;
|
||||
uchar *a, *sa, *ea;
|
||||
int i, havetext, havedata, n;
|
||||
Elf *elf;
|
||||
ElfNote note;
|
||||
ElfProg *p;
|
||||
ElfSect *s1, *s2;
|
||||
void (*elfcore)(Fhdr*, Elf*, ElfNote*);
|
||||
|
||||
if((elf = elfinit(fd)) == nil)
|
||||
return -1;
|
||||
|
|
@ -133,16 +128,37 @@ crackelf(int fd, Fhdr *fp)
|
|||
fp->map = mapelf;
|
||||
|
||||
if(fp->ftype == FCORE){
|
||||
elfcore = nil;
|
||||
for(i=0; i<nelem(ctab); i++){
|
||||
if(ctab[i].atype != fp->atype
|
||||
|| ctab[i].mtype != fp->mtype)
|
||||
continue;
|
||||
elf->coreregs = ctab[i].coreregs;
|
||||
elf->corecmd = ctab[i].corecmd;
|
||||
elfcore = ctab[i].elfcore;
|
||||
break;
|
||||
}
|
||||
if((fp->cmd = getcorecmd(fp)) == nil)
|
||||
fprint(2, "warning: reading core command: %r");
|
||||
if(elfcore)
|
||||
for(i=0; i<elf->nprog; i++){
|
||||
p = &elf->prog[i];
|
||||
if(p->type != ElfProgNote)
|
||||
continue;
|
||||
n = p->filesz;
|
||||
a = malloc(n);
|
||||
if(a == nil)
|
||||
goto err;
|
||||
if(seek(fp->fd, p->offset, 0) < 0 || readn(fp->fd, a, n) != n){
|
||||
free(a);
|
||||
continue;
|
||||
}
|
||||
sa = a;
|
||||
ea = a+n;
|
||||
while(a < ea){
|
||||
note.offset = (a-sa) + p->offset;
|
||||
if(unpacknote(elf, a, ea, ¬e, &a) < 0)
|
||||
break;
|
||||
elfcore(fp, elf, ¬e);
|
||||
}
|
||||
free(sa);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -258,10 +274,8 @@ mapelf(Fhdr *fp, ulong base, Map *map, Regs **regs)
|
|||
}
|
||||
}
|
||||
|
||||
if(fp->ftype == FCORE){
|
||||
if(mapcoreregs(fp, map, regs) < 0)
|
||||
fprint(2, "warning: reading core regs: %r");
|
||||
}
|
||||
if(fp->nthread && regs)
|
||||
*regs = coreregs(fp, fp->thread[0].id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -286,126 +300,3 @@ unpacknote(Elf *elf, uchar *a, uchar *ea, ElfNote *note, uchar **pa)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mapcoreregs(Fhdr *fp, Map *map, Regs **rp)
|
||||
{
|
||||
int i;
|
||||
uchar *a, *sa, *ea, *uregs;
|
||||
uint n;
|
||||
ElfNote note;
|
||||
ElfProg *p;
|
||||
Elf *elf;
|
||||
UregRegs *r;
|
||||
|
||||
elf = fp->elf;
|
||||
if(elf->coreregs == 0){
|
||||
werrstr("cannot parse %s %s cores", fp->mname, fp->aname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i=0; i<elf->nprog; i++){
|
||||
p = &elf->prog[i];
|
||||
if(p->type != ElfProgNote)
|
||||
continue;
|
||||
n = p->filesz;
|
||||
a = malloc(n);
|
||||
if(a == nil)
|
||||
return -1;
|
||||
if(seek(fp->fd, p->offset, 0) < 0 || readn(fp->fd, a, n) != n){
|
||||
free(a);
|
||||
continue;
|
||||
}
|
||||
sa = a;
|
||||
ea = a+n;
|
||||
while(a < ea){
|
||||
note.offset = (a-sa) + p->offset;
|
||||
if(unpacknote(elf, a, ea, ¬e, &a) < 0)
|
||||
break;
|
||||
switch(note.type){
|
||||
case ElfNotePrStatus:
|
||||
if((n = (*elf->coreregs)(elf, ¬e, &uregs)) < 0){
|
||||
free(sa);
|
||||
return -1;
|
||||
}
|
||||
free(sa);
|
||||
if((r = mallocz(sizeof(*r), 1)) == nil){
|
||||
free(uregs);
|
||||
return -1;
|
||||
}
|
||||
r->r.rw = _uregrw;
|
||||
r->ureg = uregs;
|
||||
*rp = &r->r;
|
||||
return 0;
|
||||
case ElfNotePrFpreg:
|
||||
case ElfNotePrPsinfo:
|
||||
case ElfNotePrTaskstruct:
|
||||
case ElfNotePrAuxv:
|
||||
case ElfNotePrXfpreg:
|
||||
break;
|
||||
}
|
||||
// fprint(2, "0x%lux note %s/%lud %p\n", note.offset, note.name, note.type, note.desc);
|
||||
}
|
||||
free(sa);
|
||||
}
|
||||
fprint(2, "could not find registers in core file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char*
|
||||
getcorecmd(Fhdr *fp)
|
||||
{
|
||||
int i;
|
||||
uchar *a, *sa, *ea;
|
||||
char *cmd;
|
||||
uint n;
|
||||
ElfNote note;
|
||||
ElfProg *p;
|
||||
Elf *elf;
|
||||
|
||||
elf = fp->elf;
|
||||
if(elf->corecmd == 0){
|
||||
werrstr("cannot parse %s %s cores", fp->mname, fp->aname);
|
||||
return nil;
|
||||
}
|
||||
|
||||
for(i=0; i<elf->nprog; i++){
|
||||
p = &elf->prog[i];
|
||||
if(p->type != ElfProgNote)
|
||||
continue;
|
||||
n = p->filesz;
|
||||
a = malloc(n);
|
||||
if(a == nil)
|
||||
return nil;
|
||||
if(seek(fp->fd, p->offset, 0) < 0 || readn(fp->fd, a, n) != n){
|
||||
free(a);
|
||||
continue;
|
||||
}
|
||||
sa = a;
|
||||
ea = a+n;
|
||||
while(a < ea){
|
||||
note.offset = (a-sa) + p->offset;
|
||||
if(unpacknote(elf, a, ea, ¬e, &a) < 0)
|
||||
break;
|
||||
switch(note.type){
|
||||
case ElfNotePrPsinfo:
|
||||
if((n = elf->corecmd(elf, ¬e, &cmd)) < 0){
|
||||
free(sa);
|
||||
return nil;
|
||||
}
|
||||
free(sa);
|
||||
return cmd;
|
||||
case ElfNotePrStatus:
|
||||
case ElfNotePrFpreg:
|
||||
case ElfNotePrTaskstruct:
|
||||
case ElfNotePrAuxv:
|
||||
case ElfNotePrXfpreg:
|
||||
break;
|
||||
}
|
||||
// fprint(2, "0x%lux note %s/%lud %p\n", note.offset, note.name, note.type, note.desc);
|
||||
}
|
||||
free(sa);
|
||||
}
|
||||
fprint(2, "could not find registers in core file\n");
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,8 +232,6 @@ 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**);
|
||||
void elfdl386mapdl(void);
|
||||
struct Fhdr;
|
||||
void elfcorelinux386(struct Fhdr*, Elf*, ElfNote*);
|
||||
void elfdl386mapdl(int);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ struct Status
|
|||
UregLinux386 reg;
|
||||
u32int fpvalid;
|
||||
};
|
||||
enum
|
||||
{
|
||||
StatusSize = sizeof(Status),
|
||||
};
|
||||
|
||||
struct Psinfo
|
||||
{
|
||||
|
|
@ -51,6 +55,10 @@ struct Psinfo
|
|||
char fname[16];
|
||||
char psargs[80];
|
||||
};
|
||||
enum
|
||||
{
|
||||
PsinfoSize = sizeof(Psinfo),
|
||||
};
|
||||
|
||||
int
|
||||
coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
|
||||
|
|
@ -65,8 +73,9 @@ coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
|
|||
}
|
||||
s = (Status*)note->desc;
|
||||
l = &s->reg;
|
||||
if((u = _linux2ureg386(l)) == nil)
|
||||
if((u = malloc(sizeof *u)) == nil)
|
||||
return -1;
|
||||
linux2ureg386(l, u);
|
||||
*up = (uchar*)u;
|
||||
return sizeof(Ureg);
|
||||
}
|
||||
|
|
@ -93,3 +102,101 @@ corecmdlinux386(Elf *elf, ElfNote *note, char **pp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define dprint if(0)print
|
||||
|
||||
void
|
||||
elfcorelinux386(Fhdr *fp, Elf *elf, ElfNote *note)
|
||||
{
|
||||
int i;
|
||||
Psinfo *ps;
|
||||
Status *st;
|
||||
Mach *m;
|
||||
Ureg *u;
|
||||
|
||||
m = fp->mach;
|
||||
dprint("%s ", note->name);
|
||||
switch(note->type){
|
||||
case ElfNotePrPsinfo:
|
||||
ps = (Psinfo*)note->desc;
|
||||
dprint("note info\n");
|
||||
dprint("state=%d sname=%d zomb=%d nice=%d\n",
|
||||
ps->state, ps->sname, ps->zomb, ps->nice);
|
||||
dprint("flag=0x%ux uid=%ud gid=%ud pid=%ud ppid=%ud pgrp=%ud sid=%ud\n",
|
||||
(uint)m->swap4(ps->flag),
|
||||
(uint)m->swap2(ps->uid),
|
||||
(uint)m->swap2(ps->gid),
|
||||
(uint)m->swap4(ps->pid),
|
||||
(uint)m->swap4(ps->ppid),
|
||||
(uint)m->swap4(ps->pgrp),
|
||||
(uint)m->swap4(ps->sid));
|
||||
dprint("fname=%s psargs=%s\n", ps->fname, ps->psargs);
|
||||
fp->pid = m->swap4(ps->pid);
|
||||
if((fp->prog = strdup(ps->fname)) == nil)
|
||||
fprint(2, "warning: out of memory saving core program name\n");
|
||||
if((fp->cmdline = strdup(ps->psargs)) == nil)
|
||||
fprint(2, "warning: out of memory saving core command line\n");
|
||||
break;
|
||||
case ElfNotePrTaskstruct:
|
||||
dprint("note taskstruct\n");
|
||||
break;
|
||||
case ElfNotePrAuxv:
|
||||
dprint("note auxv\n");
|
||||
break;
|
||||
case ElfNotePrStatus:
|
||||
dprint("note status\n");
|
||||
if(note->descsz < StatusSize){
|
||||
dprint("too small\n");
|
||||
break;
|
||||
}
|
||||
st = (Status*)note->desc;
|
||||
dprint("sig=%ud code=%ud errno=%ud cursig=%ud sigpend=0x%ux sighold=0x%ux\n",
|
||||
(uint)m->swap4(st->signo),
|
||||
(uint)m->swap4(st->code),
|
||||
(uint)m->swap4(st->errno),
|
||||
(uint)m->swap4(st->cursig),
|
||||
(uint)m->swap4(st->sigpend),
|
||||
(uint)m->swap4(st->sighold));
|
||||
dprint("pid=%ud ppid=%ud pgrp=%ud sid=%ud\n",
|
||||
(uint)m->swap4(st->pid),
|
||||
(uint)m->swap4(st->ppid),
|
||||
(uint)m->swap4(st->pgrp),
|
||||
(uint)m->swap4(st->sid));
|
||||
dprint("utime=%ud.%06ud stime=%ud.%06ud cutime=%ud.%06ud cstime=%ud.%06ud\n",
|
||||
(uint)m->swap4(st->utime[0]),
|
||||
(uint)m->swap4(st->utime[1]),
|
||||
(uint)m->swap4(st->stime[0]),
|
||||
(uint)m->swap4(st->stime[1]),
|
||||
(uint)m->swap4(st->cutime[0]),
|
||||
(uint)m->swap4(st->cutime[1]),
|
||||
(uint)m->swap4(st->cstime[0]),
|
||||
(uint)m->swap4(st->cstime[1]));
|
||||
dprint("fpvalid=%ud\n",
|
||||
(uint)m->swap4(st->fpvalid));
|
||||
if((fp->thread = realloc(fp->thread, (1+fp->nthread)*sizeof(fp->thread[0]))) == nil){
|
||||
fprint(2, "warning: out of memory saving thread info\n");
|
||||
return;
|
||||
}
|
||||
i = fp->nthread;
|
||||
fp->thread[i].id = m->swap4(st->pid);
|
||||
u = malloc(sizeof *u);
|
||||
if(u == nil){
|
||||
fprint(2, "warning: out of memory saving thread info\n");
|
||||
return;
|
||||
}
|
||||
fp->thread[i].ureg = u;
|
||||
linux2ureg386(&st->reg, u);
|
||||
fp->nthread++;
|
||||
break;
|
||||
case ElfNotePrFpreg:
|
||||
dprint("note fpreg\n");
|
||||
/* XXX maybe record floating-point registers eventually */
|
||||
break;
|
||||
case ElfNotePrXfpreg:
|
||||
dprint("note xfpreg\n");
|
||||
/* XXX maybe record floating-point registers eventually */
|
||||
break;
|
||||
default:
|
||||
dprint("note %d\n", note->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,14 +86,13 @@ dyninfo(Fhdr *hdr, int x)
|
|||
}
|
||||
|
||||
void
|
||||
elfdl386mapdl(void)
|
||||
elfdl386mapdl(int verbose)
|
||||
{
|
||||
int i;
|
||||
Fhdr *hdr;
|
||||
u32int linkdebug, linkmap, name, addr;
|
||||
char buf[1024];
|
||||
|
||||
print("elfdl386mapdl\n");
|
||||
if((linkdebug = dyninfo(symhdr, DT_DEBUG)) == 0){
|
||||
fprint(2, "no dt_debug section\n");
|
||||
return;
|
||||
|
|
@ -109,25 +108,27 @@ print("elfdl386mapdl\n");
|
|||
|| get4(cormap, linkmap+12, &linkmap) < 0)
|
||||
break;
|
||||
|
||||
if(name
|
||||
&& getstr(cormap, name, buf, sizeof buf) >= 0
|
||||
&& buf[0]
|
||||
&& access(buf, AEXIST) >= 0){
|
||||
if((hdr = crackhdr(buf, OREAD)) == nil)
|
||||
if(name == 0 || getstr(cormap, name, buf, sizeof buf) < 0 || buf[0] == 0)
|
||||
continue;
|
||||
if((hdr = crackhdr(buf, OREAD)) == nil){
|
||||
fprint(2, "crackhdr %s: %r\n", buf);
|
||||
else{
|
||||
fprint(2, "%s: %s %s %s\n", buf, hdr->aname, hdr->mname, hdr->fname);
|
||||
continue;
|
||||
}
|
||||
hdr->base = addr;
|
||||
if(verbose)
|
||||
fprint(2, "%s: %s %s %s\n", buf, hdr->aname, hdr->mname, hdr->fname);
|
||||
if(mapfile(hdr, addr, symmap, nil) < 0)
|
||||
fprint(2, "mapfile %s: %r\n", buf);
|
||||
fprint(2, "mapping %s: %r\n", buf);
|
||||
if(corhdr){
|
||||
/*
|
||||
* Need to map the text file under the core file.
|
||||
*/
|
||||
unmapfile(corhdr, cormap);
|
||||
mapfile(hdr, addr, cormap, nil);
|
||||
mapfile(corhdr, 0, cormap, nil);
|
||||
}
|
||||
if(symopen(hdr) < 0)
|
||||
fprint(2, "syminit %s: %\r", buf);
|
||||
}
|
||||
}
|
||||
fprint(2, "syminit %s: %r\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,8 +87,12 @@ stacktrace(Map *map, Regs *regs, Tracer trace)
|
|||
break;
|
||||
if(i < 0)
|
||||
break;
|
||||
if(sp && strcmp(sp->name, "main") == 0)
|
||||
if(sp){
|
||||
if(strcmp(sp->name, "main") == 0
|
||||
|| strcmp(sp->name, "procscheduler") == 0
|
||||
|| strcmp(sp->name, "threadstart") == 0)
|
||||
break;
|
||||
}
|
||||
pc = nextpc;
|
||||
memmove(cur, next, mach->nwindreg*sizeof(cur[0]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ addseg(Map *map, Seg seg)
|
|||
{
|
||||
Seg *ss;
|
||||
|
||||
if(map == 0){
|
||||
if(map == nil){
|
||||
werrstr("invalid map");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ findseg(Map *map, char *name, char *file)
|
|||
{
|
||||
int i;
|
||||
|
||||
if(map == 0)
|
||||
if(map == nil)
|
||||
return -1;
|
||||
for(i=0; i<map->nseg; i++){
|
||||
if(name && (!map->seg[i].name || strcmp(map->seg[i].name, name) != 0))
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ OFILES=\
|
|||
symstabs.$O\
|
||||
ureg386.$O\
|
||||
|
||||
HFILES=mach.h
|
||||
HFILES=$PLAN9/include/mach.h
|
||||
|
||||
<$PLAN9/src/mksyslib
|
||||
CFLAGS=$CFLAGS -I.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,103 @@
|
|||
#include <libc.h>
|
||||
#include <mach.h>
|
||||
|
||||
typedef struct Ptprog Ptprog;
|
||||
struct Pprog
|
||||
{
|
||||
Pthread *t;
|
||||
uint nt;
|
||||
};
|
||||
|
||||
typedef struct Pthread Pthread;
|
||||
struct Pthread
|
||||
{
|
||||
td_thrhandle_t handle;
|
||||
};
|
||||
|
||||
void
|
||||
pthreadattach(int pid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void pthreadattach()
|
||||
set up mapping
|
||||
|
||||
Regs *pthreadregs()
|
||||
int npthread();
|
||||
|
||||
|
||||
|
||||
static int td_get_allthreads(td_thragent_t*, td_thrhandle_t**);
|
||||
static int terr(int);
|
||||
|
||||
|
||||
Regs*
|
||||
threadregs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct AllThread AllThread;
|
||||
struct AllThread
|
||||
{
|
||||
td_thrhandle_t *a;
|
||||
int n;
|
||||
int err;
|
||||
};
|
||||
|
||||
static int
|
||||
thritercb(const td_thrhandle_t *th, void *cb)
|
||||
{
|
||||
td_thrhandle_t **p;
|
||||
AllThread *a;
|
||||
int n;
|
||||
|
||||
a = cb;
|
||||
if((a->n&(a->n-1)) == 0){
|
||||
if(a->n == 0)
|
||||
n = 1;
|
||||
else
|
||||
n = a->n<<1;
|
||||
if((p = realloc(a->a, n*sizeof a->a[0])) == 0){
|
||||
a->err = -1;
|
||||
return -1; /* stop iteration */
|
||||
}
|
||||
a->a = p;
|
||||
}
|
||||
a->a[a->n++] = *th;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
td_get_allthreads(td_thragent_t *ta, td_thrhandle_t **pall)
|
||||
{
|
||||
int e;
|
||||
AllThread a;
|
||||
|
||||
a.a = nil;
|
||||
a.n = 0;
|
||||
a.err = 0;
|
||||
if((e = td_ta_thr_iter(ta, thritercb, &a,
|
||||
TD_THR_ANY_STATE,
|
||||
TD_THR_LOWEST_PRIORITY,
|
||||
TD_SIGNO_MASK,
|
||||
TD_THR_ANY_USER_FLAGS)) != TD_OK){
|
||||
werrstr("%s", terr(e));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(a.err){
|
||||
free(a.a);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pall = a.a;
|
||||
return a.n;
|
||||
}
|
||||
|
||||
static char *tderrstr[] =
|
||||
{
|
||||
[TD_OK] "no error",
|
||||
|
|
@ -47,3 +144,146 @@ terr(int e)
|
|||
return tderrstr[e];
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
if(get1(ph->map, addr, v, sz) < 0)
|
||||
return PS_ERR;
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
|
||||
{
|
||||
if(put1(ph->map, 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)
|
||||
{
|
||||
return ps_pdread(ph, addr, v, sz);
|
||||
}
|
||||
|
||||
int
|
||||
ps_ptwrite(struct ps_prochandle *ph, psaddr_t addr, void *v, size_t sz)
|
||||
{
|
||||
return ps_pdwrite(ph, addr, v, sz);
|
||||
}
|
||||
|
||||
int
|
||||
ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
USED(ph);
|
||||
if(corhdr == nil)
|
||||
return sys_ps_lgetregs(ph, lwp, regs);
|
||||
for(i=0; i<corhdr->nthread; i++){
|
||||
if(corhdr->thread[i].id == lwp){
|
||||
ureg2prgregset(corhdr->thread[i].ureg, regs);
|
||||
return PS_OK;
|
||||
}
|
||||
}
|
||||
return PS_ERR;
|
||||
}
|
||||
|
||||
int
|
||||
ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwp, prgregset_t regs)
|
||||
{
|
||||
if(corhdr == nil)
|
||||
return sys_ps_lsetregs(ph, lwp, regs);
|
||||
return PS_ERR;
|
||||
}
|
||||
|
||||
int
|
||||
ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs)
|
||||
{
|
||||
if(corhdr == nil)
|
||||
return sys_ps_lgetfpregs(ph, lwp, fpregs);
|
||||
/* BUG - Look in core dump. */
|
||||
return PS_ERR:
|
||||
}
|
||||
|
||||
int
|
||||
ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwp, prfpregset_t *fpregs)
|
||||
{
|
||||
if(corhdr == nil)
|
||||
return sys_ps_lsetfpregs(ph, lwp, fpregs);
|
||||
return PS_ERR;
|
||||
}
|
||||
|
||||
/* 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 sys_ps_get_thread_area(ph, lwp, xxx, addr);
|
||||
}
|
||||
|
||||
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("libmach pthread: 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("libmach pthread: lookup %d %s %s => name not found\n", ph->pid, object_name, sym_name);
|
||||
return PS_NOSYM;
|
||||
}
|
||||
/* print("libmach pthread: lookup %d %s %s => 0x%lux\n", ph->pid, object_name, sym_name, addr); */
|
||||
*sym_addr = (void*)(addr+fp->base);
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,11 +42,12 @@ _delhdr(Fhdr *h)
|
|||
else{
|
||||
for(p=fhdrlist; p && p->next!=h; p=p->next)
|
||||
;
|
||||
if(p)
|
||||
if(p){
|
||||
p->next = h->next;
|
||||
if(p->next == nil)
|
||||
last = p;
|
||||
}
|
||||
}
|
||||
h->next = nil;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,11 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <mach.h>
|
||||
#include <elf.h>
|
||||
#include "ureg386.h"
|
||||
|
||||
|
||||
Ureg*
|
||||
_linux2ureg386(UregLinux386 *l)
|
||||
void
|
||||
linux2ureg386(UregLinux386 *l, Ureg *u)
|
||||
{
|
||||
Ureg *u;
|
||||
|
||||
u = malloc(sizeof(Ureg));
|
||||
if(u == nil)
|
||||
return nil;
|
||||
u->di = l->edi;
|
||||
u->si = l->esi;
|
||||
u->bp = l->ebp;
|
||||
|
|
@ -32,5 +25,27 @@ _linux2ureg386(UregLinux386 *l)
|
|||
u->flags = l->eflags;
|
||||
u->sp = l->esp;
|
||||
u->ss = l->xss;
|
||||
return u;
|
||||
}
|
||||
|
||||
void
|
||||
ureg2linux386(Ureg *u, UregLinux386 *l)
|
||||
{
|
||||
l->edi = u->di;
|
||||
l->esi = u->si;
|
||||
l->ebp = u->bp;
|
||||
l->esp = u->nsp;
|
||||
l->ebx = u->bx;
|
||||
l->edx = u->dx;
|
||||
l->ecx = u->cx;
|
||||
l->eax = u->ax;
|
||||
l->xgs = u->gs;
|
||||
l->xfs = u->fs;
|
||||
l->xes = u->es;
|
||||
l->xds = u->ds;
|
||||
l->eip = u->pc;
|
||||
l->xcs = u->cs;
|
||||
l->eflags = u->flags;
|
||||
l->esp = u->sp;
|
||||
l->xss = u->ss;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,24 +25,24 @@ struct Ureg
|
|||
typedef struct UregLinux386 UregLinux386;
|
||||
struct UregLinux386
|
||||
{
|
||||
ulong ebx;
|
||||
ulong ecx;
|
||||
ulong edx;
|
||||
ulong esi;
|
||||
ulong edi;
|
||||
ulong ebp;
|
||||
ulong eax;
|
||||
ulong xds;
|
||||
ulong xes;
|
||||
ulong xfs;
|
||||
ulong xgs;
|
||||
ulong origeax;
|
||||
ulong eip;
|
||||
ulong xcs;
|
||||
ulong eflags;
|
||||
ulong esp;
|
||||
ulong xss;
|
||||
u32int ebx;
|
||||
u32int ecx;
|
||||
u32int edx;
|
||||
u32int esi;
|
||||
u32int edi;
|
||||
u32int ebp;
|
||||
u32int eax;
|
||||
u32int xds;
|
||||
u32int xes;
|
||||
u32int xfs;
|
||||
u32int xgs;
|
||||
u32int origeax;
|
||||
u32int eip;
|
||||
u32int xcs;
|
||||
u32int eflags;
|
||||
u32int esp;
|
||||
u32int xss;
|
||||
};
|
||||
|
||||
Ureg *_linux2ureg386(UregLinux386*);
|
||||
|
||||
void linux2ureg386(UregLinux386*, Ureg*);
|
||||
void ureg2linux386(Ureg*, UregLinux386*);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue