25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: file.c,v 1.105 2005/08/11 16:11:33 debug Exp $ |
* $Id: file.c,v 1.116 2005/09/30 14:07:45 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: |
* memory. File formats recognized so far are: |
32 |
* |
* |
|
* ELF 32-bit and 64-bit ELFs |
|
33 |
* a.out old format used by OpenBSD 2.x pmax kernels |
* a.out old format used by OpenBSD 2.x pmax kernels |
34 |
|
* Mach-O MacOS X format, etc. |
35 |
* ecoff old format used by Ultrix, Windows NT, etc |
* ecoff old format used by Ultrix, Windows NT, etc |
36 |
* srec Motorola SREC format |
* srec Motorola SREC format |
37 |
* raw raw binaries, "address:[skiplen:[entrypoint:]]filename" |
* raw raw binaries, "address:[skiplen:[entrypoint:]]filename" |
38 |
|
* ELF 32-bit and 64-bit ELFs |
39 |
* |
* |
40 |
* If a file is not of one of the above mentioned formats, it is assumed |
* If a file is not of one of the above mentioned formats, it is assumed |
41 |
* to be symbol data generated by 'nm' or 'nm -S'. |
* to be symbol data generated by 'nm' or 'nm -S'. |
207 |
len = fread(buf, 1, len, f); |
len = fread(buf, 1, len, f); |
208 |
|
|
209 |
/* printf("fread len=%i vaddr=%x buf[0..]=%02x %02x %02x\n", |
/* printf("fread len=%i vaddr=%x buf[0..]=%02x %02x %02x\n", |
210 |
len, (int)vaddr, buf[0], buf[1], buf[2]); */ |
(int)len, (int)vaddr, buf[0], buf[1], buf[2]); */ |
211 |
|
|
212 |
if (len > 0) { |
if (len > 0) { |
213 |
int len2 = 0; |
int len2 = 0; |
305 |
|
|
306 |
|
|
307 |
/* |
/* |
308 |
|
* file_load_macho(): |
309 |
|
* |
310 |
|
* Loads a Mach-O binary image into the emulated memory. The entry point |
311 |
|
* is stored in the specified CPU's registers. |
312 |
|
* |
313 |
|
* TODO: |
314 |
|
* |
315 |
|
* o) Almost everything. |
316 |
|
* |
317 |
|
* o) I haven't had time to look into whether Apple's open source |
318 |
|
* license is BSD-compatible or not. Perhaps it would be possible |
319 |
|
* to use a header file containing symbolic names, and not use |
320 |
|
* hardcoded values. |
321 |
|
*/ |
322 |
|
static void file_load_macho(struct machine *m, struct memory *mem, |
323 |
|
char *filename, uint64_t *entrypointp, int arch, int *byte_orderp, |
324 |
|
int is_64bit, int is_reversed) |
325 |
|
{ |
326 |
|
FILE *f; |
327 |
|
uint64_t entry = 0; |
328 |
|
int entry_set = 0; |
329 |
|
int encoding = ELFDATA2MSB; |
330 |
|
unsigned char buf[65536]; |
331 |
|
char *symbols, *strings; |
332 |
|
uint32_t cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; |
333 |
|
uint64_t vmaddr, vmsize, fileoff, filesize; |
334 |
|
int cmd_type, cmd_len, pos, i, flavor; |
335 |
|
int32_t symoff, nsyms, stroff, strsize; |
336 |
|
size_t len; |
337 |
|
|
338 |
|
if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) |
339 |
|
encoding = ELFDATA2MSB; |
340 |
|
|
341 |
|
f = fopen(filename, "r"); |
342 |
|
if (f == NULL) { |
343 |
|
perror(filename); |
344 |
|
exit(1); |
345 |
|
} |
346 |
|
|
347 |
|
if (is_64bit) { |
348 |
|
fatal("TODO: 64-bit Mach-O. Not supported yet.\n"); |
349 |
|
exit(1); |
350 |
|
} |
351 |
|
if (is_reversed) { |
352 |
|
fatal("TODO: Reversed-endianness. Not supported yet.\n"); |
353 |
|
exit(1); |
354 |
|
} |
355 |
|
|
356 |
|
len = fread(buf, 1, sizeof(buf), f); |
357 |
|
if (len < 100) { |
358 |
|
fatal("Bad Mach-O file?\n"); |
359 |
|
exit(1); |
360 |
|
} |
361 |
|
|
362 |
|
unencode(cputype, &buf[4], uint32_t); |
363 |
|
unencode(cpusubtype, &buf[8], uint32_t); |
364 |
|
unencode(filetype, &buf[12], uint32_t); |
365 |
|
unencode(ncmds, &buf[16], uint32_t); |
366 |
|
unencode(sizeofcmds, &buf[20], uint32_t); |
367 |
|
unencode(flags, &buf[24], uint32_t); |
368 |
|
|
369 |
|
/* debug("cputype=0x%x cpusubtype=0x%x filetype=0x%x\n", |
370 |
|
cputype, cpusubtype, filetype); |
371 |
|
debug("ncmds=%i sizeofcmds=0x%08x flags=0x%08x\n", |
372 |
|
ncmds, sizeofcmds, flags); */ |
373 |
|
|
374 |
|
/* |
375 |
|
* Compare to "normal" values. |
376 |
|
* NOTE/TODO: These were for a Darwin (Macintosh PPC) kernel. |
377 |
|
*/ |
378 |
|
if (cputype != 0x12) { |
379 |
|
fatal("Error: Unimplemented cputype 0x%x\n", cputype); |
380 |
|
exit(1); |
381 |
|
} |
382 |
|
if (cpusubtype != 0) { |
383 |
|
fatal("Error: Unimplemented cpusubtype 0x%x\n", cpusubtype); |
384 |
|
exit(1); |
385 |
|
} |
386 |
|
/* Filetype 2 means an executable image. */ |
387 |
|
if (filetype != 2) { |
388 |
|
fatal("Error: Unimplemented filetype 0x%x\n", filetype); |
389 |
|
exit(1); |
390 |
|
} |
391 |
|
if (!(flags & 1)) { |
392 |
|
fatal("Error: File has 'undefined references'. Cannot" |
393 |
|
" be executed.\n", flags); |
394 |
|
exit(1); |
395 |
|
} |
396 |
|
|
397 |
|
/* I've only encountered flags == 1 so far. */ |
398 |
|
if (flags != 1) { |
399 |
|
fatal("Error: Unimplemented flags 0x%x\n", flags); |
400 |
|
exit(1); |
401 |
|
} |
402 |
|
|
403 |
|
/* |
404 |
|
* Read all load commands: |
405 |
|
*/ |
406 |
|
pos = is_64bit? 32 : 28; |
407 |
|
cmd_type = 0; |
408 |
|
do { |
409 |
|
/* Read command type and length: */ |
410 |
|
unencode(cmd_type, &buf[pos], uint32_t); |
411 |
|
unencode(cmd_len, &buf[pos+4], uint32_t); |
412 |
|
|
413 |
|
#if 0 |
414 |
|
debug("cmd %i, len=%i\n", cmd_type, cmd_len); |
415 |
|
for (i=8; i<cmd_len; i++) { |
416 |
|
unsigned char ch = buf[pos+i]; |
417 |
|
if (ch >= ' ' && ch < 127) |
418 |
|
debug("%c", ch); |
419 |
|
else |
420 |
|
debug("."); |
421 |
|
} |
422 |
|
#endif |
423 |
|
switch (cmd_type) { |
424 |
|
case 1: /* LC_SEGMENT */ |
425 |
|
debug("seg "); |
426 |
|
for (i=0; i<16; i++) { |
427 |
|
if (buf[pos + 8 + i] == 0) |
428 |
|
break; |
429 |
|
debug("%c", buf[pos + 8 + i]); |
430 |
|
} |
431 |
|
unencode(vmaddr, &buf[pos+8+16+0], uint32_t); |
432 |
|
unencode(vmsize, &buf[pos+8+16+4], uint32_t); |
433 |
|
unencode(fileoff, &buf[pos+8+16+8], uint32_t); |
434 |
|
unencode(filesize, &buf[pos+8+16+12], uint32_t); |
435 |
|
debug(": vmaddr=0x%x size=0x%x fileoff=0x%x", |
436 |
|
(int)vmaddr, (int)vmsize, (int)fileoff); |
437 |
|
|
438 |
|
if (filesize == 0) { |
439 |
|
debug("\n"); |
440 |
|
break; |
441 |
|
} |
442 |
|
|
443 |
|
fseek(f, fileoff, SEEK_SET); |
444 |
|
|
445 |
|
/* Load data from the file: */ |
446 |
|
while (filesize != 0) { |
447 |
|
unsigned char buf[32768]; |
448 |
|
ssize_t len = filesize > sizeof(buf) ? |
449 |
|
sizeof(buf) : filesize; |
450 |
|
len = fread(buf, 1, len, f); |
451 |
|
|
452 |
|
/* printf("fread len=%i vmaddr=%x buf[0..]=" |
453 |
|
"%02x %02x %02x\n", (int)len, (int)vmaddr, |
454 |
|
buf[0], buf[1], buf[2]); */ |
455 |
|
|
456 |
|
if (len > 0) { |
457 |
|
int len2 = 0; |
458 |
|
uint64_t vaddr1 = vmaddr & |
459 |
|
((1 << BITS_PER_MEMBLOCK) - 1); |
460 |
|
uint64_t vaddr2 = (vmaddr + |
461 |
|
len) & ((1 << BITS_PER_MEMBLOCK)-1); |
462 |
|
if (vaddr2 < vaddr1) { |
463 |
|
len2 = len - vaddr2; |
464 |
|
m->cpus[0]->memory_rw(m->cpus[ |
465 |
|
0], mem, vmaddr, &buf[0], |
466 |
|
len2, MEM_WRITE, |
467 |
|
NO_EXCEPTIONS); |
468 |
|
} |
469 |
|
m->cpus[0]->memory_rw(m->cpus[0], mem, |
470 |
|
vmaddr + len2, &buf[len2], len-len2, |
471 |
|
MEM_WRITE, NO_EXCEPTIONS); |
472 |
|
} else { |
473 |
|
fprintf(stderr, "error reading\n"); |
474 |
|
exit(1); |
475 |
|
} |
476 |
|
|
477 |
|
vmaddr += len; |
478 |
|
filesize -= len; |
479 |
|
} |
480 |
|
|
481 |
|
debug("\n"); |
482 |
|
break; |
483 |
|
|
484 |
|
case 2: /* LC_SYMTAB */ |
485 |
|
unencode(symoff, &buf[pos+8], uint32_t); |
486 |
|
unencode(nsyms, &buf[pos+12], uint32_t); |
487 |
|
unencode(stroff, &buf[pos+16], uint32_t); |
488 |
|
unencode(strsize, &buf[pos+20], uint32_t); |
489 |
|
debug("symtable: %i symbols @ 0x%x (strings at " |
490 |
|
"0x%x)\n", nsyms, symoff, stroff); |
491 |
|
|
492 |
|
symbols = malloc(12 * nsyms); |
493 |
|
if (symbols == NULL) { |
494 |
|
fprintf(stderr, "out of memory\n"); |
495 |
|
exit(1); |
496 |
|
} |
497 |
|
fseek(f, symoff, SEEK_SET); |
498 |
|
fread(symbols, 1, 12 * nsyms, f); |
499 |
|
|
500 |
|
strings = malloc(strsize); |
501 |
|
if (strings == NULL) { |
502 |
|
fprintf(stderr, "out of memory\n"); |
503 |
|
exit(1); |
504 |
|
} |
505 |
|
fseek(f, stroff, SEEK_SET); |
506 |
|
fread(strings, 1, strsize, f); |
507 |
|
|
508 |
|
for (i=0; i<nsyms; i++) { |
509 |
|
int n_strx, n_type, n_sect, n_desc; |
510 |
|
uint32_t n_value; |
511 |
|
unencode(n_strx, &symbols[i*12+0], int32_t); |
512 |
|
unencode(n_type, &symbols[i*12+4], uint8_t); |
513 |
|
unencode(n_sect, &symbols[i*12+5], uint8_t); |
514 |
|
unencode(n_desc, &symbols[i*12+6], int16_t); |
515 |
|
unencode(n_value, &symbols[i*12+8], uint32_t); |
516 |
|
/* debug("%i: strx=%i type=%i sect=%i desc=%i" |
517 |
|
" value=0x%x\n", i, n_strx, n_type, |
518 |
|
n_sect, n_desc, n_value); */ |
519 |
|
add_symbol_name(&m->symbol_context, |
520 |
|
n_value, 0, strings + n_strx, 0, -1); |
521 |
|
} |
522 |
|
|
523 |
|
free(symbols); |
524 |
|
free(strings); |
525 |
|
break; |
526 |
|
|
527 |
|
case 5: debug("unix thread context: "); |
528 |
|
/* See http://cvs.sf.net/viewcvs.py/hte/ |
529 |
|
HT%20Editor/machostruc.h or similar for details |
530 |
|
on the thread struct. */ |
531 |
|
unencode(flavor, &buf[pos+8], uint32_t); |
532 |
|
if (flavor != 1) { |
533 |
|
fatal("unimplemented flavor %i\n", flavor); |
534 |
|
exit(1); |
535 |
|
} |
536 |
|
|
537 |
|
if (arch != ARCH_PPC) { |
538 |
|
fatal("non-PPC arch? TODO\n"); |
539 |
|
exit(1); |
540 |
|
} |
541 |
|
|
542 |
|
unencode(entry, &buf[pos+16], uint32_t); |
543 |
|
entry_set = 1; |
544 |
|
debug("pc=0x%x\n", (int)entry); |
545 |
|
|
546 |
|
for (i=1; i<40; i++) { |
547 |
|
uint32_t x; |
548 |
|
unencode(x, &buf[pos+16+i*4], uint32_t); |
549 |
|
if (x != 0) { |
550 |
|
fatal("Entry nr %i in the Mach-O" |
551 |
|
" thread struct is non-zero" |
552 |
|
" (0x%x). This is not supported" |
553 |
|
" yet. TODO\n", i, x); |
554 |
|
exit(1); |
555 |
|
} |
556 |
|
} |
557 |
|
break; |
558 |
|
|
559 |
|
default:fatal("WARNING! Unimplemented load command %i!\n", |
560 |
|
cmd_type); |
561 |
|
} |
562 |
|
|
563 |
|
pos += cmd_len; |
564 |
|
} while (pos < sizeofcmds && cmd_type != 0); |
565 |
|
|
566 |
|
fclose(f); |
567 |
|
|
568 |
|
if (!entry_set) { |
569 |
|
fatal("No entry point? Aborting.\n"); |
570 |
|
exit(1); |
571 |
|
} |
572 |
|
|
573 |
|
*entrypointp = entry; |
574 |
|
|
575 |
|
if (encoding == ELFDATA2LSB) |
576 |
|
*byte_orderp = EMUL_LITTLE_ENDIAN; |
577 |
|
else |
578 |
|
*byte_orderp = EMUL_BIG_ENDIAN; |
579 |
|
|
580 |
|
n_executables_loaded ++; |
581 |
|
} |
582 |
|
|
583 |
|
|
584 |
|
/* |
585 |
* file_load_ecoff(): |
* file_load_ecoff(): |
586 |
* |
* |
587 |
* Loads an ecoff binary image into the emulated memory. The entry point |
* Loads an ecoff binary image into the emulated memory. The entry point |
1355 |
ok = 1; |
ok = 1; |
1356 |
} |
} |
1357 |
break; |
break; |
1358 |
|
case ARCH_ARM: |
1359 |
|
switch (emachine) { |
1360 |
|
case EM_ARM: |
1361 |
|
ok = 1; |
1362 |
|
} |
1363 |
|
break; |
1364 |
|
case ARCH_AVR: |
1365 |
|
switch (emachine) { |
1366 |
|
case EM_AVR: |
1367 |
|
ok = 1; |
1368 |
|
} |
1369 |
|
break; |
1370 |
|
case ARCH_HPPA: |
1371 |
|
switch (emachine) { |
1372 |
|
case EM_PARISC: |
1373 |
|
ok = 1; |
1374 |
|
} |
1375 |
|
break; |
1376 |
|
case ARCH_I960: |
1377 |
|
switch (emachine) { |
1378 |
|
case EM_960: |
1379 |
|
ok = 1; |
1380 |
|
} |
1381 |
|
break; |
1382 |
|
case ARCH_IA64: |
1383 |
|
switch (emachine) { |
1384 |
|
case EM_IA_64: |
1385 |
|
ok = 1; |
1386 |
|
} |
1387 |
|
break; |
1388 |
|
case ARCH_M68K: |
1389 |
|
switch (emachine) { |
1390 |
|
case EM_68K: |
1391 |
|
ok = 1; |
1392 |
|
} |
1393 |
|
break; |
1394 |
case ARCH_MIPS: |
case ARCH_MIPS: |
1395 |
switch (emachine) { |
switch (emachine) { |
1396 |
case EM_MIPS: |
case EM_MIPS: |
1405 |
ok = 1; |
ok = 1; |
1406 |
} |
} |
1407 |
break; |
break; |
1408 |
|
case ARCH_SH: |
1409 |
|
switch (emachine) { |
1410 |
|
case EM_SH: |
1411 |
|
ok = 1; |
1412 |
|
} |
1413 |
|
break; |
1414 |
case ARCH_SPARC: |
case ARCH_SPARC: |
1415 |
switch (emachine) { |
switch (emachine) { |
1416 |
case EM_SPARC: |
case EM_SPARC: |
1431 |
break; |
break; |
1432 |
} |
} |
1433 |
break; |
break; |
|
case ARCH_ARM: |
|
|
switch (emachine) { |
|
|
case EM_ARM: |
|
|
ok = 1; |
|
|
} |
|
|
break; |
|
|
case ARCH_IA64: |
|
|
switch (emachine) { |
|
|
case EM_IA_64: |
|
|
ok = 1; |
|
|
} |
|
|
break; |
|
|
case ARCH_M68K: |
|
|
switch (emachine) { |
|
|
case EM_68K: |
|
|
ok = 1; |
|
|
} |
|
|
break; |
|
1434 |
default: |
default: |
1435 |
fatal("file.c: INTERNAL ERROR: Unimplemented arch!\n"); |
fatal("file.c: INTERNAL ERROR: Unimplemented arch!\n"); |
1436 |
} |
} |
1462 |
* TODO: Find out what e_flag actually contains. |
* TODO: Find out what e_flag actually contains. |
1463 |
* TODO 2: This only sets mips16 for cpu 0. Yuck. Fix this! |
* TODO 2: This only sets mips16 for cpu 0. Yuck. Fix this! |
1464 |
*/ |
*/ |
1465 |
|
if (arch == ARCH_MIPS && ((eflags >> 24) & 0xff) == 0x24) { |
|
if (((eflags >> 24) & 0xff) == 0x24) { |
|
1466 |
debug("MIPS16 encoding (e_flags = 0x%08x)\n", eflags); |
debug("MIPS16 encoding (e_flags = 0x%08x)\n", eflags); |
1467 |
#ifdef ENABLE_MIPS16 |
#ifdef ENABLE_MIPS16 |
1468 |
m->cpus[0]->cd.mips.mips16 = 1; |
m->cpus[0]->cd.mips.mips16 = 1; |
1471 |
"(or use the --mips16 configure option)\n"); |
"(or use the --mips16 configure option)\n"); |
1472 |
exit(1); |
exit(1); |
1473 |
#endif |
#endif |
1474 |
} else if (eentry & 0x3) { |
} else if (arch == ARCH_MIPS && (eentry & 0x3)) { |
1475 |
debug("MIPS16 encoding (eentry not 32-bit aligned)\n"); |
debug("MIPS16 encoding (eentry not 32-bit aligned)\n"); |
1476 |
#ifdef ENABLE_MIPS16 |
#ifdef ENABLE_MIPS16 |
1477 |
m->cpus[0]->cd.mips.mips16 = 1; |
m->cpus[0]->cd.mips.mips16 = 1; |
1482 |
#endif |
#endif |
1483 |
} |
} |
1484 |
|
|
1485 |
|
/* |
1486 |
|
* SH64: 32-bit instruction encoding? TODO |
1487 |
|
*/ |
1488 |
|
if (arch == ARCH_SH && (eentry & 1)) { |
1489 |
|
debug("SH64: 32-bit instruction encoding\n"); |
1490 |
|
m->cpus[0]->cd.sh.compact = 0; |
1491 |
|
m->cpus[0]->cd.sh.bits = 64; |
1492 |
|
} |
1493 |
|
|
1494 |
/* Read the program headers: */ |
/* Read the program headers: */ |
1495 |
|
|
1496 |
for (i=0; i<ephnum; i++) { |
for (i=0; i<ephnum; i++) { |
1954 |
entrypointp, arch, byte_orderp); |
entrypointp, arch, byte_orderp); |
1955 |
goto ret; |
goto ret; |
1956 |
} |
} |
1957 |
|
if (buf[0]==0x00 && buf[1]==0x8f && buf[2]==0x01 && buf[3]==0x0b) { |
1958 |
|
/* ARM a.out */ |
1959 |
|
file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING, |
1960 |
|
entrypointp, arch, byte_orderp); |
1961 |
|
goto ret; |
1962 |
|
} |
1963 |
if (buf[0]==0x00 && buf[1]==0x86 && buf[2]==0x01 && buf[3]==0x0b) { |
if (buf[0]==0x00 && buf[1]==0x86 && buf[2]==0x01 && buf[3]==0x0b) { |
1964 |
/* i386 a.out (old OpenBSD and NetBSD etc) */ |
/* i386 a.out (old OpenBSD and NetBSD etc) */ |
1965 |
file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING, |
file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING, |
1973 |
goto ret; |
goto ret; |
1974 |
} |
} |
1975 |
|
|
1976 |
|
/* |
1977 |
|
* Is it a Mach-O file? |
1978 |
|
*/ |
1979 |
|
if (buf[0] == 0xfe && buf[1] == 0xed && buf[2] == 0xfa && |
1980 |
|
(buf[3] == 0xce || buf[3] == 0xcf)) { |
1981 |
|
file_load_macho(machine, mem, filename, entrypointp, |
1982 |
|
arch, byte_orderp, buf[3] == 0xcf, 0); |
1983 |
|
goto ret; |
1984 |
|
} |
1985 |
|
if ((buf[0] == 0xce || buf[0] == 0xcf) && buf[1] == 0xfa && |
1986 |
|
buf[2] == 0xed && buf[3] == 0xfe) { |
1987 |
|
file_load_macho(machine, mem, filename, entrypointp, |
1988 |
|
arch, byte_orderp, buf[0] == 0xcf, 1); |
1989 |
|
goto ret; |
1990 |
|
} |
1991 |
|
|
1992 |
/* |
/* |
1993 |
* Is it an ecoff? |
* Is it an ecoff? |
1994 |
* |
* |