URI: 
       tStart working through proper handling of pthreads when debugging Linux core dumps.  Pthreads for active processes is still not supported, nor are other systems. - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit dd944ec72a26d0b380ba2af5f6c00310f2f1651e
   DIR parent a0e8d02d093e01fdadf8a16bc86fe18b0c4e82c3
  HTML Author: rsc <devnull@localhost>
       Date:   Sun, 23 Jan 2005 22:33:04 +0000
       
       Start working through proper handling of pthreads when
       debugging Linux core dumps.  Pthreads for active processes
       is still not supported, nor are other systems.
       
       Diffstat:
         M src/libmach/Linux.c                 |     191 +------------------------------
         M src/libmach/cmdline.c               |      39 +++++++++++++++++++++-----------
         M src/libmach/crack.c                 |      38 ++++++++++++++++++++++++++++---
         M src/libmach/crackelf.c              |     181 ++++++-------------------------
         M src/libmach/elf.h                   |       8 +++-----
         M src/libmach/elfcorelinux386.c       |     109 ++++++++++++++++++++++++++++++-
         M src/libmach/elfdl386.c              |      43 ++++++++++++++++---------------
         M src/libmach/frame.c                 |       8 ++++++--
         M src/libmach/map.c                   |       4 ++--
         M src/libmach/mkfile                  |       2 +-
         M src/libmach/pthread.c               |     240 +++++++++++++++++++++++++++++++
         M src/libmach/sym.c                   |       7 ++++---
         M src/libmach/ureg386.c               |      35 ++++++++++++++++++++++---------
         M src/libmach/ureg386.h               |      38 ++++++++++++++++----------------
       
       14 files changed, 528 insertions(+), 415 deletions(-)
       ---
   DIR diff --git a/src/libmach/Linux.c b/src/libmach/Linux.c
       t@@ -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;
                        }
                }
       t@@ -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;
       -}
   DIR diff --git a/src/libmach/cmdline.c b/src/libmach/cmdline.c
       t@@ -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;
       t@@ -56,9 +56,9 @@ attachargs(int argc, char **argv, int omode)
                                fprint(2, "crackhdr %s: %r\n", argv[i]);
                                continue;
                        }
       -                fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
       +                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);
       t@@ -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){
       t@@ -124,10 +135,10 @@ attachargs(int argc, char **argv, int omode)
        
                if(corpid)        
                        attachproc(corpid);
       -
                if(corhdr)
                        attachcore(corhdr);
        
       +        attachdynamic(verbose);
                return 0;
        }
        
       t@@ -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);
       t@@ -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;
        }
        
   DIR diff --git a/src/libmach/crack.c b/src/libmach/crack.c
       t@@ -2,6 +2,7 @@
        #include <libc.h>
        #include <bio.h>
        #include <mach.h>
       +#include "elf.h"
        
        static struct
        {
       t@@ -50,9 +51,18 @@ crackhdr(char *name, int mode)
        void
        uncrackhdr(Fhdr *hdr)
        {
       -        close(hdr->fd);
       -        _delhdr(hdr);
       -        free(hdr->cmd);
       +        int i;
       +
       +        symclose(hdr);
       +        if(hdr->elf)
       +                elfclose(hdr->elf);
       +        if(hdr->fd >= 0)
       +                close(hdr->fd);
       +        free(hdr->cmdline);
       +        free(hdr->prog);
       +        for(i=0; i<hdr->nthread; i++)
       +                free(hdr->thread[i].ureg);
       +        free(hdr->thread);
                free(hdr);
        }
        
       t@@ -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);
        }
        
       t@@ -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;
       +}
       +
   DIR diff --git a/src/libmach/crackelf.c b/src/libmach/crackelf.c
       t@@ -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
        {
       t@@ -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;
       t@@ -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, &note, &a) < 0)
       +                                        break;
       +                                elfcore(fp, elf, &note);
       +                        }
       +                        free(sa);
       +                }
                        return 0;
                }
        
       t@@ -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;        
        }
       t@@ -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, &note, &a) < 0)
       -                                break;
       -                        switch(note.type){
       -                        case ElfNotePrStatus:
       -                                if((n = (*elf->coreregs)(elf, &note, &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, &note, &a) < 0)
       -                                break;
       -                        switch(note.type){
       -                        case ElfNotePrPsinfo:
       -                                if((n = elf->corecmd(elf, &note, &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;
       -}
       -
   DIR diff --git a/src/libmach/elf.h b/src/libmach/elf.h
       t@@ -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);
   DIR diff --git a/src/libmach/elfcorelinux386.c b/src/libmach/elfcorelinux386.c
       t@@ -34,6 +34,10 @@ struct Status
                UregLinux386        reg;
                u32int        fpvalid;
        };
       +enum
       +{
       +        StatusSize = sizeof(Status),
       +};
        
        struct Psinfo
        {
       t@@ -51,6 +55,10 @@ struct Psinfo
                char fname[16];
                char psargs[80];
        };
       +enum
       +{
       +        PsinfoSize = sizeof(Psinfo),
       +};
        
        int
        coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
       t@@ -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);
        }
       t@@ -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);
       +        }
       +}
       +
   DIR diff --git a/src/libmach/elfdl386.c b/src/libmach/elfdl386.c
       t@@ -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;
       t@@ -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)
       -                                fprint(2, "crackhdr %s: %r\n", buf);
       -                        else{
       -                                fprint(2, "%s: %s %s %s\n", buf, hdr->aname, hdr->mname, hdr->fname);
       -                                hdr->base = addr;
       -                                if(mapfile(hdr, addr, symmap, nil) < 0)
       -                                        fprint(2, "mapfile %s: %r\n", buf);
       -                                if(corhdr){
       -                                        unmapfile(corhdr, cormap);
       -                                        mapfile(hdr, addr, cormap, nil);
       -                                }
       -                                if(symopen(hdr) < 0)
       -                                        fprint(2, "syminit %s: %\r", buf);
       -                        }
       -                }        
       +                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);
       +                        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, "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\n", buf);
                }
        }
        
   DIR diff --git a/src/libmach/frame.c b/src/libmach/frame.c
       t@@ -87,8 +87,12 @@ stacktrace(Map *map, Regs *regs, Tracer trace)
                                break;
                        if(i < 0)
                                break;
       -                if(sp && strcmp(sp->name, "main") == 0)
       -                        break;
       +                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]));
                }
   DIR diff --git a/src/libmach/map.c b/src/libmach/map.c
       t@@ -31,7 +31,7 @@ addseg(Map *map, Seg seg)
        {
                Seg *ss;
        
       -        if(map == 0){
       +        if(map == nil){
                        werrstr("invalid map");
                        return -1;
                }
       t@@ -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))
   DIR diff --git a/src/libmach/mkfile b/src/libmach/mkfile
       t@@ -43,7 +43,7 @@ OFILES=\
                symstabs.$O\
                ureg386.$O\
        
       -HFILES=mach.h
       +HFILES=$PLAN9/include/mach.h
        
        <$PLAN9/src/mksyslib
        CFLAGS=$CFLAGS -I.
   DIR diff --git a/src/libmach/pthread.c b/src/libmach/pthread.c
       t@@ -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",
       t@@ -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;
       +}
       +
   DIR diff --git a/src/libmach/sym.c b/src/libmach/sym.c
       t@@ -42,10 +42,11 @@ _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;
       +                        if(p->next == nil)
       +                                last = p;
       +                }
                }
                h->next = nil;
        }
   DIR diff --git a/src/libmach/ureg386.c b/src/libmach/ureg386.c
       t@@ -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;
       t@@ -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;
       +}
       +
   DIR diff --git a/src/libmach/ureg386.h b/src/libmach/ureg386.h
       t@@ -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*);