mirror of
https://github.com/ctm/executor.git
synced 2024-11-30 05:51:22 +00:00
1044 lines
25 KiB
C
1044 lines
25 KiB
C
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include "disasm.h"
|
||
|
|
||
|
|
||
|
#define DISASM_CODE_START 0x10000
|
||
|
|
||
|
#define NOP_SIZE 2
|
||
|
#define NOP 0x4E71
|
||
|
#define NOPS_BETWEEN_SEGMENTS 4
|
||
|
|
||
|
#define NO_ADDRESS 0xFFFFFFFF
|
||
|
|
||
|
|
||
|
static char *patch_intersegment_calls (char *code, const codeseg_t *code0,
|
||
|
const codeseg_t *seg);
|
||
|
static codeseg_t *sort_segments (codeseg_t *seg);
|
||
|
static unsigned long jump_table_entry_to_address (long a5_offset,
|
||
|
const codeseg_t *code0,
|
||
|
const codeseg_t *seg);
|
||
|
static int create_asm (const char *filename, const unsigned char *mem,
|
||
|
unsigned long num_bytes,
|
||
|
unsigned long starting_address);
|
||
|
static int create_gdb_commands (const char *filename, unsigned long num_bytes);
|
||
|
static char *cleanup_assembly (char *code);
|
||
|
|
||
|
|
||
|
#define GDB_TERMINATING_STRING "End of assembler dump.\n"
|
||
|
#define GDB_TERMINATING_STRING_LENGTH \
|
||
|
(sizeof (GDB_TERMINATING_STRING) - 1)
|
||
|
|
||
|
|
||
|
/* Disassembles the specified block of memory and returns the disassembled
|
||
|
* code.
|
||
|
*/
|
||
|
char *
|
||
|
disasm (const unsigned char *mem, unsigned long num_bytes,
|
||
|
unsigned long starting_address)
|
||
|
{
|
||
|
FILE *gdb_fp;
|
||
|
char *buf;
|
||
|
unsigned long size, max_size;
|
||
|
int c;
|
||
|
|
||
|
/* Create the assembly file containing the raw bytes. */
|
||
|
if (create_asm ("/tmp/bytes.s", mem, num_bytes, starting_address))
|
||
|
return NULL;
|
||
|
|
||
|
/* Compile that into a bogus executable. */
|
||
|
if (system ("gcc -b i486-linuxaout -g -c /tmp/bytes.s -o /tmp/bytes.o"))
|
||
|
return NULL;
|
||
|
|
||
|
/* Create a temporary set of commands for gdb to execute. */
|
||
|
if (create_gdb_commands ("/tmp/gdbcmds", num_bytes))
|
||
|
return NULL;
|
||
|
|
||
|
/* Run gdb as the disassembler. */
|
||
|
gdb_fp = popen ("gdb -nx -batch -cd /tmp -x gdbcmds bytes.o", "r");
|
||
|
if (gdb_fp == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "Problems executing gdb.\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
max_size = 1024;
|
||
|
buf = (char *)malloc (max_size);
|
||
|
|
||
|
/* Skip first informational line from gdb. */
|
||
|
while ((c = getc (gdb_fp)) != EOF && c != '\n')
|
||
|
;
|
||
|
|
||
|
/* Read in everything from gdb. */
|
||
|
for (size = 0; (c = getc (gdb_fp)) != EOF; size++)
|
||
|
{
|
||
|
if (size >= max_size - 1)
|
||
|
{
|
||
|
if (max_size >= 4 * 1024 * 1024)
|
||
|
max_size += 4 * 1024 * 1024;
|
||
|
else
|
||
|
max_size *= 2;
|
||
|
buf = (char *)realloc (buf, max_size);
|
||
|
if (buf == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "Virtual memory exhausted!\n");
|
||
|
exit (-100);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
buf[size] = c;
|
||
|
}
|
||
|
|
||
|
/* Close the gdb pipe. */
|
||
|
pclose (gdb_fp);
|
||
|
|
||
|
/* Strip off the useless message gdb prints out at the end. */
|
||
|
if (size >= GDB_TERMINATING_STRING_LENGTH
|
||
|
&& !strncmp (buf + size - GDB_TERMINATING_STRING_LENGTH,
|
||
|
GDB_TERMINATING_STRING,
|
||
|
GDB_TERMINATING_STRING_LENGTH))
|
||
|
size -= GDB_TERMINATING_STRING_LENGTH;
|
||
|
|
||
|
/* Terminate the array and minimize the required memory. */
|
||
|
buf[size] = '\0';
|
||
|
buf = (char *)realloc (buf, size + 1);
|
||
|
if (buf == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "realloc problem!\n");
|
||
|
exit (-102);
|
||
|
}
|
||
|
|
||
|
remove ("/tmp/disassembly");
|
||
|
remove ("/tmp/gdbcmds");
|
||
|
remove ("/tmp/bytes.s");
|
||
|
remove ("/tmp/bytes");
|
||
|
|
||
|
/* Verify that the code went where the wanted it to go. */
|
||
|
if (size > 2)
|
||
|
{
|
||
|
unsigned long first_addr;
|
||
|
if (buf[0] != '0' || buf[1] != 'x'
|
||
|
|| sscanf (buf + 2, "%lx", &first_addr) != 1)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
fprintf (stderr, "Unable to verify first address! First line:\n");
|
||
|
for (i = 0; buf[i] != '\n' && buf[i] != '\0'; i++)
|
||
|
putc (buf[i], stderr);
|
||
|
putc ('\n', stderr);
|
||
|
|
||
|
free (buf);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (first_addr != starting_address)
|
||
|
{
|
||
|
fprintf (stderr, "Internal error: wanted to start code at 0x%lX, "
|
||
|
"but started it at 0x%lX.\n", starting_address,
|
||
|
first_addr);
|
||
|
free (buf);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return cleanup_assembly (buf);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Disassembles the specified linked list of code segments and returns
|
||
|
* the disassembled code.
|
||
|
*/
|
||
|
char *
|
||
|
disasm_code_segments (codeseg_t *seg, unsigned long *entry_point)
|
||
|
{
|
||
|
codeseg_t *code0, *c, *prev;
|
||
|
unsigned char *all_code;
|
||
|
unsigned long all_code_size, max_all_code_size;
|
||
|
char *disassembled_code;
|
||
|
|
||
|
/* Sort the code segments by segment number. */
|
||
|
seg = sort_segments (seg);
|
||
|
|
||
|
/* Default value for the entry point. */
|
||
|
*entry_point = NO_ADDRESS;
|
||
|
|
||
|
prev = NULL;
|
||
|
for (code0 = seg; code0 != NULL && code0->segment != 0; code0 = code0->next)
|
||
|
prev = code0;
|
||
|
if (code0 == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "Unable to find code resource 0!\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Take code0 out of the chain. */
|
||
|
if (prev == NULL)
|
||
|
seg = code0->next;
|
||
|
else
|
||
|
prev->next = code0->next;
|
||
|
|
||
|
/* Allocate enough space to hold all of the code. */
|
||
|
for (c = seg, max_all_code_size = 0; c != NULL; c = c->next)
|
||
|
max_all_code_size += c->num_code_bytes + NOPS_BETWEEN_SEGMENTS * NOP_SIZE;
|
||
|
all_code = (unsigned char *)malloc (max_all_code_size);
|
||
|
if (all_code == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "malloc failed in disasm_code_segments, "
|
||
|
"requested %lu bytes.\n", max_all_code_size);
|
||
|
exit (-105);
|
||
|
}
|
||
|
|
||
|
all_code_size = 0;
|
||
|
for (c = seg; c != NULL; c = c->next)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
/* Don't disassemble code segment 0! */
|
||
|
if (c->segment == 0)
|
||
|
{
|
||
|
fprintf (stderr, "Multiple code 0 segments!\n");
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* Append this code to the big block of code. */
|
||
|
c->disasm_start = DISASM_CODE_START + all_code_size;
|
||
|
memcpy (all_code + all_code_size, c->code, c->num_code_bytes);
|
||
|
all_code_size += c->num_code_bytes;
|
||
|
|
||
|
/* Write out some NOPs between segments in case things get
|
||
|
* out of sync because of data mistakenly disassembled as code.
|
||
|
*/
|
||
|
for (i = 0; i < NOPS_BETWEEN_SEGMENTS; i++)
|
||
|
{
|
||
|
all_code[all_code_size ] = NOP >> 8;
|
||
|
all_code[all_code_size + 1] = NOP & 0xFF;
|
||
|
all_code_size += NOP_SIZE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (all_code_size == 0)
|
||
|
return NULL;
|
||
|
|
||
|
/* Disassemble the code. */
|
||
|
disassembled_code = disasm (all_code,
|
||
|
all_code_size - NOPS_BETWEEN_SEGMENTS * NOP_SIZE,
|
||
|
DISASM_CODE_START);
|
||
|
|
||
|
if (disassembled_code == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "Fatal error, disasm returned NULL, exiting.\n");
|
||
|
exit (-103);
|
||
|
}
|
||
|
|
||
|
/* Go through and patch up intersegment jsr's so they point to the
|
||
|
* actual target.
|
||
|
*/
|
||
|
disassembled_code = patch_intersegment_calls (disassembled_code, code0, seg);
|
||
|
|
||
|
/* Compute the address of the program's entry point. */
|
||
|
*entry_point = jump_table_entry_to_address (read_long (&code0->code[12]) + 2,
|
||
|
code0, seg);
|
||
|
|
||
|
return disassembled_code;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Eliminates extra cruft and canonicalizes the assembly. */
|
||
|
static char *
|
||
|
cleanup_assembly (char *code)
|
||
|
{
|
||
|
char *new, *s, *d;
|
||
|
char last = '\0';
|
||
|
int in_angle_brackets_p;
|
||
|
unsigned long len;
|
||
|
|
||
|
len = strlen (code) + 1;
|
||
|
new = (char *) malloc (len + 1000);
|
||
|
if (new == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "malloc failed in cleanup_assembly, "
|
||
|
"requested %lu bytes.\n", len);
|
||
|
exit (-104);
|
||
|
}
|
||
|
|
||
|
in_angle_brackets_p = FALSE;
|
||
|
for (s = code, d = new; *s != '\0'; s++)
|
||
|
{
|
||
|
int c = *s;
|
||
|
|
||
|
if (c != '\n' && isspace (last) && isspace (c))
|
||
|
continue;
|
||
|
if (in_angle_brackets_p)
|
||
|
{
|
||
|
if (c == '>')
|
||
|
in_angle_brackets_p = FALSE;
|
||
|
}
|
||
|
else if (c == '<')
|
||
|
in_angle_brackets_p = TRUE;
|
||
|
else if (c != ':' || s == code || s[-1] != '>')
|
||
|
{
|
||
|
if (c == '\n' || c == ',')
|
||
|
while (d > new && isspace (d[-1]))
|
||
|
--d;
|
||
|
*d++ = last = c;
|
||
|
}
|
||
|
}
|
||
|
*d = '\0';
|
||
|
|
||
|
free (code);
|
||
|
return (char *)realloc (new, strlen (new) + 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Creates an assembly file with the specified code bytes. MEM and NUM_BYTES
|
||
|
* specify the code bytes, STARTING_ADDRESS specifies the address at which
|
||
|
* the code in the disassembly should begin.
|
||
|
*/
|
||
|
static int
|
||
|
create_asm (const char *filename, const unsigned char *mem,
|
||
|
unsigned long num_bytes, unsigned long starting_address)
|
||
|
{
|
||
|
FILE *asm_fp;
|
||
|
unsigned long n;
|
||
|
|
||
|
/* Open the output file. */
|
||
|
asm_fp = fopen (filename, "w");
|
||
|
if (asm_fp == NULL)
|
||
|
{
|
||
|
perror (filename);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
fprintf (asm_fp,
|
||
|
".text\n"
|
||
|
".space 0x%lX\n", starting_address - 0x1078);
|
||
|
#warning "FIXME - this is a gross hack...must be a good way to set the PC"
|
||
|
#endif
|
||
|
|
||
|
fprintf (asm_fp,
|
||
|
".text\n"
|
||
|
".set ., 0x%lX\n"
|
||
|
".globl main\n"
|
||
|
"main:\n" /* For ELF */
|
||
|
".globl _main\n"
|
||
|
"_main:\n", /* for a.out */
|
||
|
starting_address);
|
||
|
|
||
|
for (n = 0; n < num_bytes; n += 8)
|
||
|
{
|
||
|
unsigned long i;
|
||
|
|
||
|
fputs ("\t.byte ", asm_fp);
|
||
|
for (i = 0; i < 8 && n + i < num_bytes; i++)
|
||
|
fprintf (asm_fp, "%s0x%02X", (i != 0) ? "," : "",
|
||
|
(unsigned)mem[n + i]);
|
||
|
putc ('\n', asm_fp);
|
||
|
}
|
||
|
|
||
|
/* Toss out a few NOPs so disassembly can't run off the end and die. */
|
||
|
fprintf (asm_fp, "\t.byte 0x4E,0x71,0x4E,0x71,0x4E,0x71,0x4E,0x71\n");
|
||
|
|
||
|
/* Dump out low globals. Sadly gdb only uses these for branch targets. */
|
||
|
fputs (".set _nilhandle,0x00\n"
|
||
|
".globl _nilhandle\n"
|
||
|
".set _trapvectors,0x80\n"
|
||
|
".globl _trapvectors\n"
|
||
|
".set _dodusesit,0xE4\n"
|
||
|
".globl _dodusesit\n"
|
||
|
".set _monkeylives,0x100\n"
|
||
|
".globl _monkeylives\n"
|
||
|
".set _ScrVRes,0x102\n"
|
||
|
".globl _ScrVRes\n"
|
||
|
".set _ScrHRes,0x104\n"
|
||
|
".globl _ScrHRes\n"
|
||
|
".set _ScreenRow,0x106\n"
|
||
|
".globl _ScreenRow\n"
|
||
|
".set _MemTop,0x108\n"
|
||
|
".globl _MemTop\n"
|
||
|
".set _BufPtr,0x10C\n"
|
||
|
".globl _BufPtr\n"
|
||
|
".set _HeapEnd,0x114\n"
|
||
|
".globl _HeapEnd\n"
|
||
|
".set _TheZone,0x118\n"
|
||
|
".globl _TheZone\n"
|
||
|
".set _UTableBase,0x11C\n"
|
||
|
".globl _UTableBase\n"
|
||
|
".set _loadtrap,0x12D\n"
|
||
|
".globl _loadtrap\n"
|
||
|
".set _CPUFlag,0x12F\n"
|
||
|
".globl _CPUFlag\n"
|
||
|
".set _ApplLimit,0x130\n"
|
||
|
".globl _ApplLimit\n"
|
||
|
".set _SysEvtMask,0x144\n"
|
||
|
".globl _SysEvtMask\n"
|
||
|
".set _EventQueue,0x14A\n"
|
||
|
".globl _EventQueue\n"
|
||
|
".set _RndSeed_L,0x156\n"
|
||
|
".globl _RndSeed_L\n"
|
||
|
".set _SysVersion,0x15A\n"
|
||
|
".globl _SysVersion\n"
|
||
|
".set _SEvtEnb,0x15C\n"
|
||
|
".globl _SEvtEnb\n"
|
||
|
".set _VBLQueue,0x160\n"
|
||
|
".globl _VBLQueue\n"
|
||
|
".set _Ticks,0x16A\n"
|
||
|
".globl _Ticks\n"
|
||
|
".set _KeyMap,0x174\n"
|
||
|
".globl _KeyMap\n"
|
||
|
".set _KeyThresh,0x18E\n"
|
||
|
".globl _KeyThresh\n"
|
||
|
".set _KeyRepThresh,0x190\n"
|
||
|
".globl _KeyRepThresh\n"
|
||
|
".set _Lvl1DT,0x192\n"
|
||
|
".globl _Lvl1DT\n"
|
||
|
".set _hyperlong,0x1AA\n"
|
||
|
".globl _hyperlong\n"
|
||
|
".set _Lvl2DT,0x1B2\n"
|
||
|
".globl _Lvl2DT\n"
|
||
|
".set _UnitNtryCnt,0x1D2\n"
|
||
|
".globl _UnitNtryCnt\n"
|
||
|
".set _VIA,0x1D4\n"
|
||
|
".globl _VIA\n"
|
||
|
".set _SCCRd,0x1D8\n"
|
||
|
".globl _SCCRd\n"
|
||
|
".set _SCCWr,0x1DC\n"
|
||
|
".globl _SCCWr\n"
|
||
|
".set _IWM,0x1E0\n"
|
||
|
".globl _IWM\n"
|
||
|
".set _Scratch20,0x1E4\n"
|
||
|
".globl _Scratch20\n"
|
||
|
".set _SPValid,0x1F8\n"
|
||
|
".globl _SPValid\n"
|
||
|
".set _SPATalkA,0x1F9\n"
|
||
|
".globl _SPATalkA\n"
|
||
|
".set _SPATalkB,0x1FA\n"
|
||
|
".globl _SPATalkB\n"
|
||
|
".set _SPConfig,0x1FB\n"
|
||
|
".globl _SPConfig\n"
|
||
|
".set _SPPortA,0x1FC\n"
|
||
|
".globl _SPPortA\n"
|
||
|
".set _SPPortB,0x1FE\n"
|
||
|
".globl _SPPortB\n"
|
||
|
".set _SPAlarm,0x200\n"
|
||
|
".globl _SPAlarm\n"
|
||
|
".set _SPFont,0x204\n"
|
||
|
".globl _SPFont\n"
|
||
|
".set _SPKbd,0x206\n"
|
||
|
".globl _SPKbd\n"
|
||
|
".set _SPPrint,0x207\n"
|
||
|
".globl _SPPrint\n"
|
||
|
".set _SPVolCtl,0x208\n"
|
||
|
".globl _SPVolCtl\n"
|
||
|
".set _SPClikCaret,0x209\n"
|
||
|
".globl _SPClikCaret\n"
|
||
|
".set _SPMisc2,0x20B\n"
|
||
|
".globl _SPMisc2\n"
|
||
|
".set _Time,0x20C\n"
|
||
|
".globl _Time\n"
|
||
|
".set _BootDrive,0x210\n"
|
||
|
".globl _BootDrive\n"
|
||
|
".set _SFSaveDisk,0x214\n"
|
||
|
".globl _SFSaveDisk\n"
|
||
|
".set _KbdLast,0x218\n"
|
||
|
".globl _KbdLast\n"
|
||
|
".set _KbdType,0x21E\n"
|
||
|
".globl _KbdType\n"
|
||
|
".set _MemErr,0x220\n"
|
||
|
".globl _MemErr\n"
|
||
|
".set _SdVolume,0x260\n"
|
||
|
".globl _SdVolume\n"
|
||
|
".set _SoundPtr,0x262\n"
|
||
|
".globl _SoundPtr\n"
|
||
|
".set _SoundBase,0x266\n"
|
||
|
".globl _SoundBase\n"
|
||
|
".set _SoundActive,0x27E\n"
|
||
|
".globl _SoundActive\n"
|
||
|
".set _SoundLevel,0x27F\n"
|
||
|
".globl _SoundLevel\n"
|
||
|
".set _CurPitch,0x280\n"
|
||
|
".globl _CurPitch\n"
|
||
|
".set _mathones,0x282\n"
|
||
|
".globl _mathones\n"
|
||
|
".set _ROM85,0x28E\n"
|
||
|
".globl _ROM85\n"
|
||
|
".set _PortBUse,0x291\n"
|
||
|
".globl _PortBUse\n"
|
||
|
".set _ScreenVars,0x292\n"
|
||
|
".globl _ScreenVars\n"
|
||
|
".set _Key1Trans,0x29E\n"
|
||
|
".globl _Key1Trans\n"
|
||
|
".set _Key2Trans,0x2A2\n"
|
||
|
".globl _Key2Trans\n"
|
||
|
".set _SysZone,0x2A6\n"
|
||
|
".globl _SysZone\n"
|
||
|
".set _ApplZone,0x2AA\n"
|
||
|
".globl _ApplZone\n"
|
||
|
".set _ROMBase,0x2AE\n"
|
||
|
".globl _ROMBase\n"
|
||
|
".set _RAMBase,0x2B2\n"
|
||
|
".globl _RAMBase\n"
|
||
|
".set _DSAlertTab,0x2BA\n"
|
||
|
".globl _DSAlertTab\n"
|
||
|
".set _ExtStsDT,0x2BE\n"
|
||
|
".globl _ExtStsDT\n"
|
||
|
".set _ABusVars,0x2D8\n"
|
||
|
".globl _ABusVars\n"
|
||
|
".set _FinderName,0x2E0\n"
|
||
|
".globl _FinderName\n"
|
||
|
".set _DoubleTime,0x2F0\n"
|
||
|
".globl _DoubleTime\n"
|
||
|
".set _CaretTime,0x2F4\n"
|
||
|
".globl _CaretTime\n"
|
||
|
".set _ScrDmpEnb,0x2F8\n"
|
||
|
".globl _ScrDmpEnb\n"
|
||
|
".set _BufTgFNum,0x2FC\n"
|
||
|
".globl _BufTgFNum\n"
|
||
|
".set _BufTgFFlg,0x300\n"
|
||
|
".globl _BufTgFFlg\n"
|
||
|
".set _BufTgFBkNum,0x302\n"
|
||
|
".globl _BufTgFBkNum\n"
|
||
|
".set _BufTgDate,0x304\n"
|
||
|
".globl _BufTgDate\n"
|
||
|
".set _DrvQHdr,0x308\n"
|
||
|
".globl _DrvQHdr\n"
|
||
|
".set _heapcheck,0x316\n"
|
||
|
".globl _heapcheck\n"
|
||
|
".set _Lo3Bytes,0x31A\n"
|
||
|
".globl _Lo3Bytes\n"
|
||
|
".set _MinStack,0x31E\n"
|
||
|
".globl _MinStack\n"
|
||
|
".set _DefltStack,0x322\n"
|
||
|
".globl _DefltStack\n"
|
||
|
".set _GZRootHnd,0x328\n"
|
||
|
".globl _GZRootHnd\n"
|
||
|
".set _EjectNotify,0x338\n"
|
||
|
".globl _EjectNotify\n"
|
||
|
".set _IAZNotify,0x33C\n"
|
||
|
".globl _IAZNotify\n"
|
||
|
".set _FCBSPtr,0x34E\n"
|
||
|
".globl _FCBSPtr\n"
|
||
|
".set _DefVCBPtr,0x352\n"
|
||
|
".globl _DefVCBPtr\n"
|
||
|
".set _VCBQHdr,0x356\n"
|
||
|
".globl _VCBQHdr\n"
|
||
|
".set _FSQHdr,0x360\n"
|
||
|
".globl _FSQHdr\n"
|
||
|
".set _WDCBsPtr,0x372\n"
|
||
|
".globl _WDCBsPtr\n"
|
||
|
".set _DefVRefNum,0x384\n"
|
||
|
".globl _DefVRefNum\n"
|
||
|
".set _CurDirStore,0x398\n"
|
||
|
".globl _CurDirStore\n"
|
||
|
".set _MCLKPCmiss1,0x3A0\n"
|
||
|
".globl _MCLKPCmiss1\n"
|
||
|
".set _MCLKPCmiss2,0x3A6\n"
|
||
|
".globl _MCLKPCmiss2\n"
|
||
|
".set _ToExtFS,0x3F2\n"
|
||
|
".globl _ToExtFS\n"
|
||
|
".set _FSFCBLen,0x3F6\n"
|
||
|
".globl _FSFCBLen\n"
|
||
|
".set _DSAlertRect,0x3F8\n"
|
||
|
".globl _DSAlertRect\n"
|
||
|
".set _JADBProc,0x6B8\n"
|
||
|
".globl _JADBProc\n"
|
||
|
".set _JFLUSH,0x6F4\n"
|
||
|
".globl _JFLUSH\n"
|
||
|
".set _JResUnknown1,0x700\n"
|
||
|
".globl _JResUnknown1\n"
|
||
|
".set _JResUnknown2,0x714\n"
|
||
|
".globl _JResUnknown2\n"
|
||
|
".set _JHideCursor,0x800\n"
|
||
|
".globl _JHideCursor\n"
|
||
|
".set _JShowCursor,0x804\n"
|
||
|
".globl _JShowCursor\n"
|
||
|
".set _JShieldCursor,0x808\n"
|
||
|
".globl _JShieldCursor\n"
|
||
|
".set _JScrnAddr,0x80C\n"
|
||
|
".globl _JScrnAddr\n"
|
||
|
".set _JScrnSize,0x810\n"
|
||
|
".globl _JScrnSize\n"
|
||
|
".set _JInitCrsr,0x814\n"
|
||
|
".globl _JInitCrsr\n"
|
||
|
".set _JSetCrsr,0x818\n"
|
||
|
".globl _JSetCrsr\n"
|
||
|
".set _JCrsrObscure,0x81C\n"
|
||
|
".globl _JCrsrObscure\n"
|
||
|
".set _JUpdateProc,0x820\n"
|
||
|
".globl _JUpdateProc\n"
|
||
|
".set _ScrnBase,0x824\n"
|
||
|
".globl _ScrnBase\n"
|
||
|
".set _MouseLocation,0x82C\n"
|
||
|
".globl _MouseLocation\n"
|
||
|
".set _CrsrPin,0x834\n"
|
||
|
".globl _CrsrPin\n"
|
||
|
".set _MainDevice,0x8A4\n"
|
||
|
".globl _MainDevice\n"
|
||
|
".set _DeviceList,0x8A8\n"
|
||
|
".globl _DeviceList\n"
|
||
|
".set _QDColors,0x8B0\n"
|
||
|
".globl _QDColors\n"
|
||
|
".set _CrsrVis,0x8CC\n"
|
||
|
".globl _CrsrVis\n"
|
||
|
".set _CrsrState,0x8D0\n"
|
||
|
".globl _CrsrState\n"
|
||
|
".set _mousemask,0x8D6\n"
|
||
|
".globl _mousemask\n"
|
||
|
".set _mouseoffset,0x8DA\n"
|
||
|
".globl _mouseoffset\n"
|
||
|
".set _JournalFlag,0x8DE\n"
|
||
|
".globl _JournalFlag\n"
|
||
|
".set _JSwapFont,0x8E0\n"
|
||
|
".globl _JSwapFont\n"
|
||
|
".set _WidthListHand,0x8E4\n"
|
||
|
".globl _WidthListHand\n"
|
||
|
".set _JournalRef,0x8E8\n"
|
||
|
".globl _JournalRef\n"
|
||
|
".set _CrsrThresh,0x8EC\n"
|
||
|
".globl _CrsrThresh\n"
|
||
|
".set _WWExist,0x8F2\n"
|
||
|
".globl _WWExist\n"
|
||
|
".set _QDExist,0x8F3\n"
|
||
|
".globl _QDExist\n"
|
||
|
".set _JFetch,0x8F4\n"
|
||
|
".globl _JFetch\n"
|
||
|
".set _JStash,0x8F8\n"
|
||
|
".globl _JStash\n"
|
||
|
".set _JIODone,0x8FC\n"
|
||
|
".globl _JIODone\n"
|
||
|
".set _CurApRefNum,0x900\n"
|
||
|
".globl _CurApRefNum\n"
|
||
|
".set _CurrentA5,0x904\n"
|
||
|
".globl _CurrentA5\n"
|
||
|
".set _CurStackBase,0x908\n"
|
||
|
".globl _CurStackBase\n"
|
||
|
".set _CurApName,0x910\n"
|
||
|
".globl _CurApName\n"
|
||
|
".set _CurJTOffset,0x934\n"
|
||
|
".globl _CurJTOffset\n"
|
||
|
".set _CurPageOption,0x936\n"
|
||
|
".globl _CurPageOption\n"
|
||
|
".set _HiliteMode,0x938\n"
|
||
|
".globl _HiliteMode\n"
|
||
|
".set _PrintErr,0x944\n"
|
||
|
".globl _PrintErr\n"
|
||
|
".set _graphlooksat,0x952\n"
|
||
|
".globl _graphlooksat\n"
|
||
|
".set _macwritespace,0x954\n"
|
||
|
".globl _macwritespace\n"
|
||
|
".set _ScrapSize,0x960\n"
|
||
|
".globl _ScrapSize\n"
|
||
|
".set _ScrapHandle,0x964\n"
|
||
|
".globl _ScrapHandle\n"
|
||
|
".set _ScrapCount,0x968\n"
|
||
|
".globl _ScrapCount\n"
|
||
|
".set _ScrapState,0x96A\n"
|
||
|
".globl _ScrapState\n"
|
||
|
".set _ScrapName,0x96C\n"
|
||
|
".globl _ScrapName\n"
|
||
|
".set _ROMFont0,0x980\n"
|
||
|
".globl _ROMFont0\n"
|
||
|
".set _ApFontID,0x984\n"
|
||
|
".globl _ApFontID\n"
|
||
|
".set _ROMlib_myfmi,0x988\n"
|
||
|
".globl _ROMlib_myfmi\n"
|
||
|
".set _ROMlib_fmo,0x998\n"
|
||
|
".globl _ROMlib_fmo\n"
|
||
|
".set _ToolScratch,0x9CE\n"
|
||
|
".globl _ToolScratch\n"
|
||
|
".set _WindowList,0x9D6\n"
|
||
|
".globl _WindowList\n"
|
||
|
".set _SaveUpdate,0x9DA\n"
|
||
|
".globl _SaveUpdate\n"
|
||
|
".set _PaintWhite,0x9DC\n"
|
||
|
".globl _PaintWhite\n"
|
||
|
".set _WMgrPort,0x9DE\n"
|
||
|
".globl _WMgrPort\n"
|
||
|
".set _OldStructure,0x9E6\n"
|
||
|
".globl _OldStructure\n"
|
||
|
".set _OldContent,0x9EA\n"
|
||
|
".globl _OldContent\n"
|
||
|
".set _GrayRgn,0x9EE\n"
|
||
|
".globl _GrayRgn\n"
|
||
|
".set _SaveVisRgn,0x9F2\n"
|
||
|
".globl _SaveVisRgn\n"
|
||
|
".set _DragHook,0x9F6\n"
|
||
|
".globl _DragHook\n"
|
||
|
".set _Scratch8,0x9FA\n"
|
||
|
".globl _Scratch8\n"
|
||
|
".set _OneOne,0xA02\n"
|
||
|
".globl _OneOne\n"
|
||
|
".set _MinusOne,0xA06\n"
|
||
|
".globl _MinusOne\n"
|
||
|
".set _TopMenuItem,0xA0A\n"
|
||
|
".globl _TopMenuItem\n"
|
||
|
".set _AtMenuBottom,0xA0C\n"
|
||
|
".globl _AtMenuBottom\n"
|
||
|
".set _MenuList,0xA1C\n"
|
||
|
".globl _MenuList\n"
|
||
|
".set _MBarEnable,0xA20\n"
|
||
|
".globl _MBarEnable\n"
|
||
|
".set _MenuFlash,0xA24\n"
|
||
|
".globl _MenuFlash\n"
|
||
|
".set _TheMenu,0xA26\n"
|
||
|
".globl _TheMenu\n"
|
||
|
".set _MBarHook,0xA2C\n"
|
||
|
".globl _MBarHook\n"
|
||
|
".set _MenuHook,0xA30\n"
|
||
|
".globl _MenuHook\n"
|
||
|
".set _DragPattern,0xA34\n"
|
||
|
".globl _DragPattern\n"
|
||
|
".set _DeskPattern,0xA3C\n"
|
||
|
".globl _DeskPattern\n"
|
||
|
".set _fpstate,0xA4A\n"
|
||
|
".globl _fpstate\n"
|
||
|
".set _TopMapHndl,0xA50\n"
|
||
|
".globl _TopMapHndl\n"
|
||
|
".set _SysMapHndl,0xA54\n"
|
||
|
".globl _SysMapHndl\n"
|
||
|
".set _SysMap,0xA58\n"
|
||
|
".globl _SysMap\n"
|
||
|
".set _CurMap,0xA5A\n"
|
||
|
".globl _CurMap\n"
|
||
|
".set _resreadonly,0xA5C\n"
|
||
|
".globl _resreadonly\n"
|
||
|
".set _ResLoad,0xA5E\n"
|
||
|
".globl _ResLoad\n"
|
||
|
".set _ResErr,0xA60\n"
|
||
|
".globl _ResErr\n"
|
||
|
".set _FScaleDisable,0xA63\n"
|
||
|
".globl _FScaleDisable\n"
|
||
|
".set _CurActivate,0xA64\n"
|
||
|
".globl _CurActivate\n"
|
||
|
".set _CurDeactive,0xA68\n"
|
||
|
".globl _CurDeactive\n"
|
||
|
".set _DeskHook,0xA6C\n"
|
||
|
".globl _DeskHook\n"
|
||
|
".set _TEDoText,0xA70\n"
|
||
|
".globl _TEDoText\n"
|
||
|
".set _TERecal,0xA74\n"
|
||
|
".globl _TERecal\n"
|
||
|
".set _ApplScratch,0xA78\n"
|
||
|
".globl _ApplScratch\n"
|
||
|
".set _GhostWindow,0xA84\n"
|
||
|
".globl _GhostWindow\n"
|
||
|
".set _ResumeProc,0xA8C\n"
|
||
|
".globl _ResumeProc\n"
|
||
|
".set _ANumber,0xA98\n"
|
||
|
".globl _ANumber\n"
|
||
|
".set _ACount,0xA9A\n"
|
||
|
".globl _ACount\n"
|
||
|
".set _DABeeper,0xA9C\n"
|
||
|
".globl _DABeeper\n"
|
||
|
".set _DAStrings,0xAA0\n"
|
||
|
".globl _DAStrings\n"
|
||
|
".set _TEScrpLength,0xAB0\n"
|
||
|
".globl _TEScrpLength\n"
|
||
|
".set _TEScrpHandle,0xAB4\n"
|
||
|
".globl _TEScrpHandle\n"
|
||
|
".set _AppPacks,0xAB8\n"
|
||
|
".globl _AppPacks\n"
|
||
|
".set _SysResName,0xAD8\n"
|
||
|
".globl _SysResName\n"
|
||
|
".set _AppParmHandle,0xAEC\n"
|
||
|
".globl _AppParmHandle\n"
|
||
|
".set _DSErrCode,0xAF0\n"
|
||
|
".globl _DSErrCode\n"
|
||
|
".set _ResErrProc,0xAF2\n"
|
||
|
".globl _ResErrProc\n"
|
||
|
".set _DlgFont,0xAFA\n"
|
||
|
".globl _DlgFont\n"
|
||
|
".set _WidthPtr,0xB10\n"
|
||
|
".globl _WidthPtr\n"
|
||
|
".set _SCSIFlags,0xB22\n"
|
||
|
".globl _SCSIFlags\n"
|
||
|
".set _WidthTabHandle,0xB2A\n"
|
||
|
".globl _WidthTabHandle\n"
|
||
|
".set _hyperwritesto,0xB4C\n"
|
||
|
".globl _hyperwritesto\n"
|
||
|
".set _MenuDisable,0xB54\n"
|
||
|
".globl _MenuDisable\n"
|
||
|
".set _MBDFHndl,0xB58\n"
|
||
|
".globl _MBDFHndl\n"
|
||
|
".set _MBSaveLoc,0xB5C\n"
|
||
|
".globl _MBSaveLoc\n"
|
||
|
".set _RomMapInsert,0xB9E\n"
|
||
|
".globl _RomMapInsert\n"
|
||
|
".set _TmpResLoad,0xB9F\n"
|
||
|
".globl _TmpResLoad\n"
|
||
|
".set _IntlSpec,0xBA0\n"
|
||
|
".globl _IntlSpec\n"
|
||
|
".set _SysFontFam,0xBA6\n"
|
||
|
".globl _SysFontFam\n"
|
||
|
".set _SysFontSiz,0xBA8\n"
|
||
|
".globl _SysFontSiz\n"
|
||
|
".set _MBarHeight,0xBAA\n"
|
||
|
".globl _MBarHeight\n"
|
||
|
".set _TESysJust,0xBAC\n"
|
||
|
".globl _TESysJust\n"
|
||
|
".set _LastFOND,0xBC2\n"
|
||
|
".globl _LastFOND\n"
|
||
|
".set _fondid,0xBC6\n"
|
||
|
".globl _fondid\n"
|
||
|
".set _FractEnable,0xBF4\n"
|
||
|
".globl _FractEnable\n"
|
||
|
".set _MMU32Bit,0xCB2\n"
|
||
|
".globl _MMU32Bit\n"
|
||
|
".set _TheGDevice,0xCC8\n"
|
||
|
".globl _TheGDevice\n"
|
||
|
".set _AuxWinHead,0xCD0\n"
|
||
|
".globl _AuxWinHead\n"
|
||
|
".set _AuxCtlHead,0xCD4\n"
|
||
|
".globl _AuxCtlHead\n"
|
||
|
".set _TimeDBRA,0xD00\n"
|
||
|
".globl _TimeDBRA\n"
|
||
|
".set _TimeSCCDB,0xD02\n"
|
||
|
".globl _TimeSCCDB\n"
|
||
|
".set _JVBLTask,0xD28\n"
|
||
|
".globl _JVBLTask\n"
|
||
|
".set _WMgrCPort,0xD2C\n"
|
||
|
".globl _WMgrCPort\n"
|
||
|
".set _SynListHandle,0xD32\n"
|
||
|
".globl _SynListHandle\n"
|
||
|
".set _MenuCInfo,0xD50\n"
|
||
|
".globl _MenuCInfo\n"
|
||
|
".set _DTQueue,0xD92\n"
|
||
|
".globl _DTQueue\n"
|
||
|
".set _JDTInstall,0xD9C\n"
|
||
|
".globl _JDTInstall\n"
|
||
|
".set _HiliteRGB,0xDA0\n"
|
||
|
".globl _HiliteRGB\n"
|
||
|
".set _TimeSCSIDB,0xDA6\n"
|
||
|
".globl _TimeSCSIDB\n",
|
||
|
asm_fp);
|
||
|
|
||
|
/* Close the output file. */
|
||
|
if (fclose (asm_fp))
|
||
|
{
|
||
|
perror (filename);
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
create_gdb_commands (const char *filename, unsigned long num_bytes)
|
||
|
{
|
||
|
FILE *cmd_fp;
|
||
|
|
||
|
cmd_fp = fopen (filename, "w");
|
||
|
if (cmd_fp == NULL)
|
||
|
{
|
||
|
perror (filename);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
fprintf (cmd_fp,
|
||
|
"set m68k on\n"
|
||
|
"disassemble main main+%lu\n"
|
||
|
"quit\n",
|
||
|
num_bytes);
|
||
|
|
||
|
if (fclose (cmd_fp))
|
||
|
{
|
||
|
perror (filename);
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static unsigned long
|
||
|
jump_table_entry_to_address (long a5_offset, const codeseg_t *code0,
|
||
|
const codeseg_t *seg)
|
||
|
{
|
||
|
unsigned long jmp_table_length;
|
||
|
long jmp_table_offset, jmp_table_byte_index;
|
||
|
short segment_offset, segment_number;
|
||
|
unsigned char *p;
|
||
|
const codeseg_t *c;
|
||
|
|
||
|
/* Extract two useful fields from the code0 resource. */
|
||
|
jmp_table_length = read_long (&code0->code[8]);
|
||
|
jmp_table_offset = read_long (&code0->code[12]);
|
||
|
|
||
|
if (jmp_table_offset != 32)
|
||
|
{
|
||
|
fprintf (stderr, "Warning: expected 32 for jump table offset, "
|
||
|
"got %lu.\n", jmp_table_offset);
|
||
|
}
|
||
|
|
||
|
/* Figure out how many bytes into the jmp table to go. */
|
||
|
jmp_table_byte_index = a5_offset - jmp_table_offset;
|
||
|
|
||
|
/* If this isn't a legal entry, bail. */
|
||
|
if ((jmp_table_byte_index % 8) != 2
|
||
|
|| jmp_table_byte_index >= jmp_table_length)
|
||
|
return NO_ADDRESS;
|
||
|
|
||
|
/* Grab the segment number and offset for the target. The target
|
||
|
* is the actual push instruction, two bytes into the 8 byte
|
||
|
* stub.
|
||
|
*/
|
||
|
p = &code0->code[16 + jmp_table_byte_index];
|
||
|
segment_offset = read_short (p - 2);
|
||
|
segment_number = read_short (p + 2);
|
||
|
|
||
|
/* Look for a matching segment if we find one, return the
|
||
|
* address of the target code.
|
||
|
*/
|
||
|
for (c = seg; c != NULL; c = c->next)
|
||
|
{
|
||
|
if (c->segment == segment_number)
|
||
|
return c->disasm_start + segment_offset + 4;
|
||
|
}
|
||
|
|
||
|
return NO_ADDRESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Extracts the specified field from a line, copying it into buf. Returns
|
||
|
* buf if successful, NULL if there weren't that many fields on that line.
|
||
|
*/
|
||
|
char *
|
||
|
extract_field (const char *c, int field_num, char *buf)
|
||
|
{
|
||
|
char *d;
|
||
|
|
||
|
buf[0] = '\0';
|
||
|
while (field_num > 0)
|
||
|
{
|
||
|
if (isspace (*c))
|
||
|
{
|
||
|
/* Move on to the next field. */
|
||
|
while (isspace (*c) && *c != '\n')
|
||
|
c++;
|
||
|
if (*c == '\n' || *c == '\0')
|
||
|
return NULL;
|
||
|
--field_num;
|
||
|
}
|
||
|
else
|
||
|
c++;
|
||
|
}
|
||
|
|
||
|
/* Copy the specified field out to buf. */
|
||
|
for (d = buf; !isspace (*c) && *c != '\0'; c++, d++)
|
||
|
*d = *c;
|
||
|
*d = '\0';
|
||
|
|
||
|
return buf;
|
||
|
}
|
||
|
|
||
|
|
||
|
static char *
|
||
|
patch_intersegment_calls (char *code, const codeseg_t *code0,
|
||
|
const codeseg_t *seg)
|
||
|
{
|
||
|
char *new, *s, *d;
|
||
|
unsigned long len;
|
||
|
|
||
|
/* Allocate plenty of space for the new code. */
|
||
|
len = 100 + strlen (code) * 2;
|
||
|
new = (char *) malloc (len);
|
||
|
if (new == NULL)
|
||
|
{
|
||
|
fprintf (stderr, "malloc failed in patch_intersegment_calls, "
|
||
|
"%lu bytes requested.\n", len);
|
||
|
exit (-106);
|
||
|
}
|
||
|
|
||
|
for (s = code, d = new; *s != '\0'; )
|
||
|
{
|
||
|
char opcode[1024], operand[1024], junk[1024];
|
||
|
int handled_p = FALSE;
|
||
|
|
||
|
if (extract_field (s, 1, opcode)
|
||
|
&& (!strcmp (opcode, "jsr")
|
||
|
|| !strcmp (opcode, "jmp"))
|
||
|
&& extract_field (s, 2, operand)
|
||
|
&& !strncmp (operand, "a5@(", 4)
|
||
|
&& isdigit (operand[4])
|
||
|
&& !extract_field (s, 3, junk))
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 4; operand[i] != ')' && operand[i]; i++)
|
||
|
if (!isdigit (operand[i]))
|
||
|
break;
|
||
|
|
||
|
if (operand[i] == ')' && operand[i + 1] == '\0')
|
||
|
{
|
||
|
unsigned long new_addr;
|
||
|
new_addr = jump_table_entry_to_address (atoi (operand + 4),
|
||
|
code0, seg);
|
||
|
if (new_addr != NO_ADDRESS)
|
||
|
{
|
||
|
char addr[1024];
|
||
|
sprintf (d, "%s %s 0x%lx", extract_field (s, 0, addr),
|
||
|
opcode, new_addr);
|
||
|
d += strlen (d);
|
||
|
while (*s && *s != '\n')
|
||
|
s++;
|
||
|
handled_p = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!handled_p)
|
||
|
{
|
||
|
/* Copy this line from in to out. */
|
||
|
while (*s && *s != '\n')
|
||
|
*d++ = *s++;
|
||
|
}
|
||
|
|
||
|
if (*s == '\n')
|
||
|
*d++ = *s++;
|
||
|
}
|
||
|
|
||
|
*d = '\0';
|
||
|
free (code);
|
||
|
return (char *)realloc (new, strlen (new) + 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* qsort helper function. */
|
||
|
static int
|
||
|
compare_segs (const void *p1, const void *p2)
|
||
|
{
|
||
|
return ((*(const codeseg_t **)p1)->segment
|
||
|
- (*(const codeseg_t **)p2)->segment);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Sorts a linked list of code segments by segment number, lowest first. */
|
||
|
static codeseg_t *
|
||
|
sort_segments (codeseg_t *seg)
|
||
|
{
|
||
|
codeseg_t **array, *c, *next;
|
||
|
int num_segs, s;
|
||
|
|
||
|
if (seg == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
for (num_segs = 0, c = seg; c != NULL; c = c->next)
|
||
|
num_segs++;
|
||
|
array = (codeseg_t **)alloca (num_segs * sizeof array[0]);
|
||
|
for (s = 0, c = seg; c != NULL; c = c->next, s++)
|
||
|
array[s] = c;
|
||
|
|
||
|
qsort (array, num_segs, sizeof array[0], compare_segs);
|
||
|
|
||
|
for (s = num_segs - 1, next = NULL; s >= 0; s--)
|
||
|
{
|
||
|
array[s]->next = next;
|
||
|
next = array[s];
|
||
|
}
|
||
|
|
||
|
return next;
|
||
|
}
|