[net.micro.atari16] Executable Format Dumper

david@looking.UUCP (David Rowley) (11/06/86)

*** REPLACE THIS LINE WITH YOUR MESSAGE ***

What follows is a simple program that dumps the format of an executable,
and displays the symbol table (if any).  Both the standard and Mark Williams
symbol tables can be displayed.  The dumper checks the integrity of various
aspects of the format, and can thus be used to see if a program has been
properly transmitted over the net.

I hope someone finds it useful.  I use a modified version of the routine
to load and relocate my own .PRG's, my own Pexec() if you will.

The source compiles under Alcyon (v4.14) and Mark Williams, I have not
tried it under Megamax, but there shouldn't be any major problem.
(Of course, Megamax does not spit out ANY form of symbol table, since
 everything is PC relative)


----------cut here---------------cut here---------------------------
/************************************************************************
 *
 *            Executable Program Dumper - Nov. 6th / 1986
 *
 *            David Rowley (..utzoo!watmath!looking!david)
 *
 *     Thanks to the person who posted the header format of a .PRG
 *
 ************************************************************************/

#include <stdio.h>
#include <ctype.h>

/* Select the appropriate define below: */

/* #define ALCYON 1 */
/* #define MarkWilliams 1 */


#ifdef ALCYON
	extern FILE *fopenb();
#endif

#ifdef MarkWilliams
	extern FILE *fopen();
#endif

extern long ftell();

#define FROM_CURRENT		1	/* Seek from current file pos */

typedef struct hdr {
	int	magic;		/* Magic word, contains 601Ah */

	long	text_size;	/* size of text segment */
	long	data_size;	/* size of data segment */

	long	bss_size;	/* Block storage segment size */
	long	sym_size;	/* Symbol Table size */

	long	zero1;		/* reserved, zero */
	long	zero2;		/* reserved, zero */

	int	reloc;		/* Flag - 0 - relocation info present */

	} HEADER;

typedef struct symtab {

	char	name[8];	/* name padded to 8 chars */
	int	symtype;	/* type */
	long	value;		/* value */

	} SYMTAB;

/*
 * Mark Williams Symbol Table Info
 */

typedef struct _mark_hdr {
	char	mwc_hdr[48];
	} MWC_HEADER;

typedef struct _mwc_sym {
	char	        mwc_name[16];
	unsigned char	mwc_type[2];
	unsigned char	mwc_value[4];
	} MWC_SYM;

#define	DEFINED		0x8000
#define EQUATED		0x4000
#define GLOBAL		0x2000
#define EQUATED_REG	0x1000
#define EXTERN_REF	0x0800
#define DATA_RELOC	0x0400
#define TEXT_RELOC	0x0200
#define BSS_RELOC	0x0100

int show_sym       = FALSE;
int show_end_bytes = FALSE;
int mark_williams  = FALSE;

main( argc, argv )
int argc;
char *argv[];
{
	char *str;

	while( (argc--) > 1 ) {
		str = argv[1];
		if( str[0] == '-' ) {
			switch( str[1] ) {
				case 's':
				case 'S':
					show_sym = TRUE;
					break;
				case 'a':
				case 'A':
					show_end_bytes = TRUE;
					break;
				case 'm':
				case 'M':
					mark_williams = TRUE;
					break;
				default:
					usage();
					exit(1);
			}
		} else {

			printf( "Dumping file '%s'\n", str );

			dump_prg( str );

		}
		argv++;
	}
}

usage()
{
	printf( "dump [-sam] filenames...\n" );
	printf( "     -s  displays symbol table (if any)\n" );
	printf( "     -a  displays the surplus bytes at the end of file\n" );
	printf( "     -m  displays a Mark Williams format symbol table\n" );
}

