diff options
author | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
commit | a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch) | |
tree | 59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/macho.c | |
parent | 0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff) | |
download | plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2 plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip |
libmach
Diffstat (limited to 'src/libmach/macho.c')
-rw-r--r-- | src/libmach/macho.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/libmach/macho.c b/src/libmach/macho.c new file mode 100644 index 00000000..641db598 --- /dev/null +++ b/src/libmach/macho.c @@ -0,0 +1,128 @@ +#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); +} |