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