1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: file.c,v 1.116 2005/09/30 14:07:45 debug Exp $ |
* $Id: file.c,v 1.127 2006/01/22 23:20:33 debug Exp $ |
29 |
* |
* |
30 |
* This file contains functions which load executable images into (emulated) |
* This file contains functions which load executable images into (emulated) |
31 |
* memory. File formats recognized so far are: |
* memory. File formats recognized so far are: |
56 |
#include "symbol.h" |
#include "symbol.h" |
57 |
|
|
58 |
|
|
59 |
|
extern int quiet_mode; |
60 |
|
extern int verbose; |
61 |
|
|
62 |
|
|
63 |
/* ELF machine types as strings: (same as exec_elf.h) */ |
/* ELF machine types as strings: (same as exec_elf.h) */ |
64 |
#define N_ELF_MACHINE_TYPES 64 |
#define N_ELF_MACHINE_TYPES 64 |
65 |
static char *elf_machine_type[N_ELF_MACHINE_TYPES] = { |
static char *elf_machine_type[N_ELF_MACHINE_TYPES] = { |
131 |
#define AOUT_FLAG_DECOSF1 1 |
#define AOUT_FLAG_DECOSF1 1 |
132 |
#define AOUT_FLAG_FROM_BEGINNING 2 |
#define AOUT_FLAG_FROM_BEGINNING 2 |
133 |
#define AOUT_FLAG_VADDR_ZERO_HACK 4 |
#define AOUT_FLAG_VADDR_ZERO_HACK 4 |
134 |
|
#define AOUT_FLAG_NO_SIZES 8 |
135 |
/* |
/* |
136 |
* file_load_aout(): |
* file_load_aout(): |
137 |
* |
* |
167 |
if (flags & AOUT_FLAG_DECOSF1) { |
if (flags & AOUT_FLAG_DECOSF1) { |
168 |
fread(&buf, 1, 32, f); |
fread(&buf, 1, 32, f); |
169 |
vaddr = buf[16] + (buf[17] << 8) + |
vaddr = buf[16] + (buf[17] << 8) + |
170 |
(buf[18] << 16) + (buf[19] << 24); |
(buf[18] << 16) + ((uint64_t)buf[19] << 24); |
171 |
entry = buf[20] + (buf[21] << 8) + |
entry = buf[20] + (buf[21] << 8) + |
172 |
(buf[22] << 16) + (buf[23] << 24); |
(buf[22] << 16) + ((uint64_t)buf[23] << 24); |
173 |
debug("OSF1 a.out, load address 0x%08lx, " |
debug("OSF1 a.out, load address 0x%08lx, " |
174 |
"entry point 0x%08x\n", (long)vaddr, (long)entry); |
"entry point 0x%08x\n", (long)vaddr, (long)entry); |
175 |
symbsize = 0; |
symbsize = 0; |
178 |
textsize = ftello(f) - 512; |
textsize = ftello(f) - 512; |
179 |
datasize = 0; |
datasize = 0; |
180 |
fseek(f, 512, SEEK_SET); |
fseek(f, 512, SEEK_SET); |
181 |
|
} else if (flags & AOUT_FLAG_NO_SIZES) { |
182 |
|
fseek(f, 0, SEEK_END); |
183 |
|
textsize = ftello(f) - 32; |
184 |
|
datasize = 0; |
185 |
|
vaddr = entry = 0; |
186 |
|
fseek(f, 32, SEEK_SET); |
187 |
} else { |
} else { |
188 |
len = fread(&aout_header, 1, sizeof(aout_header), f); |
len = fread(&aout_header, 1, sizeof(aout_header), f); |
189 |
if (len != sizeof(aout_header)) { |
if (len != sizeof(aout_header)) { |
342 |
char *symbols, *strings; |
char *symbols, *strings; |
343 |
uint32_t cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; |
uint32_t cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; |
344 |
uint64_t vmaddr, vmsize, fileoff, filesize; |
uint64_t vmaddr, vmsize, fileoff, filesize; |
345 |
int cmd_type, cmd_len, pos, i, flavor; |
int cmd_type, cmd_len, i, flavor; |
346 |
int32_t symoff, nsyms, stroff, strsize; |
int32_t symoff, nsyms, stroff, strsize; |
347 |
size_t len; |
size_t len, pos; |
348 |
|
|
349 |
if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) |
if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) |
350 |
encoding = ELFDATA2MSB; |
encoding = ELFDATA2MSB; |
869 |
debug("%c", sym->name[i]); */ |
debug("%c", sym->name[i]); */ |
870 |
v = sym->value[0] + (sym->value[1] << 8) |
v = sym->value[0] + (sym->value[1] << 8) |
871 |
+ (sym->value[2] << 16) |
+ (sym->value[2] << 16) |
872 |
+ (sym->value[3] << 24); |
+ ((uint64_t)sym->value[3] << 24); |
873 |
altname = sym->name[4] + (sym->name[5] << 8) |
altname = sym->name[4] + (sym->name[5] << 8) |
874 |
+ (sym->name[6] << 16) |
+ (sym->name[6] << 16) |
875 |
+ (sym->name[3] << 24); |
+ ((uint64_t)sym->name[3] << 24); |
876 |
t = (sym->type[1] << 8) + sym->type[0]; |
t = (sym->type[1] << 8) + sym->type[0]; |
877 |
/* TODO: big endian COFF? */ |
/* TODO: big endian COFF? */ |
878 |
/* debug("' value=0x%x type=0x%04x", v, t); */ |
/* debug("' value=0x%x type=0x%04x", v, t); */ |
1103 |
bytes[2]; |
bytes[2]; |
1104 |
break; |
break; |
1105 |
case 3: data_start = 4; |
case 3: data_start = 4; |
1106 |
vaddr = (bytes[0] << 24) + (bytes[1] << 16) + |
vaddr = ((uint64_t)bytes[0] << 24) + |
1107 |
(bytes[2] << 8) + bytes[3]; |
(bytes[1] << 16) + (bytes[2]<<8) + bytes[3]; |
1108 |
} |
} |
1109 |
m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, |
m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, |
1110 |
&bytes[data_start], count - 1 - data_start, |
&bytes[data_start], count - 1 - data_start, |
1116 |
case 9: |
case 9: |
1117 |
/* switch again, to get the entry point: */ |
/* switch again, to get the entry point: */ |
1118 |
switch (buf[1]) { |
switch (buf[1]) { |
1119 |
case 7: entry = (bytes[0] << 24) + (bytes[1] << 16) + |
case 7: entry = ((uint64_t)bytes[0] << 24) + |
1120 |
(bytes[2] << 8) + bytes[3]; |
(bytes[1] << 16) + (bytes[2]<<8) + bytes[3]; |
1121 |
break; |
break; |
1122 |
case 8: entry = (bytes[0] << 16) + (bytes[1] << 8) + |
case 8: entry = (bytes[0] << 16) + (bytes[1] << 8) + |
1123 |
bytes[2]; |
bytes[2]; |
1538 |
unencode(p_align, &phdr32.p_align, Elf32_Word); |
unencode(p_align, &phdr32.p_align, Elf32_Word); |
1539 |
} |
} |
1540 |
|
|
1541 |
|
/* |
1542 |
|
* Hack for loading Linux/PPC kernels, linked to high |
1543 |
|
* addresses, at low addresses. |
1544 |
|
*/ |
1545 |
|
if (arch == ARCH_PPC) { |
1546 |
|
if (elf64) { |
1547 |
|
p_vaddr &= 0x0fffffffffffffffULL; |
1548 |
|
p_paddr &= 0x0fffffffffffffffULL; |
1549 |
|
} else { |
1550 |
|
p_vaddr &= 0x0fffffff; |
1551 |
|
p_paddr &= 0x0fffffff; |
1552 |
|
} |
1553 |
|
} |
1554 |
|
|
1555 |
if (p_memsz != 0 && (p_type == PT_LOAD || |
if (p_memsz != 0 && (p_type == PT_LOAD || |
1556 |
(p_type & PF_MASKPROC) == PT_MIPS_REGINFO)) { |
(p_type & PF_MASKPROC) == PT_MIPS_REGINFO)) { |
1557 |
debug("chunk %i (", i); |
debug("chunk %i (", i); |
1569 |
|
|
1570 |
debug(" len=0x%llx\n", (long long)p_memsz); |
debug(" len=0x%llx\n", (long long)p_memsz); |
1571 |
|
|
1572 |
if (p_vaddr != p_paddr) |
if (p_vaddr != p_paddr) { |
1573 |
fatal("WARNING! vaddr (0x%llx) and paddr " |
if (elf64) |
1574 |
"(0x%llx) differ; using vaddr\n", |
fatal("NOTE: vaddr (0x%llx) and " |
1575 |
(long long)p_vaddr, (long long)p_paddr); |
"paddr (0x%llx) differ; using " |
1576 |
|
"vaddr\n", (long long)p_vaddr, |
1577 |
|
(long long)p_paddr); |
1578 |
|
else |
1579 |
|
fatal("NOTE: vaddr (0x%08x) and " |
1580 |
|
"paddr (0x%08x) differ; using vaddr" |
1581 |
|
"\n", (int)p_vaddr, (int)p_paddr); |
1582 |
|
} |
1583 |
|
|
1584 |
if (p_memsz < p_filesz) { |
if (p_memsz < p_filesz) { |
1585 |
fprintf(stderr, "%s: memsz < filesz. TODO: how" |
fprintf(stderr, "%s: memsz < filesz. TODO: how" |
1799 |
} else { |
} else { |
1800 |
sym32 = symbols_sym32[i]; |
sym32 = symbols_sym32[i]; |
1801 |
unencode(st_name, &sym32.st_name, Elf32_Word); |
unencode(st_name, &sym32.st_name, Elf32_Word); |
1802 |
unencode(st_info, &sym64.st_info, Elf_Byte); |
unencode(st_info, &sym32.st_info, Elf_Byte); |
1803 |
unencode(addr, &sym32.st_value, Elf32_Word); |
unencode(addr, &sym32.st_value, Elf32_Word); |
1804 |
unencode(size, &sym32.st_size, Elf32_Word); |
unencode(size, &sym32.st_size, Elf32_Word); |
1805 |
} |
} |
1914 |
char *filename, uint64_t *entrypointp, |
char *filename, uint64_t *entrypointp, |
1915 |
int arch, uint64_t *gpp, int *byte_orderp, uint64_t *tocp) |
int arch, uint64_t *gpp, int *byte_orderp, uint64_t *tocp) |
1916 |
{ |
{ |
1917 |
int iadd = 4; |
int iadd = DEBUG_INDENTATION, old_quiet_mode; |
1918 |
FILE *f; |
FILE *f; |
1919 |
unsigned char buf[12]; |
unsigned char buf[12]; |
1920 |
unsigned char buf2[2]; |
unsigned char buf2[2]; |
1940 |
if (filename[0] == '@') |
if (filename[0] == '@') |
1941 |
return; |
return; |
1942 |
|
|
1943 |
debug("loading %s:\n", filename); |
debug("loading %s%s\n", filename, verbose >= 2? ":" : ""); |
1944 |
debug_indentation(iadd); |
debug_indentation(iadd); |
1945 |
|
|
1946 |
|
old_quiet_mode = quiet_mode; |
1947 |
|
if (verbose < 2) |
1948 |
|
quiet_mode = 1; |
1949 |
|
|
1950 |
f = fopen(filename, "r"); |
f = fopen(filename, "r"); |
1951 |
if (f == NULL) { |
if (f == NULL) { |
1952 |
file_load_raw(machine, mem, filename, entrypointp); |
file_load_raw(machine, mem, filename, entrypointp); |
2002 |
entrypointp, arch, byte_orderp); |
entrypointp, arch, byte_orderp); |
2003 |
goto ret; |
goto ret; |
2004 |
} |
} |
2005 |
|
if (buf[0]==0x01 && buf[1]==0x03 && buf[2]==0x01 && buf[3]==0x07) { |
2006 |
|
/* SPARC a.out (old 32-bit NetBSD etc) */ |
2007 |
|
file_load_aout(machine, mem, filename, AOUT_FLAG_NO_SIZES, |
2008 |
|
entrypointp, arch, byte_orderp); |
2009 |
|
goto ret; |
2010 |
|
} |
2011 |
if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { |
if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { |
2012 |
/* DEC OSF1 on MIPS: */ |
/* DEC OSF1 on MIPS: */ |
2013 |
file_load_aout(machine, mem, filename, AOUT_FLAG_DECOSF1, |
file_load_aout(machine, mem, filename, AOUT_FLAG_DECOSF1, |
2110 |
|
|
2111 |
ret: |
ret: |
2112 |
debug_indentation(-iadd); |
debug_indentation(-iadd); |
2113 |
|
quiet_mode = old_quiet_mode; |
2114 |
} |
} |
2115 |
|
|