Commit Diff


commit - a0e8d02d093e01fdadf8a16bc86fe18b0c4e82c3
commit + dd944ec72a26d0b380ba2af5f6c00310f2f1651e
blob - 9127434fd9f8a6784339095e008085fbde469ac5
blob + ff727409faa4cbaaa4e846f320d3a9a7bb9ddaba
--- src/libmach/Linux.c
+++ src/libmach/Linux.c
@@ -168,7 +168,7 @@ ptracerw(int type, int xtype, int isr, int pid, ulong 
 				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;
-}
blob - 4da38d9efc33df574f4021696d9f318148a179a1
blob + 568bc017048b45d719656d168a58735f4a24d490
--- src/libmach/cmdline.c
+++ src/libmach/cmdline.c
@@ -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;
 		}
-		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);
@@ -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;
 }
 
blob - ffc3b06c7e5ecd6af56dd74605cf69ad0d005d36
blob + c186456a661331990ed2d731012b3e4b617471bf
--- src/libmach/crack.c
+++ src/libmach/crack.c
@@ -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)
 {
-	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);
 }
 
@@ -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;
+}
+
blob - 682d9a72cbd429752be7a510f6be92e4b6c2979e
blob + e80d9ec3a7ee61dbf7524d2d20ffdf676c2341bd
--- src/libmach/crackelf.c
+++ src/libmach/crackelf.c
@@ -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, &note, &a) < 0)
+					break;
+				elfcore(fp, elf, &note);
+			}
+			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 *not
 	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;
-}
-
blob - 6b65cfc86b856817731a86e9c83e1fb6fad0c125
blob + f52450997363bafa1d6692c425816801babbe6c2
--- src/libmach/elf.h
+++ src/libmach/elf.h
@@ -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);
blob - 9e8d0aa9794d1b79f2634a6eb3e640b5b472b996
blob + 4c4aabc44e13cdaf16e7bc5885d24cbd9ac8dd41
--- src/libmach/elfcorelinux386.c
+++ src/libmach/elfcorelinux386.c
@@ -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);
+	}
+}
+
blob - a2439158f4025c31f6b0d7452fd2207f6f8313f2
blob + 5386f1b64ff567594b7d1c28797fd50a19a66c46
--- src/libmach/elfdl386.c
+++ src/libmach/elfdl386.c
@@ -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)
-				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);
 	}
 }
 
blob - 035c6a5233802ed23e254628f3811337d85dc95f
blob + 7d03f3b4c070026d3c615122f948e18ed810b1fe
--- src/libmach/frame.c
+++ src/libmach/frame.c
@@ -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]));
 	}
blob - bfb5f722813acb01c7712bf157a4344fa7440cbd
blob + b20bd8738b98d54940bb9fb333195d0bfe49e500
--- src/libmach/map.c
+++ src/libmach/map.c
@@ -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))
blob - 53d1af99e49643bc1192684b64acedd445efdbbf
blob + a6d6507e2ca4c6e73e26ebecbd6141558485793e
--- src/libmach/mkfile
+++ src/libmach/mkfile
@@ -43,7 +43,7 @@ OFILES=\
 	symstabs.$O\
 	ureg386.$O\
 
-HFILES=mach.h
+HFILES=$PLAN9/include/mach.h
 
 <$PLAN9/src/mksyslib
 CFLAGS=$CFLAGS -I.
blob - 46eca4f2ed36b7aa59538df7d291b64614b3fbe9
blob + 8a2b60a989069685e0cb23c48469981d24e44973
--- src/libmach/pthread.c
+++ src/libmach/pthread.c
@@ -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;
+}
+
blob - b5d3eacf5df903294e3686ac5b9d8f673de7ef0f
blob + 3b5c5ec4360c379efdff4560cac3d7daeae0274e
--- src/libmach/sym.c
+++ src/libmach/sym.c
@@ -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;
 }
blob - 09ef095db2596e94e60cb9a99823761810e4d6bd
blob + 76945030fe746f6365382228d42f630808c24096
--- src/libmach/ureg386.c
+++ src/libmach/ureg386.c
@@ -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;
+}
+
blob - f5f9a474adf261869b609e0e1013ebc71ddd3c10
blob + 9c4853d6822c027055fa9bd6ebf843d964cabb6f
--- src/libmach/ureg386.h
+++ src/libmach/ureg386.h
@@ -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*);