1 |
/* |
2 |
* Copyright (C) 2003-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_elf.c,v 1.2 2007/04/18 14:08:35 debug Exp $ |
29 |
* |
30 |
* ELF file support. |
31 |
*/ |
32 |
|
33 |
/* Note: Included from file.c. */ |
34 |
|
35 |
|
36 |
#include "exec_elf.h" |
37 |
|
38 |
/* ELF machine types as strings: (same as exec_elf.h) */ |
39 |
#define N_ELF_MACHINE_TYPES 84 |
40 |
static char *elf_machine_type[N_ELF_MACHINE_TYPES] = { |
41 |
"NONE", "M32", "SPARC", "386", /* 0..3 */ |
42 |
"68K", "88K", "486", "860", /* 4..7 */ |
43 |
"MIPS", "S370", "MIPS_RS3_LE", "RS6000", /* 8..11 */ |
44 |
"unknown12", "unknown13", "unknown14", "PARISC", /* 12..15 */ |
45 |
"NCUBE", "VPP500", "SPARC32PLUS", "960", /* 16..19 */ |
46 |
"PPC", "PPC64", "unknown22", "unknown23", /* 20..23 */ |
47 |
"unknown24", "unknown25", "unknown26", "unknown27", /* 24..27 */ |
48 |
"unknown28", "unknown29", "unknown30", "unknown31", /* 28..31 */ |
49 |
"unknown32", "unknown33", "unknown34", "unknown35", /* 32..35 */ |
50 |
"V800", "FR20", "RH32", "RCE", /* 36..39 */ |
51 |
"ARM", "ALPHA", "SH", "SPARCV9", /* 40..43 */ |
52 |
"TRICORE", "ARC", "H8_300", "H8_300H", /* 44..47 */ |
53 |
"H8S", "H8_500", "IA_64", "MIPS_X", /* 48..51 */ |
54 |
"COLDFIRE", "68HC12", "unknown54", "unknown55", /* 52..55 */ |
55 |
"unknown56", "unknown57", "unknown58", "unknown59", /* 56..59 */ |
56 |
"unknown60", "unknown61", "AMD64", "unknown63", /* 60..63 */ |
57 |
"unknown64", "unknown65", "unknown66", "unknown67", /* 64..67 */ |
58 |
"unknown68", "unknown69", "unknown70", "unknown71", /* 68..71 */ |
59 |
"unknown72", "unknown73", "unknown74", "unknown75", /* 72..75 */ |
60 |
"unknown76", "unknown77", "unknown78", "unknown79", /* 76..79 */ |
61 |
"unknown80", "unknown81", "unknown82", "AVR" /* 80..83 */ |
62 |
}; |
63 |
|
64 |
|
65 |
/* |
66 |
* file_load_elf(): |
67 |
* |
68 |
* Loads an ELF image into the emulated memory. The entry point (read from |
69 |
* the ELF header) and the initial value of the gp register (read from the |
70 |
* ELF symbol table) are stored in the specified CPU's registers. |
71 |
* |
72 |
* This is pretty heavy stuff, but is needed because of the heaviness of |
73 |
* ELF files. :-/ Hopefully it will be able to recognize most valid ELFs. |
74 |
*/ |
75 |
static void file_load_elf(struct machine *m, struct memory *mem, |
76 |
char *filename, uint64_t *entrypointp, int arch, uint64_t *gpp, |
77 |
int *byte_order, uint64_t *tocp) |
78 |
{ |
79 |
Elf32_Ehdr hdr32; |
80 |
Elf64_Ehdr hdr64; |
81 |
FILE *f; |
82 |
uint64_t eentry; |
83 |
int len, i, ok; |
84 |
int elf64, encoding, eflags; |
85 |
int etype, emachine; |
86 |
int ephnum, ephentsize, eshnum, eshentsize; |
87 |
off_t ephoff, eshoff; |
88 |
Elf32_Phdr phdr32; |
89 |
Elf64_Phdr phdr64; |
90 |
Elf32_Shdr shdr32; |
91 |
Elf64_Shdr shdr64; |
92 |
Elf32_Sym sym32; |
93 |
Elf64_Sym sym64; |
94 |
int ofs; |
95 |
int chunk_len = 1024, align_len; |
96 |
char *symbol_strings = NULL; size_t symbol_length = 0; |
97 |
char *s; |
98 |
Elf32_Sym *symbols_sym32 = NULL; int n_symbols = 0; |
99 |
Elf64_Sym *symbols_sym64 = NULL; |
100 |
|
101 |
f = fopen(filename, "r"); |
102 |
if (f == NULL) { |
103 |
perror(filename); |
104 |
exit(1); |
105 |
} |
106 |
|
107 |
len = fread(&hdr32, 1, sizeof(Elf32_Ehdr), f); |
108 |
if (len < (signed int)sizeof(Elf32_Ehdr)) { |
109 |
fprintf(stderr, "%s: not an ELF file image\n", filename); |
110 |
exit(1); |
111 |
} |
112 |
|
113 |
if (memcmp(&hdr32.e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) { |
114 |
fprintf(stderr, "%s: not an ELF file image\n", filename); |
115 |
exit(1); |
116 |
} |
117 |
|
118 |
switch (hdr32.e_ident[EI_CLASS]) { |
119 |
case ELFCLASS32: |
120 |
elf64 = 0; |
121 |
break; |
122 |
case ELFCLASS64: |
123 |
elf64 = 1; |
124 |
fseek(f, 0, SEEK_SET); |
125 |
len = fread(&hdr64, 1, sizeof(Elf64_Ehdr), f); |
126 |
if (len < (signed int)sizeof(Elf64_Ehdr)) { |
127 |
fprintf(stderr, "%s: not an ELF64 file image\n", |
128 |
filename); |
129 |
exit(1); |
130 |
} |
131 |
break; |
132 |
default: |
133 |
fprintf(stderr, "%s: unknown ELF class '%i'\n", |
134 |
filename, hdr32.e_ident[EI_CLASS]); |
135 |
exit(1); |
136 |
} |
137 |
|
138 |
encoding = hdr32.e_ident[EI_DATA]; |
139 |
if (encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) { |
140 |
fprintf(stderr, "%s: unknown data encoding '%i'\n", |
141 |
filename, hdr32.e_ident[EI_DATA]); |
142 |
exit(1); |
143 |
} |
144 |
|
145 |
if (elf64) { |
146 |
unencode(etype, &hdr64.e_type, Elf64_Quarter); |
147 |
unencode(eflags, &hdr64.e_flags, Elf64_Half); |
148 |
unencode(emachine, &hdr64.e_machine, Elf64_Quarter); |
149 |
unencode(eentry, &hdr64.e_entry, Elf64_Addr); |
150 |
unencode(ephnum, &hdr64.e_phnum, Elf64_Quarter); |
151 |
unencode(ephentsize, &hdr64.e_phentsize, Elf64_Quarter); |
152 |
unencode(ephoff, &hdr64.e_phoff, Elf64_Off); |
153 |
unencode(eshnum, &hdr64.e_shnum, Elf64_Quarter); |
154 |
unencode(eshentsize, &hdr64.e_shentsize, Elf64_Quarter); |
155 |
unencode(eshoff, &hdr64.e_shoff, Elf64_Off); |
156 |
if (ephentsize != sizeof(Elf64_Phdr)) { |
157 |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
158 |
"be %i\nPerhaps this is a dynamically linked " |
159 |
"binary (which isn't supported yet).\n", filename, |
160 |
(int)ephentsize, (int)sizeof(Elf64_Phdr)); |
161 |
exit(1); |
162 |
} |
163 |
if (eshentsize != sizeof(Elf64_Shdr)) { |
164 |
fprintf(stderr, "%s: incorrect shentsize? %i, should " |
165 |
"be %i\nPerhaps this is a dynamically linked " |
166 |
"binary (which isn't supported yet).\n", filename, |
167 |
(int)eshentsize, (int)sizeof(Elf64_Shdr)); |
168 |
exit(1); |
169 |
} |
170 |
} else { |
171 |
unencode(etype, &hdr32.e_type, Elf32_Half); |
172 |
unencode(eflags, &hdr32.e_flags, Elf32_Word); |
173 |
unencode(emachine, &hdr32.e_machine, Elf32_Half); |
174 |
unencode(eentry, &hdr32.e_entry, Elf32_Addr); |
175 |
unencode(ephnum, &hdr32.e_phnum, Elf32_Half); |
176 |
unencode(ephentsize, &hdr32.e_phentsize, Elf32_Half); |
177 |
unencode(ephoff, &hdr32.e_phoff, Elf32_Off); |
178 |
unencode(eshnum, &hdr32.e_shnum, Elf32_Half); |
179 |
unencode(eshentsize, &hdr32.e_shentsize, Elf32_Half); |
180 |
unencode(eshoff, &hdr32.e_shoff, Elf32_Off); |
181 |
if (ephentsize != sizeof(Elf32_Phdr)) { |
182 |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
183 |
"be %i\nPerhaps this is a dynamically linked " |
184 |
"binary (which isn't supported yet).\n", filename, |
185 |
(int)ephentsize, (int)sizeof(Elf32_Phdr)); |
186 |
exit(1); |
187 |
} |
188 |
if (eshentsize != sizeof(Elf32_Shdr)) { |
189 |
fprintf(stderr, "%s: incorrect shentsize? %i, should " |
190 |
"be %i\nPerhaps this is a dynamically linked " |
191 |
"binary (which isn't supported yet).\n", filename, |
192 |
(int)eshentsize, (int)sizeof(Elf32_Shdr)); |
193 |
exit(1); |
194 |
} |
195 |
} |
196 |
|
197 |
if ( etype != ET_EXEC ) { |
198 |
fprintf(stderr, "%s is not an ELF Executable file, type = %i\n", |
199 |
filename, etype); |
200 |
exit(1); |
201 |
} |
202 |
|
203 |
ok = 0; |
204 |
switch (arch) { |
205 |
case ARCH_ALPHA: |
206 |
switch (emachine) { |
207 |
case EM_ALPHA: |
208 |
case -28634: |
209 |
ok = 1; |
210 |
} |
211 |
break; |
212 |
case ARCH_ARM: |
213 |
switch (emachine) { |
214 |
case EM_ARM: |
215 |
ok = 1; |
216 |
} |
217 |
break; |
218 |
case ARCH_AVR: |
219 |
switch (emachine) { |
220 |
case EM_AVR: |
221 |
ok = 1; |
222 |
} |
223 |
break; |
224 |
/* case ARCH_AVR32: |
225 |
switch (emachine) { |
226 |
case 6317: |
227 |
ok = 1; |
228 |
} |
229 |
break; |
230 |
case ARCH_HPPA: |
231 |
switch (emachine) { |
232 |
case EM_PARISC: |
233 |
ok = 1; |
234 |
} |
235 |
break; |
236 |
case ARCH_I960: |
237 |
switch (emachine) { |
238 |
case EM_960: |
239 |
ok = 1; |
240 |
} |
241 |
break; |
242 |
case ARCH_IA64: |
243 |
switch (emachine) { |
244 |
case EM_IA_64: |
245 |
ok = 1; |
246 |
} |
247 |
break; */ |
248 |
/* case ARCH_M68K: |
249 |
switch (emachine) { |
250 |
case EM_68K: |
251 |
ok = 1; |
252 |
} |
253 |
break; */ |
254 |
case ARCH_MIPS: |
255 |
switch (emachine) { |
256 |
case EM_MIPS: |
257 |
case EM_MIPS_RS3_LE: |
258 |
ok = 1; |
259 |
} |
260 |
break; |
261 |
case ARCH_PPC: |
262 |
switch (emachine) { |
263 |
case EM_PPC: |
264 |
case EM_PPC64: |
265 |
ok = 1; |
266 |
} |
267 |
break; |
268 |
case ARCH_SH: |
269 |
switch (emachine) { |
270 |
case EM_SH: |
271 |
ok = 1; |
272 |
} |
273 |
break; |
274 |
case ARCH_SPARC: |
275 |
switch (emachine) { |
276 |
case EM_SPARC: |
277 |
case EM_SPARCV9: |
278 |
ok = 1; |
279 |
} |
280 |
break; |
281 |
/* case ARCH_X86: |
282 |
switch (emachine) { |
283 |
case EM_386: |
284 |
case EM_486: |
285 |
*tocp = 1; |
286 |
ok = 1; |
287 |
break; |
288 |
case EM_AMD64: |
289 |
*tocp = 2; |
290 |
ok = 1; |
291 |
break; |
292 |
} |
293 |
break; */ |
294 |
default: |
295 |
fatal("file.c: INTERNAL ERROR: Unimplemented arch!\n"); |
296 |
} |
297 |
if (!ok) { |
298 |
fprintf(stderr, "%s: this is a ", filename); |
299 |
if (emachine >= 0 && emachine < N_ELF_MACHINE_TYPES) |
300 |
fprintf(stderr, elf_machine_type[emachine]); |
301 |
else |
302 |
fprintf(stderr, "machine type '%i'", emachine); |
303 |
fprintf(stderr, " ELF binary!\n"); |
304 |
exit(1); |
305 |
} |
306 |
|
307 |
s = "entry point"; |
308 |
if (elf64 && arch == ARCH_PPC) |
309 |
s = "function descriptor at"; |
310 |
|
311 |
debug("ELF%i %s, %s 0x", elf64? 64 : 32, |
312 |
encoding == ELFDATA2LSB? "LSB (LE)" : "MSB (BE)", s); |
313 |
|
314 |
if (elf64) |
315 |
debug("%016"PRIx64"\n", (uint64_t) eentry); |
316 |
else |
317 |
debug("%08"PRIx32"\n", (uint32_t) eentry); |
318 |
|
319 |
/* |
320 |
* SH64: 32-bit instruction encoding? |
321 |
*/ |
322 |
if (arch == ARCH_SH && (eentry & 1)) { |
323 |
debug("SH64: 32-bit instruction encoding\n"); |
324 |
m->cpus[0]->cd.sh.compact = 0; |
325 |
m->cpus[0]->cd.sh.cpu_type.bits = 64; |
326 |
} |
327 |
|
328 |
/* Read the program headers: */ |
329 |
|
330 |
for (i=0; i<ephnum; i++) { |
331 |
int p_type; |
332 |
uint64_t p_offset; |
333 |
uint64_t p_vaddr; |
334 |
uint64_t p_paddr; |
335 |
uint64_t p_filesz; |
336 |
uint64_t p_memsz; |
337 |
int p_flags; |
338 |
int p_align; |
339 |
|
340 |
fseek(f, ephoff + i * ephentsize, SEEK_SET); |
341 |
|
342 |
if (elf64) { |
343 |
fread(&phdr64, 1, sizeof(Elf64_Phdr), f); |
344 |
unencode(p_type, &phdr64.p_type, Elf64_Half); |
345 |
unencode(p_flags, &phdr64.p_flags, Elf64_Half); |
346 |
unencode(p_offset, &phdr64.p_offset, Elf64_Off); |
347 |
unencode(p_vaddr, &phdr64.p_vaddr, Elf64_Addr); |
348 |
unencode(p_paddr, &phdr64.p_paddr, Elf64_Addr); |
349 |
unencode(p_filesz, &phdr64.p_filesz, Elf64_Xword); |
350 |
unencode(p_memsz, &phdr64.p_memsz, Elf64_Xword); |
351 |
unencode(p_align, &phdr64.p_align, Elf64_Xword); |
352 |
} else { |
353 |
fread(&phdr32, 1, sizeof(Elf32_Phdr), f); |
354 |
unencode(p_type, &phdr32.p_type, Elf32_Word); |
355 |
unencode(p_offset, &phdr32.p_offset, Elf32_Off); |
356 |
unencode(p_vaddr, &phdr32.p_vaddr, Elf32_Addr); |
357 |
unencode(p_paddr, &phdr32.p_paddr, Elf32_Addr); |
358 |
unencode(p_filesz, &phdr32.p_filesz, Elf32_Word); |
359 |
unencode(p_memsz, &phdr32.p_memsz, Elf32_Word); |
360 |
unencode(p_flags, &phdr32.p_flags, Elf32_Word); |
361 |
unencode(p_align, &phdr32.p_align, Elf32_Word); |
362 |
} |
363 |
|
364 |
/* |
365 |
* Hack for loading PPC kernels that are linked to high |
366 |
* addresses. (This requires enabling of instruction and |
367 |
* data virtual address translation.) |
368 |
*/ |
369 |
if (arch == ARCH_PPC) { |
370 |
if ( (elf64 && (p_vaddr >> 60) != 0) || |
371 |
(!elf64 && (p_vaddr >> 28) != 0) ) |
372 |
m->cpus[m->bootstrap_cpu]-> |
373 |
cd.ppc.msr |= PPC_MSR_IR | PPC_MSR_DR; |
374 |
} |
375 |
|
376 |
if (p_memsz != 0 && (p_type == PT_LOAD || |
377 |
(p_type & PF_MASKPROC) == PT_MIPS_REGINFO)) { |
378 |
debug("chunk %i (", i); |
379 |
if (p_type == PT_LOAD) |
380 |
debug("load"); |
381 |
else |
382 |
debug("0x%08"PRIx32, (uint32_t) p_type); |
383 |
|
384 |
debug(") @ 0x%"PRIx64", vaddr 0x", (uint64_t) p_offset); |
385 |
|
386 |
if (elf64) |
387 |
debug("%016"PRIx64, (uint64_t) p_vaddr); |
388 |
else |
389 |
debug("%08"PRIx32, (uint32_t) p_vaddr); |
390 |
|
391 |
debug(" len=0x%"PRIx64"\n", (uint64_t) p_memsz); |
392 |
|
393 |
if (p_vaddr != p_paddr) { |
394 |
if (elf64) |
395 |
debug("NOTE: vaddr (0x%"PRIx64") and " |
396 |
"paddr (0x%"PRIx64") differ; using " |
397 |
"vaddr\n", (uint64_t) p_vaddr, |
398 |
(uint64_t) p_paddr); |
399 |
else |
400 |
debug("NOTE: vaddr (0x%08"PRIx32") and " |
401 |
"paddr (0x%08"PRIx32") differ; usin" |
402 |
"g vaddr\n", (uint32_t) p_vaddr, |
403 |
(uint32_t)p_paddr); |
404 |
} |
405 |
|
406 |
if (p_memsz < p_filesz) { |
407 |
fprintf(stderr, "%s: memsz < filesz. TODO: how" |
408 |
" to handle this? memsz=%016"PRIx64 |
409 |
" filesz=%016"PRIx64"\n", filename, |
410 |
(uint64_t) p_memsz, (uint64_t) p_filesz); |
411 |
exit(1); |
412 |
} |
413 |
|
414 |
fseek(f, p_offset, SEEK_SET); |
415 |
align_len = 1; |
416 |
if ((p_vaddr & 0xf)==0) align_len = 0x10; |
417 |
if ((p_vaddr & 0x3f)==0) align_len = 0x40; |
418 |
if ((p_vaddr & 0xff)==0) align_len = 0x100; |
419 |
if ((p_vaddr & 0xfff)==0) align_len = 0x1000; |
420 |
if ((p_vaddr & 0x3fff)==0) align_len = 0x4000; |
421 |
if ((p_vaddr & 0xffff)==0) align_len = 0x10000; |
422 |
ofs = 0; len = chunk_len = align_len; |
423 |
while (ofs < (int64_t)p_filesz && len==chunk_len) { |
424 |
unsigned char *ch = malloc(chunk_len); |
425 |
int i = 0; |
426 |
|
427 |
/* Switch to larger size, if possible: */ |
428 |
if (align_len < 0x10000 && |
429 |
((p_vaddr + ofs) & 0xffff)==0) { |
430 |
align_len = 0x10000; |
431 |
len = chunk_len = align_len; |
432 |
free(ch); |
433 |
ch = malloc(chunk_len); |
434 |
} else if (align_len < 0x1000 && |
435 |
((p_vaddr + ofs) & 0xfff)==0) { |
436 |
align_len = 0x1000; |
437 |
len = chunk_len = align_len; |
438 |
free(ch); |
439 |
ch = malloc(chunk_len); |
440 |
} |
441 |
|
442 |
if (ch == NULL) { |
443 |
fprintf(stderr, "out of memory\n"); |
444 |
exit(1); |
445 |
} |
446 |
|
447 |
len = fread(&ch[0], 1, chunk_len, f); |
448 |
if (ofs + len > (int64_t)p_filesz) |
449 |
len = p_filesz - ofs; |
450 |
|
451 |
while (i < len) { |
452 |
size_t len_to_copy; |
453 |
len_to_copy = (i + align_len) <= len? |
454 |
align_len : len - i; |
455 |
m->cpus[0]->memory_rw(m->cpus[0], mem, |
456 |
p_vaddr + ofs, &ch[i], len_to_copy, |
457 |
MEM_WRITE, NO_EXCEPTIONS); |
458 |
ofs += align_len; |
459 |
i += align_len; |
460 |
} |
461 |
|
462 |
free(ch); |
463 |
} |
464 |
} |
465 |
} |
466 |
|
467 |
/* |
468 |
* Read the section headers to find the address of the _gp |
469 |
* symbol (for MIPS): |
470 |
*/ |
471 |
|
472 |
for (i=0; i<eshnum; i++) { |
473 |
int sh_name, sh_type, sh_flags, sh_link, sh_info, sh_entsize; |
474 |
uint64_t sh_addr, sh_size, sh_addralign; |
475 |
off_t sh_offset; |
476 |
int n_entries; /* for reading the symbol / string tables */ |
477 |
|
478 |
/* debug("section header %i at %016"PRIx64"\n", i, |
479 |
(uint64_t) eshoff+i*eshentsize); */ |
480 |
|
481 |
fseek(f, eshoff + i * eshentsize, SEEK_SET); |
482 |
|
483 |
if (elf64) { |
484 |
len = fread(&shdr64, 1, sizeof(Elf64_Shdr), f); |
485 |
if (len != sizeof(Elf64_Shdr)) { |
486 |
fprintf(stderr, "couldn't read header\n"); |
487 |
exit(1); |
488 |
} |
489 |
unencode(sh_name, &shdr64.sh_name, Elf64_Half); |
490 |
unencode(sh_type, &shdr64.sh_type, Elf64_Half); |
491 |
unencode(sh_flags, &shdr64.sh_flags, Elf64_Xword); |
492 |
unencode(sh_addr, &shdr64.sh_addr, Elf64_Addr); |
493 |
unencode(sh_offset, &shdr64.sh_offset, Elf64_Off); |
494 |
unencode(sh_size, &shdr64.sh_size, Elf64_Xword); |
495 |
unencode(sh_link, &shdr64.sh_link, Elf64_Half); |
496 |
unencode(sh_info, &shdr64.sh_info, Elf64_Half); |
497 |
unencode(sh_addralign, &shdr64.sh_addralign, |
498 |
Elf64_Xword); |
499 |
unencode(sh_entsize, &shdr64.sh_entsize, Elf64_Xword); |
500 |
} else { |
501 |
len = fread(&shdr32, 1, sizeof(Elf32_Shdr), f); |
502 |
if (len != sizeof(Elf32_Shdr)) { |
503 |
fprintf(stderr, "couldn't read header\n"); |
504 |
exit(1); |
505 |
} |
506 |
unencode(sh_name, &shdr32.sh_name, Elf32_Word); |
507 |
unencode(sh_type, &shdr32.sh_type, Elf32_Word); |
508 |
unencode(sh_flags, &shdr32.sh_flags, Elf32_Word); |
509 |
unencode(sh_addr, &shdr32.sh_addr, Elf32_Addr); |
510 |
unencode(sh_offset, &shdr32.sh_offset, Elf32_Off); |
511 |
unencode(sh_size, &shdr32.sh_size, Elf32_Word); |
512 |
unencode(sh_link, &shdr32.sh_link, Elf32_Word); |
513 |
unencode(sh_info, &shdr32.sh_info, Elf32_Word); |
514 |
unencode(sh_addralign, &shdr32.sh_addralign,Elf32_Word); |
515 |
unencode(sh_entsize, &shdr32.sh_entsize, Elf32_Word); |
516 |
} |
517 |
|
518 |
/* debug("sh_name=%04lx, sh_type=%08lx, sh_flags=%08lx" |
519 |
" sh_size=%06lx sh_entsize=%03lx\n", |
520 |
(long)sh_name, (long)sh_type, (long)sh_flags, |
521 |
(long)sh_size, (long)sh_entsize); */ |
522 |
|
523 |
/* Perhaps it is bad to reuse sh_entsize like this? TODO */ |
524 |
if (elf64) |
525 |
sh_entsize = sizeof(Elf64_Sym); |
526 |
else |
527 |
sh_entsize = sizeof(Elf32_Sym); |
528 |
|
529 |
if (sh_type == SHT_SYMTAB) { |
530 |
size_t len; |
531 |
n_entries = sh_size / sh_entsize; |
532 |
|
533 |
fseek(f, sh_offset, SEEK_SET); |
534 |
|
535 |
if (elf64) { |
536 |
if (symbols_sym64 != NULL) |
537 |
free(symbols_sym64); |
538 |
symbols_sym64 = malloc(sh_size); |
539 |
if (symbols_sym64 == NULL) { |
540 |
fprintf(stderr, "out of memory\n"); |
541 |
exit(1); |
542 |
} |
543 |
|
544 |
len = fread(symbols_sym64, 1, sh_entsize * |
545 |
n_entries, f); |
546 |
} else { |
547 |
if (symbols_sym32 != NULL) |
548 |
free(symbols_sym32); |
549 |
symbols_sym32 = malloc(sh_size); |
550 |
if (symbols_sym32 == NULL) { |
551 |
fprintf(stderr, "out of memory\n"); |
552 |
exit(1); |
553 |
} |
554 |
|
555 |
len = fread(symbols_sym32, 1, |
556 |
sh_entsize * n_entries, f); |
557 |
} |
558 |
|
559 |
if (len != sh_size) { |
560 |
fprintf(stderr, "could not read symbols from " |
561 |
"%s\n", filename); |
562 |
exit(1); |
563 |
} |
564 |
|
565 |
debug("%i symbol entries at 0x%"PRIx64"\n", |
566 |
(int) n_entries, (uint64_t) sh_offset); |
567 |
|
568 |
n_symbols = n_entries; |
569 |
} |
570 |
|
571 |
/* |
572 |
* TODO: This is incorrect, there may be several strtab |
573 |
* sections. |
574 |
* |
575 |
* For now, the simple/stupid guess that the largest string |
576 |
* table is the one to use seems to be good enough. |
577 |
*/ |
578 |
|
579 |
if (sh_type == SHT_STRTAB && sh_size > symbol_length) { |
580 |
size_t len; |
581 |
|
582 |
if (symbol_strings != NULL) |
583 |
free(symbol_strings); |
584 |
|
585 |
symbol_strings = malloc(sh_size + 1); |
586 |
if (symbol_strings == NULL) { |
587 |
fprintf(stderr, "out of memory\n"); |
588 |
exit(1); |
589 |
} |
590 |
|
591 |
fseek(f, sh_offset, SEEK_SET); |
592 |
len = fread(symbol_strings, 1, sh_size, f); |
593 |
if (len != sh_size) { |
594 |
fprintf(stderr, "could not read symbols from " |
595 |
"%s\n", filename); |
596 |
exit(1); |
597 |
} |
598 |
|
599 |
debug("%i bytes of symbol strings at 0x%"PRIx64"\n", |
600 |
(int) sh_size, (uint64_t) sh_offset); |
601 |
|
602 |
symbol_strings[sh_size] = '\0'; |
603 |
symbol_length = sh_size; |
604 |
} |
605 |
} |
606 |
|
607 |
fclose(f); |
608 |
|
609 |
/* Decode symbols: */ |
610 |
if (symbol_strings != NULL) { |
611 |
for (i=0; i<n_symbols; i++) { |
612 |
uint64_t st_name, addr, size; |
613 |
int st_info; |
614 |
|
615 |
if (elf64) { |
616 |
sym64 = symbols_sym64[i]; |
617 |
unencode(st_name, &sym64.st_name, Elf64_Half); |
618 |
unencode(st_info, &sym64.st_info, Elf_Byte); |
619 |
unencode(addr, &sym64.st_value, Elf64_Addr); |
620 |
unencode(size, &sym64.st_size, Elf64_Xword); |
621 |
} else { |
622 |
sym32 = symbols_sym32[i]; |
623 |
unencode(st_name, &sym32.st_name, Elf32_Word); |
624 |
unencode(st_info, &sym32.st_info, Elf_Byte); |
625 |
unencode(addr, &sym32.st_value, Elf32_Word); |
626 |
unencode(size, &sym32.st_size, Elf32_Word); |
627 |
} |
628 |
|
629 |
/* debug("symbol info=0x%02x addr=0x%016"PRIx64 |
630 |
" (%i) '%s'\n", st_info, (uint64_t) addr, |
631 |
st_name, symbol_strings + st_name); */ |
632 |
|
633 |
if (size == 0) |
634 |
size ++; |
635 |
|
636 |
if (addr != 0) /* && ((st_info >> 4) & 0xf) |
637 |
>= STB_GLOBAL) */ { |
638 |
/* debug("symbol info=0x%02x addr=0x%016"PRIx64 |
639 |
" '%s'\n", st_info, (uint64_t) addr, |
640 |
symbol_strings + st_name); */ |
641 |
add_symbol_name(&m->symbol_context, |
642 |
addr, size, symbol_strings + st_name, |
643 |
0, -1); |
644 |
} |
645 |
|
646 |
if (strcmp(symbol_strings + st_name, "_gp") == 0) { |
647 |
debug("found _gp address: 0x"); |
648 |
if (elf64) |
649 |
debug("%016"PRIx64"\n", (uint64_t)addr); |
650 |
else |
651 |
debug("%08"PRIx32"\n", (uint32_t)addr); |
652 |
*gpp = addr; |
653 |
} |
654 |
} |
655 |
} |
656 |
|
657 |
*entrypointp = eentry; |
658 |
|
659 |
if (encoding == ELFDATA2LSB) |
660 |
*byte_order = EMUL_LITTLE_ENDIAN; |
661 |
else |
662 |
*byte_order = EMUL_BIG_ENDIAN; |
663 |
|
664 |
if (elf64 && arch == ARCH_PPC) { |
665 |
/* |
666 |
* Special case for 64-bit PPC ELFs: |
667 |
* |
668 |
* The ELF starting symbol points to a ".opd" section |
669 |
* which contains a function descriptor: |
670 |
* |
671 |
* uint64_t start; |
672 |
* uint64_t toc_base; |
673 |
* uint64_t something_else; (?) |
674 |
*/ |
675 |
int res; |
676 |
unsigned char b[sizeof(uint64_t)]; |
677 |
uint64_t toc_base; |
678 |
|
679 |
debug("PPC64: "); |
680 |
|
681 |
res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry, b, |
682 |
sizeof(b), MEM_READ, NO_EXCEPTIONS); |
683 |
if (!res) |
684 |
debug(" [WARNING: could not read memory?] "); |
685 |
|
686 |
/* PPC are always big-endian: */ |
687 |
*entrypointp = ((uint64_t)b[0] << 56) + |
688 |
((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + |
689 |
((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + |
690 |
((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + |
691 |
(uint64_t)b[7]; |
692 |
|
693 |
res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry + 8, |
694 |
b, sizeof(b), MEM_READ, NO_EXCEPTIONS); |
695 |
if (!res) |
696 |
fatal(" [WARNING: could not read memory?] "); |
697 |
|
698 |
toc_base = ((uint64_t)b[0] << 56) + |
699 |
((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + |
700 |
((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + |
701 |
((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + |
702 |
(uint64_t)b[7]; |
703 |
|
704 |
debug("entrypoint 0x%016"PRIx64", toc_base 0x%016"PRIx64"\n", |
705 |
(uint64_t) *entrypointp, (uint64_t) toc_base); |
706 |
if (tocp != NULL) |
707 |
*tocp = toc_base; |
708 |
} |
709 |
|
710 |
n_executables_loaded ++; |
711 |
} |
712 |
|