file.cc Source File

Back to the index.

file.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2009 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  * This module contains functions which load executable images into (emulated)
29  * memory. File formats recognized so far are:
30  *
31  * a.out traditional old-style Unix binary format
32  * Mach-O MacOS X format, etc.
33  * ecoff old format used by Ultrix, Windows NT, etc
34  * srec Motorola SREC format
35  * raw raw binaries, "address:[skiplen:[entrypoint:]]filename"
36  * ELF 32-bit and 64-bit ELFs
37  *
38  * If a file is not of one of the above mentioned formats, it is assumed
39  * to be symbol data generated by 'nm' or 'nm -S'.
40  */
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/types.h>
46 
47 #include "cpu.h"
48 #include "machine.h"
49 #include "memory.h"
50 #include "misc.h"
51 #include "symbol.h"
52 
53 
54 extern int quiet_mode;
55 extern int verbose;
56 
57 
58 /*
59  * This should be increased by every routine here that actually loads an
60  * executable file into memory. (For example, loading a symbol file should
61  * NOT increase this.)
62  */
63 static int n_executables_loaded = 0;
64 
65 
66 #include "thirdparty/exec_elf.h" /* Ugly; needed for ELFDATA2LSB etc. */
67 
68 #define unencode(var,dataptr,typ) { \
69  int Wi; unsigned char Wb; \
70  unsigned char *Wp = (unsigned char *) dataptr; \
71  int Wlen = sizeof(typ); \
72  var = 0; \
73  for (Wi=0; Wi<Wlen; Wi++) { \
74  if (encoding == ELFDATA2LSB) \
75  Wb = Wp[Wlen-1 - Wi]; \
76  else \
77  Wb = Wp[Wi]; \
78  if (Wi == 0 && (Wb & 0x80)) { \
79  var --; /* set var to -1 :-) */ \
80  var <<= 8; \
81  } \
82  var |= Wb; \
83  if (Wi < Wlen-1) \
84  var <<= 8; \
85  } \
86  }
87 
88 
89 #include "file_aout.cc"
90 #include "file_ecoff.cc"
91 #include "file_elf.cc"
92 #include "file_macho.cc"
93 #include "file_raw.cc"
94 #include "file_srec.cc"
95 
96 
97 /*
98  * file_n_executables_loaded():
99  *
100  * Returns the number of executable files loaded into emulated memory.
101  */
103 {
104  return n_executables_loaded;
105 }
106 
107 
108 /*
109  * file_load():
110  *
111  * Sense the file format of a file (ELF, a.out, ecoff), and call the
112  * right file_load_XXX() function. If the file isn't of a recognized
113  * binary format, assume that it contains symbol definitions.
114  *
115  * If the filename doesn't exist, try to treat the name as
116  * "address:filename" and load the file as a raw binary.
117  */
118 void file_load(struct machine *machine, struct memory *mem,
119  char *filename, uint64_t *entrypointp,
120  int arch, uint64_t *gpp, int *byte_orderp, uint64_t *tocp)
121 {
122  int iadd = DEBUG_INDENTATION, old_quiet_mode;
123  FILE *f;
124  const char *tmpdir = getenv("TMPDIR") == NULL?
125  DEFAULT_TMP_DIR : getenv("TMPDIR");
126  unsigned char buf[12];
127  unsigned char buf2[2];
128  char tmpname[400];
129  size_t len, len2, i;
130  off_t size;
131 
132  if (byte_orderp == NULL) {
133  fprintf(stderr, "file_load(): byte_order == NULL\n");
134  exit(1);
135  }
136 
137  if (arch == ARCH_NOARCH) {
138  fprintf(stderr, "file_load(): FATAL ERROR: no arch?\n");
139  exit(1);
140  }
141 
142  if (mem == NULL || filename == NULL) {
143  fprintf(stderr, "file_load(): mem or filename is NULL\n");
144  exit(1);
145  }
146 
147  /* Skip configuration files: */
148  if (filename[0] == '@')
149  return;
150 
151  debug("loading %s%s\n", filename, verbose >= 2? ":" : "");
152  debug_indentation(iadd);
153 
154  old_quiet_mode = quiet_mode;
155  if (verbose < 2)
156  quiet_mode = 1;
157 
158  f = fopen(filename, "r");
159  if (f == NULL) {
160  file_load_raw(machine, mem, filename, entrypointp);
161  goto ret;
162  }
163 
164  fseek(f, 0, SEEK_END);
165  size = ftello(f);
166  fseek(f, 0, SEEK_SET);
167 
168  memset(buf, 0, sizeof(buf));
169  len = fread(buf, 1, sizeof(buf), f);
170  fseek(f, 510, SEEK_SET);
171  len2 = fread(buf2, 1, sizeof(buf2), f);
172  fclose(f);
173 
174  if (len < (signed int)sizeof(buf)) {
175  fprintf(stderr, "\nThis file is too small to contain "
176  "anything useful\n");
177  exit(1);
178  }
179 
180  /* Is it an ELF? */
181  if (buf[0] == 0x7f && buf[1]=='E' && buf[2]=='L' && buf[3]=='F') {
182  file_load_elf(machine, mem, filename,
183  entrypointp, arch, gpp, byte_orderp, tocp);
184  goto ret;
185  }
186 
187  /* Is it an a.out? */
188  if (buf[0]==0x00 && buf[1]==0x8b && buf[2]==0x01 && buf[3]==0x07) {
189  /* MIPS a.out */
190  file_load_aout(machine, mem, filename, 0,
191  entrypointp, arch, byte_orderp);
192  goto ret;
193  }
194  if (buf[0]==0x00 && buf[1]==0x87 && buf[2]==0x01 && buf[3]==0x08) {
195  /* M68K a.out */
196  file_load_aout(machine, mem, filename,
197  AOUT_FLAG_VADDR_ZERO_HACK /* for OpenBSD/mac68k */,
198  entrypointp, arch, byte_orderp);
199  goto ret;
200  }
201  if (buf[0]==0x00 && buf[1]==0x99 && buf[2]==0x01 && buf[3]==0x0b) {
202  /* OpenBSD/M88K a.out */
203  file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING,
204  entrypointp, arch, byte_orderp);
205  goto ret;
206  }
207  if (buf[0]==0x00 && buf[1]==0x8f && buf[2]==0x01 && buf[3]==0x0b) {
208  /* ARM a.out */
209  file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING,
210  entrypointp, arch, byte_orderp);
211  goto ret;
212  }
213  if (buf[0]==0x00 && buf[1]==0x86 && buf[2]==0x01 && buf[3]==0x0b) {
214  /* i386 a.out (old OpenBSD and NetBSD etc) */
215  file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING,
216  entrypointp, arch, byte_orderp);
217  goto ret;
218  }
219  if (buf[0]==0x01 && buf[1]==0x03 && buf[2]==0x01 && buf[3]==0x07) {
220  /* SPARC a.out (old 32-bit NetBSD etc) */
221  file_load_aout(machine, mem, filename, AOUT_FLAG_NO_SIZES,
222  entrypointp, arch, byte_orderp);
223  goto ret;
224  }
225  if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) {
226  /* DEC OSF1 on MIPS: */
227  file_load_aout(machine, mem, filename, AOUT_FLAG_DECOSF1,
228  entrypointp, arch, byte_orderp);
229  goto ret;
230  }
231 
232  /*
233  * Is it a Mach-O file?
234  */
235  if (buf[0] == 0xfe && buf[1] == 0xed && buf[2] == 0xfa &&
236  (buf[3] == 0xce || buf[3] == 0xcf)) {
237  file_load_macho(machine, mem, filename, entrypointp,
238  arch, byte_orderp, buf[3] == 0xcf, 0);
239  goto ret;
240  }
241  if ((buf[0] == 0xce || buf[0] == 0xcf) && buf[1] == 0xfa &&
242  buf[2] == 0xed && buf[3] == 0xfe) {
243  file_load_macho(machine, mem, filename, entrypointp,
244  arch, byte_orderp, buf[0] == 0xcf, 1);
245  goto ret;
246  }
247 
248  /*
249  * Is it an ecoff?
250  *
251  * TODO: What's the deal with the magic value's byte order? Sometimes
252  * it seems to be reversed for BE when compared to LE, but not always?
253  */
254  if (buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEB ||
255  buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEL ||
256  buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEB2 ||
257  buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEL2 ||
258  buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEB3 ||
259  buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEL3 ||
260  buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEB ||
261  buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEL ||
262  buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEB2 ||
263  buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEL2 ||
264  buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEB3 ||
265  buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEL3) {
266  file_load_ecoff(machine, mem, filename, entrypointp,
267  arch, gpp, byte_orderp);
268  goto ret;
269  }
270 
271  /* Is it a Motorola SREC file? */
272  if ((buf[0]=='S' && buf[1]>='0' && buf[1]<='9')) {
273  file_load_srec(machine, mem, filename, entrypointp);
274  goto ret;
275  }
276 
277  /* gzipped files are not supported: */
278  if (buf[0]==0x1f && buf[1]==0x8b) {
279  fprintf(stderr, "\nYou need to gunzip the file before you"
280  " try to use it.\n");
281  exit(1);
282  }
283 
284  if (size > 24000000) {
285  fprintf(stderr, "\nThis file is very large (%lli bytes)\n",
286  (long long)size);
287  fprintf(stderr, "Are you sure it is a kernel and not a disk "
288  "image? (Use the -d option.)\n");
289  exit(1);
290  }
291 
292  if (size == 1474560)
293  fprintf(stderr, "Hm... this file is the size of a 1.44 MB "
294  "floppy image. Maybe you forgot the\n-d switch?\n");
295 
296  /*
297  * Ugly hack for Dreamcast: When booting from a Dreamcast CDROM
298  * image, a temporary file is extracted into /tmp/gxemul.*, but this
299  * is a "scrambled" raw binary. This code unscrambles it, and loads
300  * it as a raw binary.
301  */
302  snprintf(tmpname, sizeof(tmpname), "%s/gxemul.", tmpdir);
303  if (machine->machine_type == MACHINE_DREAMCAST &&
304  strncmp(filename, tmpname, strlen(tmpname)) == 0) {
305  char *tmp_filename = (char *) malloc(strlen(filename) + 100);
306  snprintf(tmp_filename, strlen(filename) + 100,
307  "%s.descrambled", filename);
308  debug("descrambling into %s\n", tmp_filename);
309  dreamcast_descramble(filename, tmp_filename);
310 
311  snprintf(tmp_filename, strlen(filename) + 100,
312  "0x8c010000:%s.descrambled", filename);
313  debug("loading descrambled Dreamcast binary\n");
314  file_load_raw(machine, mem, tmp_filename, entrypointp);
315 
316  snprintf(tmp_filename, strlen(filename) + 100,
317  "%s.descrambled", filename);
318  remove(tmp_filename);
319  free(tmp_filename);
320 
321  /* Hack: Start a "boot from CDROM" sequence: */
322  *entrypointp = 0x8c000140;
323  goto ret;
324  }
325 
326  /*
327  * Last resort: symbol definitions from nm (or nm -S):
328  *
329  * If the buf contains typical 'binary' characters, then print
330  * an error message and quit instead of assuming that it is a
331  * symbol file.
332  */
333  for (i=0; i<(signed)sizeof(buf); i++)
334  if (buf[i] < 32 && buf[i] != '\t' &&
335  buf[i] != '\n' && buf[i] != '\r' &&
336  buf[i] != '\f') {
337  fprintf(stderr, "\nThe file format of '%s' is "
338  "unknown.\n\n ", filename);
339  for (i=0; i<(signed)sizeof(buf); i++)
340  fprintf(stderr, " %02x", buf[i]);
341 
342  if (len2 == 2 && buf2[0] == 0x55 && buf2[1] == 0xaa)
343  fprintf(stderr, "\n\nIt has a PC-style "
344  "bootsector marker.");
345 
346  fprintf(stderr, "\n\nPossible explanations:\n\n"
347  " o) If this is a disk image, you forgot '-d' "
348  "on the command line.\n"
349  " o) You are attempting to load a raw binary "
350  "into emulated memory,\n"
351  " but forgot to add the address prefix.\n"
352  " o) This is an unsupported binary format.\n\n");
353  exit(1);
354  }
355 
356  symbol_readfile(&machine->symbol_context, filename);
357 
358 ret:
359  debug_indentation(-iadd);
361 }
362 
#define ECOFF_MAGIC_MIPSEB2
#define AOUT_FLAG_NO_SIZES
Definition: file_aout.cc:40
#define DEBUG_INDENTATION
Definition: misc.h:212
#define AOUT_FLAG_DECOSF1
Definition: file_aout.cc:37
int old_quiet_mode
Definition: debugger.cc:76
void file_load(struct machine *machine, struct memory *mem, char *filename, uint64_t *entrypointp, int arch, uint64_t *gpp, int *byte_orderp, uint64_t *tocp)
Definition: file.cc:118
int machine_type
Definition: machine.h:111
void f(int s, int func, int only_name)
void symbol_readfile(struct symbol_context *, char *fname)
Definition: symbol.cc:284
#define ECOFF_MAGIC_MIPSEB
#define ARCH_NOARCH
Definition: machine.h:202
#define ECOFF_MAGIC_MIPSEL
#define AOUT_FLAG_VADDR_ZERO_HACK
Definition: file_aout.cc:39
#define ECOFF_MAGIC_MIPSEL2
#define DEFAULT_TMP_DIR
Definition: misc.h:148
int file_n_executables_loaded(void)
Definition: file.cc:102
int verbose
Definition: main.cc:77
#define AOUT_FLAG_FROM_BEGINNING
Definition: file_aout.cc:38
#define MACHINE_DREAMCAST
Definition: machine.h:252
#define debug
Definition: dev_adb.cc:57
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
#define ECOFF_MAGIC_MIPSEL3
void debug_indentation(int diff)
Definition: main.cc:120
struct symbol_context symbol_context
Definition: machine.h:144
#define ECOFF_MAGIC_MIPSEB3
int quiet_mode
Definition: main.cc:78
Definition: memory.h:75
void dreamcast_descramble(char *from, char *to)

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13