|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <mach.h> | 
|  | #include "elf.h" | 
|  | #include "dwarf.h" | 
|  |  | 
|  | static int mapelf(Fhdr *fp, ulong base, Map *map, Regs**); | 
|  | static int unpacknote(Elf *elf, uchar *a, uchar *ea, ElfNote *note, uchar **pa); | 
|  |  | 
|  | static struct | 
|  | { | 
|  | uint etype; | 
|  | uint mtype; | 
|  | Mach *mach; | 
|  | char *name; | 
|  | } mtab[] = | 
|  | {	/* Font Tab 4 */ | 
|  | ElfMachSparc,	MSPARC,		nil,		"sparc", | 
|  | ElfMach386,		M386,		&mach386,	"386", | 
|  | ElfMachMips,	MMIPS,		nil,		"mips", | 
|  | ElfMachArm,		MARM,		nil,		"arm", | 
|  | ElfMachPower,	MPOWER,		nil,		"powerpc", | 
|  | ElfMachPower64,	MNONE,		nil,		"powerpc64", | 
|  | }; | 
|  |  | 
|  | static struct | 
|  | { | 
|  | uint etype; | 
|  | uint atype; | 
|  | char *aname; | 
|  | } atab[] = | 
|  | {	/* Font Tab 4 */ | 
|  | ElfAbiSystemV,	ALINUX,		"linux",	/* [sic] */ | 
|  | ElfAbiLinux,	ALINUX,		"linux", | 
|  | ElfAbiFreeBSD,	AFREEBSD,	"freebsd", | 
|  | }; | 
|  |  | 
|  | static struct | 
|  | { | 
|  | uint mtype; | 
|  | uint atype; | 
|  | void (*elfcore)(Fhdr*, Elf*, ElfNote*); | 
|  | } ctab[] = | 
|  | {	/* Font Tab 4 */ | 
|  | M386,		ALINUX,		elfcorelinux386, | 
|  | M386,		ANONE,		elfcorelinux386,	/* [sic] */ | 
|  | /*	M386,		AFREEBSD,	elfcorefreebsd386, */ | 
|  | }; | 
|  |  | 
|  | int | 
|  | crackelf(int fd, Fhdr *fp) | 
|  | { | 
|  | 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; | 
|  |  | 
|  | fp->fd = fd; | 
|  | fp->elf = elf; | 
|  | fp->dwarf = dwarfopen(elf);	/* okay to fail */ | 
|  | fp->syminit = symelf; | 
|  |  | 
|  | if((s1 = elfsection(elf, ".stab")) != nil && s1->link!=0 && s1->link < elf->nsect){ | 
|  | s2 = &elf->sect[s1->link]; | 
|  | if(elfmap(elf, s1) >= 0 && elfmap(elf, s2) >= 0){ | 
|  | fp->stabs.stabbase = s1->base; | 
|  | fp->stabs.stabsize = s1->size; | 
|  | fp->stabs.strbase = (char*)s2->base; | 
|  | fp->stabs.strsize = s2->size; | 
|  | fp->stabs.e2 = elf->hdr.e2; | 
|  | fp->stabs.e4 = elf->hdr.e4; | 
|  | } | 
|  | } | 
|  |  | 
|  | for(i=0; i<nelem(mtab); i++){ | 
|  | if(elf->hdr.machine != mtab[i].etype) | 
|  | continue; | 
|  | fp->mach = mtab[i].mach; | 
|  | fp->mname = mtab[i].name; | 
|  | fp->mtype = mtab[i].mtype; | 
|  | break; | 
|  | } | 
|  | if(i == nelem(mtab)){ | 
|  | werrstr("unsupported machine type %d", elf->hdr.machine); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if(mach == nil) | 
|  | mach = fp->mach; | 
|  |  | 
|  | fp->aname = "unknown"; | 
|  | for(i=0; i<nelem(atab); i++){ | 
|  | if(elf->hdr.abi != atab[i].etype) | 
|  | continue; | 
|  | fp->atype = atab[i].atype; | 
|  | fp->aname = atab[i].aname; | 
|  | break; | 
|  | } | 
|  |  | 
|  | switch(elf->hdr.type){ | 
|  | default: | 
|  | werrstr("unknown file type %d", elf->hdr.type); | 
|  | goto err; | 
|  | case ElfTypeExecutable: | 
|  | fp->ftype = FEXEC; | 
|  | fp->fname = "executable"; | 
|  | break; | 
|  | case ElfTypeRelocatable: | 
|  | fp->ftype = FRELOC; | 
|  | fp->fname = "relocatable"; | 
|  | break; | 
|  | case ElfTypeSharedObject: | 
|  | fp->ftype = FSHOBJ; | 
|  | fp->fname = "shared object"; | 
|  | break; | 
|  | case ElfTypeCore: | 
|  | fp->ftype = FCORE; | 
|  | fp->fname = "core dump"; | 
|  | break; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | elfcore = ctab[i].elfcore; | 
|  | break; | 
|  | } | 
|  | 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; | 
|  | } | 
|  |  | 
|  | fp->entry = elf->hdr.entry; | 
|  |  | 
|  | /* First r-x section we find is the text and initialized data */ | 
|  | /* First rw- section we find is the r/w data */ | 
|  | havetext = 0; | 
|  | havedata = 0; | 
|  | for(i=0; i<elf->nprog; i++){ | 
|  | p = &elf->prog[i]; | 
|  | if(p->type != ElfProgLoad) | 
|  | continue; | 
|  | if(!havetext && p->flags == (ElfProgFlagRead|ElfProgFlagExec) && p->align >= mach->pgsize){ | 
|  | havetext = 1; | 
|  | fp->txtaddr = p->vaddr; | 
|  | fp->txtsz = p->memsz; | 
|  | fp->txtoff = p->offset; | 
|  | } | 
|  | if(!havedata && p->flags == (ElfProgFlagRead|ElfProgFlagWrite) && p->align >= mach->pgsize){ | 
|  | havedata = 1; | 
|  | fp->dataddr = p->vaddr; | 
|  | fp->datsz = p->filesz; | 
|  | fp->datoff = p->offset; | 
|  | fp->bsssz = p->memsz - p->filesz; | 
|  | } | 
|  | } | 
|  | if(!havetext){ | 
|  | werrstr("did not find text segment in elf binary"); | 
|  | goto err; | 
|  | } | 
|  | if(!havedata){ | 
|  | werrstr("did not find data segment in elf binary"); | 
|  | goto err; | 
|  | } | 
|  | return 0; | 
|  |  | 
|  | err: | 
|  | elfclose(elf); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static int | 
|  | mapelf(Fhdr *fp, ulong base, Map *map, Regs **regs) | 
|  | { | 
|  | int i; | 
|  | Elf *elf; | 
|  | ElfProg *p; | 
|  | ulong sz; | 
|  | ulong lim; | 
|  | Seg s; | 
|  |  | 
|  | elf = fp->elf; | 
|  | if(elf == nil){ | 
|  | werrstr("not an elf file"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | for(i=0; i<elf->nprog; i++){ | 
|  | p = &elf->prog[i]; | 
|  | if(p->type != ElfProgLoad) | 
|  | continue; | 
|  | if(p->align < mach->pgsize) | 
|  | continue; | 
|  | if(p->filesz){ | 
|  | memset(&s, 0, sizeof s); | 
|  | s.file = fp->filename; | 
|  | s.fd = fp->fd; | 
|  | if(fp->ftype == FCORE) | 
|  | s.name = "core"; | 
|  | else if(p->flags == 5) | 
|  | s.name = "text"; | 
|  | else | 
|  | s.name = "data"; | 
|  | s.base = base+p->vaddr; | 
|  | s.size = p->filesz; | 
|  | s.offset = p->offset; | 
|  | if(addseg(map, s) < 0) | 
|  | return -1; | 
|  | } | 
|  | /* | 
|  | * If memsz > filesz, we're supposed to zero fill. | 
|  | * Core files have zeroed sections where the pages | 
|  | * can be filled in from the text file, so if this is a core | 
|  | * we only fill in that which isn't yet mapped. | 
|  | */ | 
|  | if(fp->ftype == FCORE){ | 
|  | sz = p->filesz; | 
|  | while(sz < p->memsz){ | 
|  | if(addrtoseg(map, base+p->vaddr+sz, &s) < 0){ | 
|  | lim = base + p->vaddr + p->memsz; | 
|  | if(addrtosegafter(map, base+p->vaddr+sz, &s) >= 0 && s.base < lim) | 
|  | lim = s.base; | 
|  | memset(&s, 0, sizeof s); | 
|  | s.name = "zero"; | 
|  | s.base = base + p->vaddr + sz; | 
|  | s.size = lim - s.base; | 
|  | s.offset = p->offset; | 
|  | if(addseg(map, s) < 0) | 
|  | return -1; | 
|  | }else | 
|  | sz = (s.base+s.size) - (base + p->vaddr); | 
|  | } | 
|  | }else{ | 
|  | if(p->filesz < p->memsz){ | 
|  | memset(&s, 0, sizeof s); | 
|  | s.name = "zero"; | 
|  | s.base = base + p->vaddr + p->filesz; | 
|  | s.size = p->memsz - p->filesz; | 
|  | if(addseg(map, s) < 0) | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if(fp->nthread && regs) | 
|  | *regs = coreregs(fp, fp->thread[0].id); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | unpacknote(Elf *elf, uchar *a, uchar *ea, ElfNote *note, uchar **pa) | 
|  | { | 
|  | if(a+12 > ea) | 
|  | return -1; | 
|  | note->namesz = elf->hdr.e4(a); | 
|  | note->descsz = elf->hdr.e4(a+4); | 
|  | note->type = elf->hdr.e4(a+8); | 
|  | a += 12; | 
|  | note->name = (char*)a; | 
|  | /* XXX fetch alignment constants from elsewhere */ | 
|  | a += (note->namesz+3)&~3; | 
|  | note->desc = (uchar*)a; | 
|  | a += (note->descsz+3)&~3; | 
|  | if(a > ea) | 
|  | return -1; | 
|  | *pa = a; | 
|  | return 0; | 
|  | } | 
|  |  |