/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 7 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 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 42 * $Id: file_elf.c,v 1.5 2007/06/15 17:02:39 debug Exp $
29 dpavlin 38 *
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 dpavlin 42 /* case ARCH_AVR:
219 dpavlin 38 switch (emachine) {
220     case EM_AVR:
221     ok = 1;
222     }
223     break;
224 dpavlin 42 case ARCH_AVR32:
225 dpavlin 38 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 dpavlin 40 /* case ARCH_M68K:
249 dpavlin 38 switch (emachine) {
250     case EM_68K:
251     ok = 1;
252     }
253 dpavlin 40 break; */
254 dpavlin 38 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 dpavlin 42 fatal("SH64: 32-bit instruction encoding: TODO\n");
324     /* m->cpus[0]->cd.sh.compact = 0; */
325 dpavlin 38 m->cpus[0]->cd.sh.cpu_type.bits = 64;
326 dpavlin 42 exit(1);
327 dpavlin 38 }
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 dpavlin 42 unsigned char *ch;
426 dpavlin 38 int i = 0;
427    
428 dpavlin 42 CHECK_ALLOCATION(ch = malloc(chunk_len));
429    
430 dpavlin 38 /* 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 dpavlin 42 CHECK_ALLOCATION(ch=malloc(chunk_len));
437 dpavlin 38 } 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 dpavlin 42 CHECK_ALLOCATION(ch=malloc(chunk_len));
443 dpavlin 38 }
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 dpavlin 42 CHECK_ALLOCATION(symbols_sym64 =
538     malloc(sh_size));
539    
540 dpavlin 38 len = fread(symbols_sym64, 1, sh_entsize *
541     n_entries, f);
542     } else {
543     if (symbols_sym32 != NULL)
544     free(symbols_sym32);
545    
546 dpavlin 42 CHECK_ALLOCATION(symbols_sym32 =
547     malloc(sh_size));
548    
549 dpavlin 38 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 dpavlin 42 CHECK_ALLOCATION(symbol_strings = malloc(sh_size + 1));
580 dpavlin 38
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