blob: 22f4307e50275c72d471164dbe4ccded23529726 [file] [log] [blame]
#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, &note, &a) < 0)
break;
elfcore(fp, elf, &note);
}
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;
}