dump_prg( fname )
char *fname;
{
	FILE *fp;
	HEADER hdr;
	long symsize, textsize, datasize;
	long offset;
	long txt_relocs, data_relocs;
	long extra_bytes;
	long total;
	long reloc_size;
	int InText = TRUE;
	SYMTAB sym;
	int c;
	MWC_HEADER m_hdr;	/* The 48 byte header of a MWC symtab */
	MWC_SYM m_sym;		/* A MWC symtab entry */

	/*
	 * Read the header of a .TOS or .PRG file
	 */

#ifdef ALCYON
	fp = fopenb( fname, "r" );
#else
# ifdef MarkWilliams
	fp = fopen( fname, "rb" );
# else
	fp = fopen( fname, "r" );
# endif
#endif


	if( fp == (FILE *)0 ) {
		printf( "Can't open '%s'\n", fname );
		return;
	}

	fread( &hdr, 1, sizeof( HEADER ), fp );

	/*
	 * Now print out the values
	 */

	printf( "Magic Word: %4x\n\n", hdr.magic );

	if( hdr.magic != 0x601a ) {
		printf( "Unknown file type - Bad magic number\n" );
		return;
	}

	total = hdr.text_size + hdr.data_size + hdr.bss_size;

	printf( "Text size:  %8lx  %10ld\n", hdr.text_size, hdr.text_size );
	printf( "Data size:  %8lx  %10ld\n", hdr.data_size, hdr.data_size );
	printf( "Bss size:   %8lx  %10ld\n", hdr.bss_size,  hdr.bss_size  );
	printf( "-----------------------------------\n" );
	printf( "Total Size: %8lx  %10ld\n", total, total );

	printf( "\n" );
	printf( "Sym size:   %8lx  %10ld\n", hdr.sym_size,  hdr.sym_size  );

	printf( "\n" );
	if( hdr.reloc != 0 )
		printf( "No relocation information\n" );

	/*
	 * Skip past the text segment info
	 */

	textsize = hdr.text_size;

	/*
	 * Seek past the text segment
	 */
	if( fseek( fp, hdr.text_size, FROM_CURRENT ) != 0 ) {
		printf( "Error - Premature end of file in text segment\n" );
		return;
	}

	/*
	 * Skip past the data segment info
	 */

	datasize = hdr.data_size;

	if( fseek( fp, hdr.data_size, FROM_CURRENT ) != 0 ) {
		printf( "Error - Premature end of file in data segment\n" );
		return;
	}
	
	/*
	 * Now print out the symbol table
	 */
	symsize = hdr.sym_size;
	if( symsize )
		printf( "%ld symbol table entries:\n", (long)symsize / 
				(long)sizeof( SYMTAB ) );

	/*
	 * If we are to show the symbol table, then do it
	 */
	if( show_sym ) {

	    for( ;; ) {
		if( symsize == 0L ) break;
		if( symsize < sizeof( SYMTAB ) ) {
			printf( "Corrupt symbol table size\n" );
			return;
		}
		if( fread( &sym, 1, sizeof( SYMTAB ), fp ) != sizeof(SYMTAB)){
			printf( "Corrupt Symbol Table\n" );
			return;
		}

		symsize -= sizeof( SYMTAB );

		/*
		 * Print out this symbol table entry
		 */
		print_sym( &sym );

	   }
	} else {
		/*
		 * Otherwise, skip it
		 */
		fseek( fp, hdr.sym_size, FROM_CURRENT );
	}

	/*
	 * Now there is the relocation info
	 * (if present)
	 */
	if( hdr.reloc == 0) {
		fread( &offset, 1, sizeof( long ), fp );
		reloc_size = 4L;

		txt_relocs = 0L;
		data_relocs = 0L;
		if( offset > hdr.text_size ) {
			data_relocs = 1;
			InText = FALSE;
		} else {
			txt_relocs = 1;
			InText = TRUE;
		}

		while( (c = fgetc( fp )) != 0 ) {

			reloc_size++;

			if( c == EOF ) {
		printf( "Error - Premature end of file in relocation info\n" );
				return;
			}
			/*
			 * We have an offset, if it is '1', add 254
			 */
			if( (offset & 1L) == 1L ) {
				printf( "Error - relocation of odd address\n" );
				printf( "        at file location %lx\n",
						ftell( fp ) );
			}

			if( c == 1 )
				offset += 254;
			else {
				offset += c;

				if( InText && (offset > hdr.text_size )) {
					InText = FALSE;
				}

				if( InText )
					txt_relocs++;
				else
					data_relocs++;
			
				/*
				 * And relocate this location
				 */
			}
		}
		reloc_size++;

		printf( "Text Relocs: %ld, Data Relocs: %ld\n", txt_relocs,
			data_relocs );
		printf( "Size of relocation info: %ld\n", reloc_size );
	}

	/*
	 * We should get EOF now
	 */

	/*
	 * If we think this file might be a MarkWilliams one, with a symbol
	 * table, then do dump it
	 */
	if( mark_williams ) {
		/* Skip past the header */
		fread( &m_hdr, 1, sizeof( MWC_HEADER ), fp );

		printf( "Symbols:\n" );

		while( fread( &m_sym, 1, sizeof( MWC_SYM ), fp ) ) {

			print_mwc( &m_sym );

		}
	} else {
		extra_bytes = 0;
		while( (c = fgetc(fp)) != EOF ) {
			if( show_end_bytes ) {
				printf( "%2x ", c );
				if( isprint( c ) ) printf( "(%c) ", c );
			}
			extra_bytes++;
		}

		if( extra_bytes ) {
			printf( "Warning - %ld (%lx) extra bytes at end of file\n", 
					extra_bytes, extra_bytes );
		}
	}

	fclose( fp );
}

/*
 * Print out a MarkWilliams format symbol table entry
 */

print_mwc( s )
MWC_SYM *s;
{
	int i;
	int s_type;
	unsigned long s_value;
	char buf[17];

	for( i=0; i<16; i++ ) 
		buf[i] = s->mwc_name[i];
	buf[16] = 0;

	printf( "%20s   ", buf );

	s_type = (s->mwc_type[1] * 256) + s->mwc_type[0];
	printf( "%4x ", s_type );

	s_value = s->mwc_value[1];
	s_value *= 256;
	s_value |= s->mwc_value[0];
	s_value *= 256;
	s_value |= s->mwc_value[3];
	s_value *= 256;
	s_value |= s->mwc_value[2];

	printf( "%8lx ", s_value );

	printf( "\n" );
}

/*
 * Print out a standard format symbol table entry (ALCYON, etc)
 */

print_sym( s )
SYMTAB *s;
{
	char symname[9];
	int i;
	int s_type;

	for( i=0; i<8; i++ ) symname[i] = s->name[i];
	symname[8] = 0;

	printf( "%8s - %8lx : ", symname, s->value );

	s_type = s->symtype;

	if( s_type & DEFINED )
		printf( "defined " );

	if( s_type & EQUATED )
		printf( "equated " );

	if( s_type & GLOBAL )
		printf( "global " );

	if( s_type & EQUATED_REG )
		printf( "equated-reg " );

	if( s_type & EXTERN_REF )
		printf( "extern-ref " );

	if( s_type & DATA_RELOC )
		printf( "data-reloc " );

	if( s_type & TEXT_RELOC )
		printf( "text-reloc " );

	if( s_type & BSS_RELOC )
		printf( "bss-reloc " );

	printf( "\n" );
}
----------and here-----------and here-------------and here----------------

David Rowley
Looking Glass Software
Waterloo, Ontario.
..utzoo!watmath!looking!david