1 |
/* |
2 |
* Copyright (C) 2005-2007 Anders Gavare. All rights reserved. |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
6 |
* |
7 |
* 1. Redistributions of source code must retain the above copyright |
8 |
* notice, this list of conditions and the following disclaimer. |
9 |
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
* notice, this list of conditions and the following disclaimer in the |
11 |
* documentation and/or other materials provided with the distribution. |
12 |
* 3. The name of the author may not be used to endorse or promote products |
13 |
* derived from this software without specific prior written permission. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* SUCH DAMAGE. |
26 |
* |
27 |
* |
28 |
* $Id: file_macho.c,v 1.3 2007/06/17 23:32:20 debug Exp $ |
29 |
* |
30 |
* COMMENT: Mach-O file support |
31 |
*/ |
32 |
|
33 |
/* Note: Included from file.c. */ |
34 |
|
35 |
|
36 |
/* |
37 |
* file_load_macho(): |
38 |
* |
39 |
* Loads a Mach-O binary image into the emulated memory. The entry point |
40 |
* is stored in the specified CPU's registers. |
41 |
* |
42 |
* TODO: |
43 |
* |
44 |
* o) Almost everything. |
45 |
* |
46 |
* o) I haven't had time to look into whether Apple's open source |
47 |
* license is BSD-compatible or not. Perhaps it would be possible |
48 |
* to use a header file containing symbolic names, and not use |
49 |
* hardcoded values. |
50 |
*/ |
51 |
static void file_load_macho(struct machine *m, struct memory *mem, |
52 |
char *filename, uint64_t *entrypointp, int arch, int *byte_orderp, |
53 |
int is_64bit, int is_reversed) |
54 |
{ |
55 |
FILE *f; |
56 |
uint64_t entry = 0; |
57 |
int entry_set = 0; |
58 |
int encoding = ELFDATA2MSB; |
59 |
unsigned char buf[65536]; |
60 |
char *symbols, *strings; |
61 |
uint32_t cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; |
62 |
uint64_t vmaddr, vmsize, fileoff, filesize; |
63 |
int cmd_type, cmd_len, i, flavor; |
64 |
int32_t symoff, nsyms, stroff, strsize; |
65 |
size_t len, pos; |
66 |
|
67 |
if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) |
68 |
encoding = ELFDATA2MSB; |
69 |
|
70 |
f = fopen(filename, "r"); |
71 |
if (f == NULL) { |
72 |
perror(filename); |
73 |
exit(1); |
74 |
} |
75 |
|
76 |
if (is_64bit) { |
77 |
fatal("TODO: 64-bit Mach-O. Not supported yet.\n"); |
78 |
exit(1); |
79 |
} |
80 |
if (is_reversed) { |
81 |
fatal("TODO: Reversed-endianness. Not supported yet.\n"); |
82 |
exit(1); |
83 |
} |
84 |
|
85 |
len = fread(buf, 1, sizeof(buf), f); |
86 |
if (len < 100) { |
87 |
fatal("Bad Mach-O file?\n"); |
88 |
exit(1); |
89 |
} |
90 |
|
91 |
unencode(cputype, &buf[4], uint32_t); |
92 |
unencode(cpusubtype, &buf[8], uint32_t); |
93 |
unencode(filetype, &buf[12], uint32_t); |
94 |
unencode(ncmds, &buf[16], uint32_t); |
95 |
unencode(sizeofcmds, &buf[20], uint32_t); |
96 |
unencode(flags, &buf[24], uint32_t); |
97 |
|
98 |
/* debug("cputype=0x%x cpusubtype=0x%x filetype=0x%x\n", |
99 |
cputype, cpusubtype, filetype); |
100 |
debug("ncmds=%i sizeofcmds=0x%08x flags=0x%08x\n", |
101 |
ncmds, sizeofcmds, flags); */ |
102 |
|
103 |
/* |
104 |
* Compare to "normal" values. |
105 |
* NOTE/TODO: These were for a Darwin (Macintosh PPC) kernel. |
106 |
*/ |
107 |
if (cputype != 0x12) { |
108 |
fatal("Error: Unimplemented cputype 0x%x\n", cputype); |
109 |
exit(1); |
110 |
} |
111 |
if (cpusubtype != 0) { |
112 |
fatal("Error: Unimplemented cpusubtype 0x%x\n", cpusubtype); |
113 |
exit(1); |
114 |
} |
115 |
/* Filetype 2 means an executable image. */ |
116 |
if (filetype != 2) { |
117 |
fatal("Error: Unimplemented filetype 0x%x\n", filetype); |
118 |
exit(1); |
119 |
} |
120 |
if (!(flags & 1)) { |
121 |
fatal("Error: File has 'undefined references'. Cannot" |
122 |
" be executed.\n", flags); |
123 |
exit(1); |
124 |
} |
125 |
|
126 |
/* I've only encountered flags == 1 so far. */ |
127 |
if (flags != 1) { |
128 |
fatal("Error: Unimplemented flags 0x%x\n", flags); |
129 |
exit(1); |
130 |
} |
131 |
|
132 |
/* |
133 |
* Read all load commands: |
134 |
*/ |
135 |
pos = is_64bit? 32 : 28; |
136 |
cmd_type = 0; |
137 |
do { |
138 |
/* Read command type and length: */ |
139 |
unencode(cmd_type, &buf[pos], uint32_t); |
140 |
unencode(cmd_len, &buf[pos+4], uint32_t); |
141 |
|
142 |
#if 0 |
143 |
debug("cmd %i, len=%i\n", cmd_type, cmd_len); |
144 |
for (i=8; i<cmd_len; i++) { |
145 |
unsigned char ch = buf[pos+i]; |
146 |
if (ch >= ' ' && ch < 127) |
147 |
debug("%c", ch); |
148 |
else |
149 |
debug("."); |
150 |
} |
151 |
#endif |
152 |
switch (cmd_type) { |
153 |
case 1: /* LC_SEGMENT */ |
154 |
debug("seg "); |
155 |
for (i=0; i<16; i++) { |
156 |
if (buf[pos + 8 + i] == 0) |
157 |
break; |
158 |
debug("%c", buf[pos + 8 + i]); |
159 |
} |
160 |
unencode(vmaddr, &buf[pos+8+16+0], uint32_t); |
161 |
unencode(vmsize, &buf[pos+8+16+4], uint32_t); |
162 |
unencode(fileoff, &buf[pos+8+16+8], uint32_t); |
163 |
unencode(filesize, &buf[pos+8+16+12], uint32_t); |
164 |
debug(": vmaddr=0x%x size=0x%x fileoff=0x%x", |
165 |
(int)vmaddr, (int)vmsize, (int)fileoff); |
166 |
|
167 |
if (filesize == 0) { |
168 |
debug("\n"); |
169 |
break; |
170 |
} |
171 |
|
172 |
fseek(f, fileoff, SEEK_SET); |
173 |
|
174 |
/* Load data from the file: */ |
175 |
while (filesize != 0) { |
176 |
unsigned char buf[32768]; |
177 |
ssize_t len = filesize > sizeof(buf) ? |
178 |
sizeof(buf) : filesize; |
179 |
len = fread(buf, 1, len, f); |
180 |
|
181 |
/* printf("fread len=%i vmaddr=%x buf[0..]=" |
182 |
"%02x %02x %02x\n", (int)len, (int)vmaddr, |
183 |
buf[0], buf[1], buf[2]); */ |
184 |
|
185 |
if (len > 0) { |
186 |
int len2 = 0; |
187 |
uint64_t vaddr1 = vmaddr & |
188 |
((1 << BITS_PER_MEMBLOCK) - 1); |
189 |
uint64_t vaddr2 = (vmaddr + |
190 |
len) & ((1 << BITS_PER_MEMBLOCK)-1); |
191 |
if (vaddr2 < vaddr1) { |
192 |
len2 = len - vaddr2; |
193 |
m->cpus[0]->memory_rw(m->cpus[ |
194 |
0], mem, vmaddr, &buf[0], |
195 |
len2, MEM_WRITE, |
196 |
NO_EXCEPTIONS); |
197 |
} |
198 |
m->cpus[0]->memory_rw(m->cpus[0], mem, |
199 |
vmaddr + len2, &buf[len2], len-len2, |
200 |
MEM_WRITE, NO_EXCEPTIONS); |
201 |
} else { |
202 |
fprintf(stderr, "error reading\n"); |
203 |
exit(1); |
204 |
} |
205 |
|
206 |
vmaddr += len; |
207 |
filesize -= len; |
208 |
} |
209 |
|
210 |
debug("\n"); |
211 |
break; |
212 |
|
213 |
case 2: /* LC_SYMTAB */ |
214 |
unencode(symoff, &buf[pos+8], uint32_t); |
215 |
unencode(nsyms, &buf[pos+12], uint32_t); |
216 |
unencode(stroff, &buf[pos+16], uint32_t); |
217 |
unencode(strsize, &buf[pos+20], uint32_t); |
218 |
debug("symtable: %i symbols @ 0x%x (strings at " |
219 |
"0x%x)\n", nsyms, symoff, stroff); |
220 |
|
221 |
CHECK_ALLOCATION(symbols = malloc(12 * nsyms)); |
222 |
fseek(f, symoff, SEEK_SET); |
223 |
fread(symbols, 1, 12 * nsyms, f); |
224 |
|
225 |
CHECK_ALLOCATION(strings = malloc(strsize)); |
226 |
fseek(f, stroff, SEEK_SET); |
227 |
fread(strings, 1, strsize, f); |
228 |
|
229 |
for (i=0; i<nsyms; i++) { |
230 |
int n_strx, n_type, n_sect, n_desc; |
231 |
uint32_t n_value; |
232 |
unencode(n_strx, &symbols[i*12+0], int32_t); |
233 |
unencode(n_type, &symbols[i*12+4], uint8_t); |
234 |
unencode(n_sect, &symbols[i*12+5], uint8_t); |
235 |
unencode(n_desc, &symbols[i*12+6], int16_t); |
236 |
unencode(n_value, &symbols[i*12+8], uint32_t); |
237 |
/* debug("%i: strx=%i type=%i sect=%i desc=%i" |
238 |
" value=0x%x\n", i, n_strx, n_type, |
239 |
n_sect, n_desc, n_value); */ |
240 |
add_symbol_name(&m->symbol_context, |
241 |
n_value, 0, strings + n_strx, 0, -1); |
242 |
} |
243 |
|
244 |
free(symbols); |
245 |
free(strings); |
246 |
break; |
247 |
|
248 |
case 5: debug("unix thread context: "); |
249 |
/* See http://cvs.sf.net/viewcvs.py/hte/ |
250 |
HT%20Editor/machostruc.h or similar for details |
251 |
on the thread struct. */ |
252 |
unencode(flavor, &buf[pos+8], uint32_t); |
253 |
if (flavor != 1) { |
254 |
fatal("unimplemented flavor %i\n", flavor); |
255 |
exit(1); |
256 |
} |
257 |
|
258 |
if (arch != ARCH_PPC) { |
259 |
fatal("non-PPC arch? TODO\n"); |
260 |
exit(1); |
261 |
} |
262 |
|
263 |
unencode(entry, &buf[pos+16], uint32_t); |
264 |
entry_set = 1; |
265 |
debug("pc=0x%x\n", (int)entry); |
266 |
|
267 |
for (i=1; i<40; i++) { |
268 |
uint32_t x; |
269 |
unencode(x, &buf[pos+16+i*4], uint32_t); |
270 |
if (x != 0) { |
271 |
fatal("Entry nr %i in the Mach-O" |
272 |
" thread struct is non-zero" |
273 |
" (0x%x). This is not supported" |
274 |
" yet. TODO\n", i, x); |
275 |
exit(1); |
276 |
} |
277 |
} |
278 |
break; |
279 |
|
280 |
default:fatal("WARNING! Unimplemented load command %i!\n", |
281 |
cmd_type); |
282 |
} |
283 |
|
284 |
pos += cmd_len; |
285 |
} while (pos < sizeofcmds && cmd_type != 0); |
286 |
|
287 |
fclose(f); |
288 |
|
289 |
if (!entry_set) { |
290 |
fatal("No entry point? Aborting.\n"); |
291 |
exit(1); |
292 |
} |
293 |
|
294 |
*entrypointp = entry; |
295 |
|
296 |
if (encoding == ELFDATA2LSB) |
297 |
*byte_orderp = EMUL_LITTLE_ENDIAN; |
298 |
else |
299 |
*byte_orderp = EMUL_BIG_ENDIAN; |
300 |
|
301 |
n_executables_loaded ++; |
302 |
} |
303 |
|