executor/util/disasm/disasm.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;
}