| #include <u.h> | 
 | #include <libc.h> | 
 | #include <mach.h> | 
 | #include "elf.h" | 
 | #include "dwarf.h" | 
 |  | 
 | static int mapelf(Fhdr *fp, u64int 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", | 
 | 	ElfMachAmd64,	MAMD64,	&machamd64,	"amd64", | 
 | }; | 
 |  | 
 | 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, | 
 | 	MAMD64,		AFREEBSD,	elfcorefreebsdamd64, | 
 | }; | 
 |  | 
 | 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, u64int base, Map *map, Regs **regs) | 
 | { | 
 | 	int i; | 
 | 	Elf *elf; | 
 | 	ElfProg *p; | 
 | 	u64int sz; | 
 | 	u64int 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; | 
 | } | 
 |  |