| #include <u.h> |
| #include <libc.h> |
| #include <mach.h> |
| #include "macho.h" |
| |
| /* |
| http://www.channelu.com/NeXT/NeXTStep/3.3/nd/DevTools/14_MachO/MachO.htmld/ |
| */ |
| |
| Macho* |
| machoopen(char *name) |
| { |
| int fd; |
| Macho *m; |
| |
| if((fd = open(name, OREAD)) < 0) |
| return nil; |
| m = machoinit(fd); |
| if(m == nil) |
| close(fd); |
| return m; |
| } |
| |
| static int |
| unpackseg(uchar *p, Macho *m, MachoCmd *c, uint type, uint sz) |
| { |
| u32int (*e4)(uchar*); |
| |
| e4 = m->e4; |
| |
| c->type = type; |
| c->size = sz; |
| switch(type){ |
| default: |
| return -1; |
| case MachoCmdSegment: |
| if(sz < 56) |
| return -1; |
| strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); |
| c->seg.vmaddr = e4(p+24); |
| c->seg.vmsize = e4(p+28); |
| c->seg.fileoff = e4(p+32); |
| c->seg.filesz = e4(p+36); |
| c->seg.maxprot = e4(p+40); |
| c->seg.initprot = e4(p+44); |
| c->seg.nsect = e4(p+48); |
| c->seg.flags = e4(p+52); |
| break; |
| case MachoCmdSymtab: |
| if(sz < 24) |
| return -1; |
| c->sym.symoff = e4(p+8); |
| c->sym.nsyms = e4(p+12); |
| c->sym.stroff = e4(p+16); |
| c->sym.strsize = e4(p+20); |
| break; |
| } |
| return 0; |
| } |
| |
| |
| Macho* |
| machoinit(int fd) |
| { |
| int i; |
| uchar hdr[7*4], *cmdp; |
| u32int (*e4)(uchar*); |
| ulong ncmd, cmdsz, ty, sz, off; |
| Macho *m; |
| |
| if(seek(fd, 0, 0) < 0 || readn(fd, hdr, sizeof hdr) != sizeof hdr) |
| return nil; |
| |
| if(beload4(hdr) == 0xFEEDFACE) |
| e4 = beload4; |
| else if(leload4(hdr) == 0xFEEDFACE) |
| e4 = leload4; |
| else{ |
| werrstr("bad magic - not mach-o file"); |
| return nil; |
| } |
| |
| ncmd = e4(hdr+4*4); |
| cmdsz = e4(hdr+5*4); |
| if(ncmd > 0x10000 || cmdsz >= 0x01000000){ |
| werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz); |
| return nil; |
| } |
| |
| m = mallocz(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz, 1); |
| if(m == nil) |
| return nil; |
| |
| m->fd = fd; |
| m->e4 = e4; |
| m->cputype = e4(hdr+1*4); |
| m->subcputype = e4(hdr+2*4); |
| m->filetype = e4(hdr+3*4); |
| m->ncmd = ncmd; |
| m->flags = e4(hdr+6*4); |
| |
| m->cmd = (MachoCmd*)(m+1); |
| off = sizeof hdr; |
| cmdp = (uchar*)(m->cmd+ncmd); |
| if(readn(fd, cmdp, cmdsz) != cmdsz){ |
| werrstr("reading cmds: %r"); |
| free(m); |
| return nil; |
| } |
| |
| for(i=0; i<ncmd; i++){ |
| ty = e4(cmdp); |
| sz = e4(cmdp+4); |
| m->cmd[i].off = off; |
| unpackseg(cmdp, m, &m->cmd[i], ty, sz); |
| cmdp += sz; |
| off += sz; |
| } |
| |
| return m; |
| } |
| |
| void |
| machoclose(Macho *m) |
| { |
| close(m->fd); |
| free(m); |
| } |