1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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);
}
|