|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <mach.h> | 
|  | #include "macho.h" | 
|  |  | 
|  | static int mapmacho(Fhdr *fp, u64int base, Map *map, Regs**); | 
|  |  | 
|  | static struct | 
|  | { | 
|  | uint etype; | 
|  | uint mtype; | 
|  | Mach *mach; | 
|  | char *name; | 
|  | int (*coreregs)(Macho*, uchar**); | 
|  | } mtab[] = | 
|  | { | 
|  | MachoCpuPower,	MPOWER,		&machpower, 		"powerpc",	coreregsmachopower, | 
|  | }; | 
|  |  | 
|  | static uchar* | 
|  | load(int fd, ulong off, int size) | 
|  | { | 
|  | uchar *a; | 
|  |  | 
|  | a = malloc(size); | 
|  | if(a == nil) | 
|  | return nil; | 
|  | if(seek(fd, off, 0) < 0 || readn(fd, a, size) != size){ | 
|  | free(a); | 
|  | return nil; | 
|  | } | 
|  | return a; | 
|  | } | 
|  |  | 
|  | int | 
|  | crackmacho(int fd, Fhdr *fp) | 
|  | { | 
|  | int i; | 
|  | Macho *m; | 
|  |  | 
|  | if((m = machoinit(fd)) == nil) | 
|  | return -1; | 
|  |  | 
|  | fp->fd = fd; | 
|  | fp->macho = m; | 
|  |  | 
|  | for(i=0; i<nelem(mtab); i++){ | 
|  | if(m->cputype != mtab[i].etype) | 
|  | continue; | 
|  | fp->mach = mtab[i].mach; | 
|  | fp->mtype = mtab[i].mtype; | 
|  | fp->mname = mtab[i].name; | 
|  | m->coreregs = mtab[i].coreregs; | 
|  | break; | 
|  | } | 
|  | if(i == nelem(mtab)){ | 
|  | werrstr("unsupported cpu type %ud", m->cputype); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | fp->atype = AMACH; | 
|  | fp->aname = "mach"; | 
|  |  | 
|  | if(mach == nil) | 
|  | mach = fp->mach; | 
|  |  | 
|  | switch(m->filetype){ | 
|  | default: | 
|  | werrstr("unsupported macho file type %lud", m->filetype); | 
|  | goto err; | 
|  | case MachoFileObject: | 
|  | fp->ftype = FOBJ; | 
|  | fp->fname = "object"; | 
|  | break; | 
|  | case MachoFileExecutable: | 
|  | fp->ftype = FEXEC; | 
|  | fp->fname = "executable"; | 
|  | break; | 
|  | case MachoFileFvmlib: | 
|  | fp->ftype = FSHLIB; | 
|  | fp->fname = "shared library"; | 
|  | break; | 
|  | case MachoFileCore: | 
|  | fp->ftype = FCORE; | 
|  | fp->fname = "core"; | 
|  | break; | 
|  | case MachoFilePreload: | 
|  | fp->ftype = FBOOT; | 
|  | fp->fname = "preloaded executable"; | 
|  | break; | 
|  | } | 
|  |  | 
|  | fp->txtaddr = fp->dataddr = 0; | 
|  | fp->txtsz = fp->datsz = 0; | 
|  | for(i=0; i<m->ncmd; i++){ | 
|  | if(m->cmd[i].type != MachoCmdSegment) | 
|  | continue; | 
|  | if(strcmp(m->cmd[i].seg.name, "__TEXT") == 0){ | 
|  | fp->txtaddr = m->cmd[i].seg.vmaddr; | 
|  | fp->txtsz = m->cmd[i].seg.vmsize; | 
|  | fp->txtoff = m->cmd[i].seg.fileoff; | 
|  | } | 
|  | if(strcmp(m->cmd[i].seg.name, "__DATA") == 0){ | 
|  | fp->dataddr = m->cmd[i].seg.vmaddr; | 
|  | fp->datsz = m->cmd[i].seg.filesz; | 
|  | fp->datoff = m->cmd[i].seg.fileoff; | 
|  | fp->bsssz = m->cmd[i].seg.vmsize - fp->datsz; | 
|  | } | 
|  | } | 
|  |  | 
|  | fp->map = mapmacho; | 
|  | fp->syminit = symmacho; | 
|  |  | 
|  | for(i=0; i<m->ncmd; i++) | 
|  | if(m->cmd[i].type == MachoCmdSymtab) | 
|  | break; | 
|  | if(i < m->ncmd){ | 
|  | fp->stabs.stabbase = load(fp->fd, m->cmd[i].sym.symoff, m->cmd[i].sym.nsym*16); | 
|  | fp->stabs.stabsize = m->cmd[i].sym.nsym*16; | 
|  | fp->stabs.strbase = (char*)load(fp->fd, m->cmd[i].sym.stroff, m->cmd[i].sym.strsize); | 
|  | if(fp->stabs.stabbase == nil || fp->stabs.strbase == nil){ | 
|  | fp->stabs.stabbase = nil; | 
|  | fp->stabs.strbase = nil; | 
|  | }else{ | 
|  | fp->stabs.strsize = m->cmd[i].sym.strsize; | 
|  | fp->stabs.e2 = (m->e4==beload4 ? beload2 : leload2); | 
|  | fp->stabs.e4 = m->e4; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | err: | 
|  | machoclose(m); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static int | 
|  | mapmacho(Fhdr *fp, u64int base, Map *map, Regs **rp) | 
|  | { | 
|  | int i, n; | 
|  | uchar *u; | 
|  | Macho *m; | 
|  | MachoCmd *c; | 
|  | Seg s; | 
|  | UregRegs *r; | 
|  |  | 
|  | m = fp->macho; | 
|  | if(m == nil){ | 
|  | werrstr("not a macho file"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | for(i=0; i<m->ncmd; i++){ | 
|  | c = &m->cmd[i]; | 
|  | if(c->type != MachoCmdSegment) | 
|  | continue; | 
|  | if(c->seg.filesz){ | 
|  | memset(&s, 0, sizeof s); | 
|  | s.file = fp->filename; | 
|  | s.fd = fp->fd; | 
|  | if(fp->ftype == FCORE) | 
|  | s.name = "core"; | 
|  | else if(strcmp(c->seg.name, "__DATA") == 0) | 
|  | s.name = "data"; | 
|  | else | 
|  | s.name = "text"; | 
|  | s.base = base+c->seg.vmaddr; | 
|  | s.size = c->seg.filesz; | 
|  | s.offset = c->seg.fileoff; | 
|  | if(addseg(map, s) < 0) | 
|  | return -1; | 
|  | } | 
|  | if(c->seg.filesz < c->seg.vmsize){ | 
|  | memset(&s, 0, sizeof s); | 
|  | s.name = "zero"; | 
|  | s.base = base + c->seg.vmaddr + c->seg.filesz; | 
|  | s.size = c->seg.vmsize - c->seg.filesz; | 
|  | if(addseg(map, s) < 0) | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(fp->ftype == FCORE && m->coreregs){ | 
|  | n = m->coreregs(m, &u); | 
|  | if(n < 0){ | 
|  | fprint(2, "mapping registers: %r\n"); | 
|  | goto noregs; | 
|  | } | 
|  | if((r = mallocz(sizeof *r, 1)) == nil) | 
|  | return -1; | 
|  | r->r.rw = _uregrw; | 
|  | r->ureg = u; | 
|  | *rp = &r->r; | 
|  | } | 
|  | noregs: | 
|  | return 0; | 
|  | } |