2068 lines · 63.1 KB · C
RawDownload
/* txd.c V7/3 * * Z code disassembler for Infocom game files * * Requires txio.c, getopt.c, showverb.c and tx.h. * * Works for all V1, V2, V3, V4, V5, V6, V7 and V8 games. * * Usage: txd story-file-name * * Mark Howell 25 August 1992 howell_ma@movies.enet.dec.com * * History: *    Merge separate disassemblers for each type into one program *    Fix logic error in low routine scan *    Force PC past start PC in middle routine scan *    Update opcodes *    Add pre-action and action verb names to routines *    Add print mode descriptions *    Wrap long lines of text *    Cleanup for 16 bit machines *    Change JGE and JLE to JG and JL *    Add support for V1 and V2 games *    Fix bug in printing of last string *    Add symbolic names for routines and labels *    Add verb syntax *    Improve verb formatting *    Add command line options *    Fix check for low address *    Add a switch to turn off grammar *    Add support for V6 games *    Make start of code for low scan the end of dictionary data *    Generate Inform style syntax as an option *    Add dump style and width option *    Fix lint warnings *    Fix inter-routine backward jumps *    Update operand names *    Add support for V7 and V8 games *    Limit cache size to MAX_CACHE pages *    Improve translation of constants to symbols *    Distinguish between pre-actions and Inform parsing routines *    Introduce indirect operands, eg. load [sp] sp *    Fix object 0 problem *    Add support for European characters (codes up to 223) *    Add support for Inform 6 (helped by Matthew T. Russotto) *    Add support for GV2 (MTR) *    Add support for Infocom V6 games *    Fix dependencies on sizeof(int) == 2 (mostly cosmetic) NOT DONE *    Add -S dump-strings at address option *    Remove GV2A support *    Add unicode disassembly support *    Add Inform and user symbol table support */ #include "tx.h" #define MAX_PCS 100 #define ROUND_CODE(address) ((address + (code_scaler - 1)) & ~(code_scaler - 1))#define ROUND_DATA(address) ((address + (story_scaler - 1)) & ~(story_scaler - 1)) #ifndef HAS_GETOPT#ifdef __STDC__extern int getopt (int, char *[], const char *);#elseextern int getopt ();#endif#endif #ifdef __STDC__static void process_story (const char *);static void decode_program (void);static int decode_routine (void);static int decode_code (void);static int decode_opcode (void);static int decode_operands (const char *, int, int, int, int, int, int);static int decode_parameters (int *);static int decode_parameter (int, int);static int decode_extra (void);static void decode_strings (unsigned long);static void scan_strings (unsigned long);static int lookup_string (unsigned long);static void lookup_verb (unsigned long);static void setup_dictionary (void);static int in_dictionary (unsigned long);static void add_label (unsigned long);static void add_routine (unsigned long);static int lookup_label (unsigned long, int);static int lookup_routine (unsigned long, int);static void renumber_cref (cref_item_t *);static void free_cref (cref_item_t *);static int print_object_desc (unsigned int);static void print_text (unsigned long *);static void print_integer (unsigned int, int);static void dump_data (unsigned long, unsigned long);static void dump_opcode (unsigned long, int, int, int *, int);static void dump_operand (unsigned long *, int, int, int *, int *);static void print_variable (int);#elsestatic void process_story ();static void decode_program ();static int decode_routine ();static int decode_code ();static int decode_opcode ();static int decode_operands ();static int decode_parameters ();static int decode_parameter ();static int decode_extra ();static void decode_strings ();static void scan_strings ();static int lookup_string ();static void lookup_verb ();static void setup_dictionary ();static int in_dictionary ();static void add_label ();static void add_routine ();static int lookup_label ();static int lookup_routine ();static void renumber_cref ();static void free_cref ();static int print_object_desc ();static void print_text ();static void print_integer ();static void dump_data ();static void dump_opcode ();static void dump_operand ();static void print_variable ();#endif static unsigned long pctable[MAX_PCS];static int pcindex = 0; static unsigned long start_data_pc, end_data_pc; static decode_t decode;static opcode_t opcode; static cref_item_t *strings_base = NULL;static cref_item_t *routines_base = NULL;static cref_item_t *current_routine = NULL; static int locals_count = 0;static unsigned long start_of_routine = 0; static unsigned int verb_count = 0;static unsigned int action_count = 0;static unsigned int parse_count = 0;static unsigned int parser_type = 0;static unsigned int prep_type = 0;static unsigned long verb_table_base = 0;static unsigned long verb_data_base = 0;static unsigned long action_table_base = 0;static unsigned long preact_table_base = 0;static unsigned long prep_table_base = 0;static unsigned long prep_table_end = 0; static const int verb_sizes[4] = { 2, 4, 7, 7 }; static unsigned long dict_start = 0;static unsigned long dict_end = 0;static unsigned long word_size = 0;static unsigned long word_count = 0; static unsigned long code_base = 0; static unsigned int obj_count = 0;static unsigned long obj_table_base = 0, obj_table_end = 0, obj_data_base = 0, obj_data_end = 0;static unsigned short inform_version = 0;static unsigned long class_numbers_base = 0, class_numbers_end = 0;static unsigned long property_names_base = 0, property_names_end = 0;static unsigned long attr_names_base = 0, attr_names_end = 0; #ifndef HAS_GETOPT/* getopt linkages */ extern int optind;extern const char *optarg;#endif static int option_labels = 1;static int option_grammar = 1;static int option_dump = 0;static int option_width = 79;static int option_symbols = 0;static unsigned long string_location = 0; #ifdef __STDC__int main (int argc, char *argv [])#elseint main (argc, argv)int argc;char *argv [];#endif{    int c, errflg = 0;     /* Parse the options */     while ((c = getopt (argc, argv, "abdghnsw:S:u:")) != EOF) {	switch (c) {	    case 'a':		option_inform = 6;		break;	    case 'd':		option_dump = 1;		break;	    case 'g':		option_grammar = 0;		break;	    case 'n':		option_labels = 0;		break;	    case 'w':		option_width = atoi (optarg);		break;	    case 'u':		init_symbols(optarg);		/*FALLTHRU*/	    case 's':		option_symbols = 1;		break;	    case 'S':#ifdef HAS_STRTOUL	    	string_location = strtoul(optarg, (char **)NULL, 0);#else	    	string_location = atoi(optarg);#endif		break;	    case 'h':	    case '?':	    default:		errflg++;	}    }     /* Display usage if unknown flag or no story file */     if (errflg || optind >= argc) {	(void) fprintf (stderr, "usage: %s [options...] story-file [story-file...]\n\n", argv[0]);	(void) fprintf (stderr, "TXD version 7/3 - disassemble Infocom story files. By Mark Howell\n");	(void) fprintf (stderr, "Works with V1 to V8 Infocom games.\n\n");	(void) fprintf (stderr, "\t-a   generate alternate syntax used by Inform\n");	(void) fprintf (stderr, "\t-d   dump hex of opcodes and data\n");	(void) fprintf (stderr, "\t-g   turn off grammar for action routines\n");	(void) fprintf (stderr, "\t-n   use addresses instead of labels\n");	(void) fprintf (stderr, "\t-w n display width (0 = no wrap)\n");	(void) fprintf (stderr, "\t-s   Symbolic mode (Inform 6+ only)\n");	(void) fprintf (stderr, "\t-u <file> Read user symbol table, implies -s for Inform games\n");	(void) fprintf (stderr, "\t-S n Dump high strings only, starting at address n\n");	exit (EXIT_FAILURE);    }     /* Process any story files on the command line */     for (; optind < argc; optind++)	process_story (argv[optind]);     exit (EXIT_SUCCESS);     return (0); }/* main */ #ifdef __STDC__static void process_story (const char *file_name)#elsestatic void process_story (file_name)const char *file_name;#endif{     tx_set_width (option_width);     open_story (file_name);     configure (V1, V8);     load_cache ();     setup_dictionary ();     if (option_grammar)	configure_parse_tables (&verb_count, &action_count, &parse_count, &parser_type, &prep_type,				&verb_table_base, &verb_data_base,				&action_table_base, &preact_table_base,				&prep_table_base, &prep_table_end);     if (option_symbols && (parser_type >= inform_gv1)) {   	configure_object_tables (&obj_count, &obj_table_base, &obj_table_end,			     	  &obj_data_base, &obj_data_end);    	configure_inform_tables(obj_data_end, &inform_version, &class_numbers_base, &class_numbers_end,    			    	&property_names_base, &property_names_end, &attr_names_base, &attr_names_end);    }     if (header.version != V6 && header.version != V7) {	decode.pc = code_base = dict_end;	decode.initial_pc = (unsigned long) header.start_pc - 1;    } else {	decode.pc = code_base = (unsigned long) header.routines_offset * story_scaler;	decode.initial_pc = decode.pc + (unsigned long) header.start_pc * code_scaler;    }     tx_printf ("Resident data ends at %lx, program starts at %lx, file ends at %lx\n",	       (unsigned long) header.resident_size, (unsigned long) decode.initial_pc, (unsigned long) file_size);    tx_printf ("\nStarting analysis pass at address %lx\n", (unsigned long) decode.pc); #if defined(TXD_DEBUG)    decode.first_pass = 0;    decode.low_address = decode.initial_pc;    decode.high_address = file_size;#if 0    decode.low_address = atoi (getenv ("LOW_ADDRESS"));    decode.high_address = atoi (getenv ("HIGH_ADDRESS"));#endif#else    decode.first_pass = 1;#endif    if (string_location) {	decode_strings (string_location);	exit(0);    }    decode_program ();     scan_strings (decode.pc); #if !defined(TXD_DEBUG)    tx_printf ("\nEnd of analysis pass, low address = %lx, high address = %lx\n",	       (unsigned long) decode.low_address, (unsigned long) decode.high_address);    if (start_data_pc)	tx_printf ("\n%ld bytes of data in code from %lx to %lx\n",		   (unsigned long) (end_data_pc - start_data_pc),		   (unsigned long) start_data_pc, (unsigned long) end_data_pc);    if ((decode.low_address - code_base) >= story_scaler) {	tx_printf ("\n%ld bytes of data before code from %lx to %lx\n",		   (unsigned long) (decode.low_address - code_base),		   (unsigned long) code_base, (unsigned long) decode.low_address);	if (option_dump) {	    tx_printf ("\n[Start of data");	    if (option_labels == 0)		tx_printf (" at %lx", (unsigned long) code_base);	    tx_printf ("]\n\n");	    dump_data (code_base, decode.low_address - 1);	    tx_printf ("\n[End of data");	    if (option_labels == 0)		tx_printf (" at %lx", (unsigned long) (decode.low_address - 1));	    tx_printf ("]\n");	}    }     if (option_labels)	renumber_cref (routines_base);     decode.first_pass = 0;    decode_program ();     decode_strings (decode.pc);#endif     close_story (); }/* process_story */ /* decode_program - Decode Z code in two passes */ #ifdef __STDC__static void decode_program (void)#elsestatic void decode_program ()#endif{    unsigned long pc, low_pc, high_pc, prev_low_pc, prev_high_pc;    int i, flag, vars;     if (decode.first_pass) {	if (decode.pc < decode.initial_pc) {	    /* Scan for low routines */	    decode.pc = ROUND_CODE (decode.pc);	    for (pc = decode.pc, flag = 0; pc < decode.initial_pc && flag == 0; pc += code_scaler) {		for (vars = (char) read_data_byte (&pc); vars < 0 || vars > 15; vars = (char) read_data_byte (&pc))		    pc = ROUND_CODE (pc);		decode.pc = pc - 1;		for (i = 0, flag = 1; i < 3 && flag; i++) {		    pcindex = 0;		    decode.pc = ROUND_CODE (decode.pc);		    if (decode_routine () != END_OF_ROUTINE || pcindex)			flag = 0;		}		decode.pc = pc - 1;	    }	    if (flag && (unsigned int) header.version < V5) {		pc = decode.pc;		vars = (char) read_data_byte (&pc);		low_pc = decode.pc;		for (pc = pc + (vars * 2) - 1, flag = 0; pc >= low_pc && flag == 0; pc -= story_scaler) {		    decode.pc = pc;		    for (i = 0, flag = 1; i < 3 && flag; i++) {			pcindex = 0;			decode.pc = ROUND_CODE (decode.pc);			if (decode_routine () != END_OF_ROUTINE || pcindex)			    flag = 0;		    }		    decode.pc = pc;		}	    }	    if (flag == 0 || decode.pc > decode.initial_pc)		decode.pc = decode.initial_pc;	}	/* Fill in middle routines */	decode.low_address = decode.pc;	decode.high_address = decode.pc;	start_data_pc = 0;	end_data_pc = 0;	do {	    if (option_labels) {		free_cref (routines_base);		routines_base = NULL;	    }	    prev_low_pc = decode.low_address;	    prev_high_pc = decode.high_address;	    flag = 0;	    pcindex = 0;	    low_pc = decode.low_address;	    high_pc = decode.high_address;	    pc = decode.pc = decode.low_address;	    while (decode.pc <= high_pc || decode.pc <= decode.initial_pc) {		if (start_data_pc == decode.pc)		    decode.pc = end_data_pc;		if (decode_routine () != END_OF_ROUTINE) {		    if (start_data_pc == 0)			start_data_pc = decode.pc;		    flag = 1;		    end_data_pc = 0;		    pcindex = 0;		    pc = ROUND_CODE (pc);		    do {			pc += code_scaler;			vars = (char) read_data_byte (&pc);			pc--;		    } while (vars < 0 || vars > 15);		    decode.pc = pc;		} else {		    if (pc < decode.initial_pc && decode.pc > decode.initial_pc) {			pc = decode.pc = decode.initial_pc;			decode.low_address = low_pc;			decode.high_address = high_pc;		    } else {			if (start_data_pc && end_data_pc == 0)			    end_data_pc = pc;			pc = ROUND_CODE (decode.pc);			if (flag == 0) {			    low_pc = decode.low_address;			    high_pc = decode.high_address;			}		    }		}	    }	    decode.low_address = low_pc;	    decode.high_address = high_pc;	} while (low_pc < prev_low_pc || high_pc > prev_high_pc);	/* Scan for high routines */	pc = decode.pc;	while (decode_routine () == END_OF_ROUTINE) {	    decode.high_address = pc;	    pc = decode.pc;	}    } else {	tx_printf ("\n[Start of code");	if (option_labels == 0)	    tx_printf (" at %lx", (unsigned long) decode.low_address);	tx_printf ("]\n");	for (decode.pc = decode.low_address;	     decode.pc <= decode.high_address; )	    (void) decode_routine ();	tx_printf ("\n[End of code");	if (option_labels == 0)	    tx_printf (" at %lx", (unsigned long) decode.pc);	tx_printf ("]\n");    } }/* decode_program */ /* decode_routine - Decode a routine from start address to last instruction */ #ifdef __STDC__static int decode_routine (void)#elsestatic int decode_routine ()#endif{    unsigned long old_pc, old_start;    cref_item_t *cref_item;    int vars, status, i, locals;     if (decode.first_pass) {	cref_item = NULL;	if (option_labels)	    cref_item = current_routine;	old_start = start_of_routine;	locals = locals_count;	old_pc = decode.pc;

Lines 1–500 of 2068.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t