#include #include #include #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; ihdr.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; ihdr.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; iatype || ctab[i].mtype != fp->mtype) continue; elfcore = ctab[i].elfcore; break; } if(elfcore) for(i=0; inprog; 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; inprog; 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; inprog; 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; }