/[gxemul]/trunk/src/file/file_elf.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/file/file_elf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 21029 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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.5 2007/06/15 17:02:39 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 fatal("SH64: 32-bit instruction encoding: TODO\n");
324 /* m->cpus[0]->cd.sh.compact = 0; */
325 m->cpus[0]->cd.sh.cpu_type.bits = 64;
326 exit(1);
327 }
328
329 /* Read the program headers: */
330
331 for (i=0; i<ephnum; i++) {
332 int p_type;
333 uint64_t p_offset;
334 uint64_t p_vaddr;
335 uint64_t p_paddr;
336 uint64_t p_filesz;
337 uint64_t p_memsz;
338 int p_flags;
339 int p_align;
340
341 fseek(f, ephoff + i * ephentsize, SEEK_SET);
342
343 if (elf64) {
344 fread(&phdr64, 1, sizeof(Elf64_Phdr), f);
345 unencode(p_type, &phdr64.p_type, Elf64_Half);
346 unencode(p_flags, &phdr64.p_flags, Elf64_Half);
347 unencode(p_offset, &phdr64.p_offset, Elf64_Off);
348 unencode(p_vaddr, &phdr64.p_vaddr, Elf64_Addr);
349 unencode(p_paddr, &phdr64.p_paddr, Elf64_Addr);
350 unencode(p_filesz, &phdr64.p_filesz, Elf64_Xword);
351 unencode(p_memsz, &phdr64.p_memsz, Elf64_Xword);
352 unencode(p_align, &phdr64.p_align, Elf64_Xword);
353 } else {
354 fread(&phdr32, 1, sizeof(Elf32_Phdr), f);
355 unencode(p_type, &phdr32.p_type, Elf32_Word);
356 unencode(p_offset, &phdr32.p_offset, Elf32_Off);
357 unencode(p_vaddr, &phdr32.p_vaddr, Elf32_Addr);
358 unencode(p_paddr, &phdr32.p_paddr, Elf32_Addr);
359 unencode(p_filesz, &phdr32.p_filesz, Elf32_Word);
360 unencode(p_memsz, &phdr32.p_memsz, Elf32_Word);
361 unencode(p_flags, &phdr32.p_flags, Elf32_Word);
362 unencode(p_align, &phdr32.p_align, Elf32_Word);
363 }
364
365 /*
366 * Hack for loading PPC kernels that are linked to high
367 * addresses. (This requires enabling of instruction and
368 * data virtual address translation.)
369 */
370 if (arch == ARCH_PPC) {
371 if ( (elf64 && (p_vaddr >> 60) != 0) ||
372 (!elf64 && (p_vaddr >> 28) != 0) )
373 m->cpus[m->bootstrap_cpu]->
374 cd.ppc.msr |= PPC_MSR_IR | PPC_MSR_DR;
375 }
376
377 if (p_memsz != 0 && (p_type == PT_LOAD ||
378 (p_type & PF_MASKPROC) == PT_MIPS_REGINFO)) {
379 debug("chunk %i (", i);
380 if (p_type == PT_LOAD)
381 debug("load");
382 else
383 debug("0x%08"PRIx32, (uint32_t) p_type);
384
385 debug(") @ 0x%"PRIx64", vaddr 0x", (uint64_t) p_offset);
386
387 if (elf64)
388 debug("%016"PRIx64, (uint64_t) p_vaddr);
389 else
390 debug("%08"PRIx32, (uint32_t) p_vaddr);
391
392 debug(" len=0x%"PRIx64"\n", (uint64_t) p_memsz);
393
394 if (p_vaddr != p_paddr) {
395 if (elf64)
396 debug("NOTE: vaddr (0x%"PRIx64") and "
397 "paddr (0x%"PRIx64") differ; using "
398 "vaddr\n", (uint64_t) p_vaddr,
399 (uint64_t) p_paddr);
400 else
401 debug("NOTE: vaddr (0x%08"PRIx32") and "
402 "paddr (0x%08"PRIx32") differ; usin"
403 "g vaddr\n", (uint32_t) p_vaddr,
404 (uint32_t)p_paddr);
405 }
406
407 if (p_memsz < p_filesz) {
408 fprintf(stderr, "%s: memsz < filesz. TODO: how"
409 " to handle this? memsz=%016"PRIx64
410 " filesz=%016"PRIx64"\n", filename,
411 (uint64_t) p_memsz, (uint64_t) p_filesz);
412 exit(1);
413 }
414
415 fseek(f, p_offset, SEEK_SET);
416 align_len = 1;
417 if ((p_vaddr & 0xf)==0) align_len = 0x10;
418 if ((p_vaddr & 0x3f)==0) align_len = 0x40;
419 if ((p_vaddr & 0xff)==0) align_len = 0x100;
420 if ((p_vaddr & 0xfff)==0) align_len = 0x1000;
421 if ((p_vaddr & 0x3fff)==0) align_len = 0x4000;
422 if ((p_vaddr & 0xffff)==0) align_len = 0x10000;
423 ofs = 0; len = chunk_len = align_len;
424 while (ofs < (int64_t)p_filesz && len==chunk_len) {
425 unsigned char *ch;
426 int i = 0;
427
428 CHECK_ALLOCATION(ch = malloc(chunk_len));
429
430 /* Switch to larger size, if possible: */
431 if (align_len < 0x10000 &&
432 ((p_vaddr + ofs) & 0xffff)==0) {
433 align_len = 0x10000;
434 len = chunk_len = align_len;
435 free(ch);
436 CHECK_ALLOCATION(ch=malloc(chunk_len));
437 } else if (align_len < 0x1000 &&
438 ((p_vaddr + ofs) & 0xfff)==0) {
439 align_len = 0x1000;
440 len = chunk_len = align_len;
441 free(ch);
442 CHECK_ALLOCATION(ch=malloc(chunk_len));
443 }
444
445 len = fread(&ch[0], 1, chunk_len, f);
446 if (ofs + len > (int64_t)p_filesz)
447 len = p_filesz - ofs;
448
449 while (i < len) {
450 size_t len_to_copy;
451 len_to_copy = (i + align_len) <= len?
452 align_len : len - i;
453 m->cpus[0]->memory_rw(m->cpus[0], mem,
454 p_vaddr + ofs, &ch[i], len_to_copy,
455 MEM_WRITE, NO_EXCEPTIONS);
456 ofs += align_len;
457 i += align_len;
458 }
459
460 free(ch);
461 }
462 }
463 }
464
465 /*
466 * Read the section headers to find the address of the _gp
467 * symbol (for MIPS):
468 */
469
470 for (i=0; i<eshnum; i++) {
471 int sh_name, sh_type, sh_flags, sh_link, sh_info, sh_entsize;
472 uint64_t sh_addr, sh_size, sh_addralign;
473 off_t sh_offset;
474 int n_entries; /* for reading the symbol / string tables */
475
476 /* debug("section header %i at %016"PRIx64"\n", i,
477 (uint64_t) eshoff+i*eshentsize); */
478
479 fseek(f, eshoff + i * eshentsize, SEEK_SET);
480
481 if (elf64) {
482 len = fread(&shdr64, 1, sizeof(Elf64_Shdr), f);
483 if (len != sizeof(Elf64_Shdr)) {
484 fprintf(stderr, "couldn't read header\n");
485 exit(1);
486 }
487 unencode(sh_name, &shdr64.sh_name, Elf64_Half);
488 unencode(sh_type, &shdr64.sh_type, Elf64_Half);
489 unencode(sh_flags, &shdr64.sh_flags, Elf64_Xword);
490 unencode(sh_addr, &shdr64.sh_addr, Elf64_Addr);
491 unencode(sh_offset, &shdr64.sh_offset, Elf64_Off);
492 unencode(sh_size, &shdr64.sh_size, Elf64_Xword);
493 unencode(sh_link, &shdr64.sh_link, Elf64_Half);
494 unencode(sh_info, &shdr64.sh_info, Elf64_Half);
495 unencode(sh_addralign, &shdr64.sh_addralign,
496 Elf64_Xword);
497 unencode(sh_entsize, &shdr64.sh_entsize, Elf64_Xword);
498 } else {
499 len = fread(&shdr32, 1, sizeof(Elf32_Shdr), f);
500 if (len != sizeof(Elf32_Shdr)) {
501 fprintf(stderr, "couldn't read header\n");
502 exit(1);
503 }
504 unencode(sh_name, &shdr32.sh_name, Elf32_Word);
505 unencode(sh_type, &shdr32.sh_type, Elf32_Word);
506 unencode(sh_flags, &shdr32.sh_flags, Elf32_Word);
507 unencode(sh_addr, &shdr32.sh_addr, Elf32_Addr);
508 unencode(sh_offset, &shdr32.sh_offset, Elf32_Off);
509 unencode(sh_size, &shdr32.sh_size, Elf32_Word);
510 unencode(sh_link, &shdr32.sh_link, Elf32_Word);
511 unencode(sh_info, &shdr32.sh_info, Elf32_Word);
512 unencode(sh_addralign, &shdr32.sh_addralign,Elf32_Word);
513 unencode(sh_entsize, &shdr32.sh_entsize, Elf32_Word);
514 }
515
516 /* debug("sh_name=%04lx, sh_type=%08lx, sh_flags=%08lx"
517 " sh_size=%06lx sh_entsize=%03lx\n",
518 (long)sh_name, (long)sh_type, (long)sh_flags,
519 (long)sh_size, (long)sh_entsize); */
520
521 /* Perhaps it is bad to reuse sh_entsize like this? TODO */
522 if (elf64)
523 sh_entsize = sizeof(Elf64_Sym);
524 else
525 sh_entsize = sizeof(Elf32_Sym);
526
527 if (sh_type == SHT_SYMTAB) {
528 size_t len;
529 n_entries = sh_size / sh_entsize;
530
531 fseek(f, sh_offset, SEEK_SET);
532
533 if (elf64) {
534 if (symbols_sym64 != NULL)
535 free(symbols_sym64);
536
537 CHECK_ALLOCATION(symbols_sym64 =
538 malloc(sh_size));
539
540 len = fread(symbols_sym64, 1, sh_entsize *
541 n_entries, f);
542 } else {
543 if (symbols_sym32 != NULL)
544 free(symbols_sym32);
545
546 CHECK_ALLOCATION(symbols_sym32 =
547 malloc(sh_size));
548
549 len = fread(symbols_sym32, 1,
550 sh_entsize * n_entries, f);
551 }
552
553 if (len != sh_size) {
554 fprintf(stderr, "could not read symbols from "
555 "%s\n", filename);
556 exit(1);
557 }
558
559 debug("%i symbol entries at 0x%"PRIx64"\n",
560 (int) n_entries, (uint64_t) sh_offset);
561
562 n_symbols = n_entries;
563 }
564
565 /*
566 * TODO: This is incorrect, there may be several strtab
567 * sections.
568 *
569 * For now, the simple/stupid guess that the largest string
570 * table is the one to use seems to be good enough.
571 */
572
573 if (sh_type == SHT_STRTAB && sh_size > symbol_length) {
574 size_t len;
575
576 if (symbol_strings != NULL)
577 free(symbol_strings);
578
579 CHECK_ALLOCATION(symbol_strings = malloc(sh_size + 1));
580
581 fseek(f, sh_offset, SEEK_SET);
582 len = fread(symbol_strings, 1, sh_size, f);
583 if (len != sh_size) {
584 fprintf(stderr, "could not read symbols from "
585 "%s\n", filename);
586 exit(1);
587 }
588
589 debug("%i bytes of symbol strings at 0x%"PRIx64"\n",
590 (int) sh_size, (uint64_t) sh_offset);
591
592 symbol_strings[sh_size] = '\0';
593 symbol_length = sh_size;
594 }
595 }
596
597 fclose(f);
598
599 /* Decode symbols: */
600 if (symbol_strings != NULL) {
601 for (i=0; i<n_symbols; i++) {
602 uint64_t st_name, addr, size;
603 int st_info;
604
605 if (elf64) {
606 sym64 = symbols_sym64[i];
607 unencode(st_name, &sym64.st_name, Elf64_Half);
608 unencode(st_info, &sym64.st_info, Elf_Byte);
609 unencode(addr, &sym64.st_value, Elf64_Addr);
610 unencode(size, &sym64.st_size, Elf64_Xword);
611 } else {
612 sym32 = symbols_sym32[i];
613 unencode(st_name, &sym32.st_name, Elf32_Word);
614 unencode(st_info, &sym32.st_info, Elf_Byte);
615 unencode(addr, &sym32.st_value, Elf32_Word);
616 unencode(size, &sym32.st_size, Elf32_Word);
617 }
618
619 /* debug("symbol info=0x%02x addr=0x%016"PRIx64
620 " (%i) '%s'\n", st_info, (uint64_t) addr,
621 st_name, symbol_strings + st_name); */
622
623 if (size == 0)
624 size ++;
625
626 if (addr != 0) /* && ((st_info >> 4) & 0xf)
627 >= STB_GLOBAL) */ {
628 /* debug("symbol info=0x%02x addr=0x%016"PRIx64
629 " '%s'\n", st_info, (uint64_t) addr,
630 symbol_strings + st_name); */
631 add_symbol_name(&m->symbol_context,
632 addr, size, symbol_strings + st_name,
633 0, -1);
634 }
635
636 if (strcmp(symbol_strings + st_name, "_gp") == 0) {
637 debug("found _gp address: 0x");
638 if (elf64)
639 debug("%016"PRIx64"\n", (uint64_t)addr);
640 else
641 debug("%08"PRIx32"\n", (uint32_t)addr);
642 *gpp = addr;
643 }
644 }
645 }
646
647 *entrypointp = eentry;
648
649 if (encoding == ELFDATA2LSB)
650 *byte_order = EMUL_LITTLE_ENDIAN;
651 else
652 *byte_order = EMUL_BIG_ENDIAN;
653
654 if (elf64 && arch == ARCH_PPC) {
655 /*
656 * Special case for 64-bit PPC ELFs:
657 *
658 * The ELF starting symbol points to a ".opd" section
659 * which contains a function descriptor:
660 *
661 * uint64_t start;
662 * uint64_t toc_base;
663 * uint64_t something_else; (?)
664 */
665 int res;
666 unsigned char b[sizeof(uint64_t)];
667 uint64_t toc_base;
668
669 debug("PPC64: ");
670
671 res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry, b,
672 sizeof(b), MEM_READ, NO_EXCEPTIONS);
673 if (!res)
674 debug(" [WARNING: could not read memory?] ");
675
676 /* PPC are always big-endian: */
677 *entrypointp = ((uint64_t)b[0] << 56) +
678 ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) +
679 ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) +
680 ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) +
681 (uint64_t)b[7];
682
683 res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry + 8,
684 b, sizeof(b), MEM_READ, NO_EXCEPTIONS);
685 if (!res)
686 fatal(" [WARNING: could not read memory?] ");
687
688 toc_base = ((uint64_t)b[0] << 56) +
689 ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) +
690 ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) +
691 ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) +
692 (uint64_t)b[7];
693
694 debug("entrypoint 0x%016"PRIx64", toc_base 0x%016"PRIx64"\n",
695 (uint64_t) *entrypointp, (uint64_t) toc_base);
696 if (tocp != NULL)
697 *tocp = toc_base;
698 }
699
700 n_executables_loaded ++;
701 }
702

  ViewVC Help
Powered by ViewVC 1.1.26