diff options
Diffstat (limited to 'jindroush/chkexe')
| -rw-r--r-- | jindroush/chkexe/Makefile | 55 | ||||
| -rw-r--r-- | jindroush/chkexe/chkexe.cpp | 504 | ||||
| -rw-r--r-- | jindroush/chkexe/pub.def | 31 | ||||
| -rw-r--r-- | jindroush/chkexe/readme.txt | 100 | ||||
| -rw-r--r-- | jindroush/chkexe/switches.def | 21 | 
5 files changed, 711 insertions, 0 deletions
| diff --git a/jindroush/chkexe/Makefile b/jindroush/chkexe/Makefile new file mode 100644 index 0000000..04ef5f7 --- /dev/null +++ b/jindroush/chkexe/Makefile @@ -0,0 +1,55 @@ +#===================================================================== +PRGNAME		= chkexe + +all: $(PRGNAME) + +release: +	@$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall" LDFLAGS="" +	@echo RELEASE: Compiled. + +rel_strip: +	@strip $(PRGNAME).exe + +rel_inst: +	@copy $(PRGNAME).exe $(ATAROOT)\\bin +	@echo RELEASE: Installed. + +debug:  +	@$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG" LDFLAGS="-g" +	@echo DEBUG: Compiled. + +clean: +	rm -f *.o +	rm -f $(PRGNAME) +	rm -f $(PRGNAME).exe +	rm -f switches.cpp +	rm -rf rel +	@echo DEBUG: Cleaned. + +#===================================================================== +INCLUDES =	makefile		\ +		switches.def		\ +		pub.def + + +OBJECTS =	chkexe.o + +#===================================================================== +CC		= g++ +LD		= g++ +LDLIBS		= -lm -L../lib -ljindroush +CPPFLAGS=-I../include $(COPT) +COPT=-O2 + +#===================================================================== + +$(PRGNAME) : $(OBJECTS) +	$(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME) + +chkexe.o: switches.cpp + +%.o : %.cpp $(INCLUDES) switches.cpp +	$(CC) $(CPPFLAGS) -c $< -o $@ + +switches.cpp : switches.def ../switches.pl +	perl ../switches.pl $< $@ diff --git a/jindroush/chkexe/chkexe.cpp b/jindroush/chkexe/chkexe.cpp new file mode 100644 index 0000000..4d651f0 --- /dev/null +++ b/jindroush/chkexe/chkexe.cpp @@ -0,0 +1,504 @@ +//    This program is free software; you can redistribute it and/or modify +//    it under the terms of the GNU General Public License as published by +//    the Free Software Foundation; either version 2 of the License, or +//    any later version. +// +//    This program is distributed in the hope that it will be useful, +//    but WITHOUT ANY WARRANTY; without even the implied warranty of +//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +//    GNU General Public License for more details. +// +//    You should have received a copy of the GNU General Public License +//    along with this program; if not, write to the Free Software +//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include "pub.def" + +#include "jintypes.h" + +#include "at_dis.h" +#include "cfile.h" + +#define AT_HEADER		0xFFFF + +#define AT_RUNL		0x02E0 +#define AT_RUNH		0x02E1 +#define AT_RUNPREV	( AT_RUNL - 1 ) + +#define AT_INITL		0x02E2 +#define AT_INITH		0x02E3 +#define AT_INITPAST	( AT_INITH + 1 ) + +#define AT_HWSTART	0xD000 +#define AT_HWEND		0xD7FF + +typedef struct block +{ +	struct block *pNext; +	WORD wBlkStart; +	WORD wBlkEnd; +} FILE_BLOCK; + + +BOOL BlockRead( CFile&, CFile& ); +void BlockInsert( WORD, WORD ); +void BlocksWrite( CFile& ); +void PrintOffset( CFile& ); +void BlockDisassemble( WORD, WORD ); + +FILE_BLOCK *g_pBlocks = NULL; +BYTE *g_pbtPool; +BOOL g_bHasRunAddress = FALSE; +LONG g_lFileLen; +BOOL g_bDisassemble = FALSE; +BOOL g_bSilent = FALSE; +BOOL g_bIsNotOk = TRUE; +BOOL g_bSplit = FALSE; +BOOL g_bOut = FALSE; + +WORD g_iSplitNum = 0; + +WORD g_wGapFill = 0; + +char* g_szInfile = NULL; +char* g_szOutfile = NULL; + +#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n" + +#define HEADER SHEADER \ +	PRG_DESC "\n" \ +	"  Latest version can be found at " PRG_URL "\n" \ +	"  Published under GPL. See GPL.TXT.\n\n" + +#define USAGE HEADER "Usage:  " PRG_NAME " " PRG_USAGE + +#include "switches.cpp" + +int main (int argc,char *argv[]) +{ +	setbuf( stdout, NULL ); +	setbuf( stderr, NULL ); + +	if ( !SWITCHES_Init( &argc, argv ) ) +		return 1; + +	if ( ( argc < 2 ) ) +	{ +		SWFN_HELP( USAGE ); +		return 1; +	} + +	fprintf( stderr, SHEADER ); + +	g_szInfile = argv[ 1 ]; + +	if ( argc == 3 ) +		g_szOutfile = argv[ 2 ]; + +	CFile cfIn; +	CFile cfOut; + +	if ( !cfIn.Open( g_szInfile ) ) +	{ +		fprintf( stderr, "Unable to open file\n\n%s", g_szInfile ); +		return -1; +	} + +	if ( AT_HEADER != cfIn.readLEw() ) +	{ +		printf( "%s: Not an Atari 8-bit binary load format file\n", g_szInfile ); +		cfIn.Close(); +		return -1; +	} + +	if ( g_bSilent ) +		printf( "%s: ", g_szInfile ); +	else +		printf( "Binary file:  %s\n", g_szInfile ); + +	if ( argc > 2 ) +	{ +		if ( !cfOut.Create( g_szOutfile ) ) +		{ +			fprintf( stderr, "Unable to open file\n\n%s", g_szOutfile ); +			return -1; +		} +		g_bOut = TRUE; +	} + +	if ( g_bOut ) +	{ +		cfOut.writeLEw( AT_HEADER ); +	} + +	g_pbtPool = new BYTE [ 0x10000 ]; +	memset( g_pbtPool,0, 0x10000 ); + +	if ( !g_pbtPool ) +	{ +		fprintf( stderr, "Unable to allocate memory for address space.\n" ); +		return -1; +	} + +	g_lFileLen = cfIn.GetLength(); + +	cfIn.Seek( 2, SEEK_SET ); + +	while ( cfIn.Tell() < g_lFileLen ) +	{ +		if ( ( g_bIsNotOk = !BlockRead( cfIn, cfOut ) ) ) +			break; +	} + +	cfIn.Close(); + +	if ( g_bHasRunAddress ) +		BlockInsert( AT_RUNL, AT_RUNH ); + +	if ( g_bOut ) +	{ +		BlocksWrite( cfOut ); // Write all blocks since last init +		cfOut.Close(); +	} + +	delete [] g_pbtPool; + +	if ( !g_bIsNotOk ) +		printf( "Ok!\n" ); + +	return 0; +} + + +BOOL BlockRead( CFile& cfIn, CFile& cfOut ) +{ +	WORD wBlkStart; +	WORD wBlkEnd; +	WORD wBlkLen; + +	do +	{ +		PrintOffset( cfIn ); + +		if ( cfIn.Tell() >= g_lFileLen ) +		{ +			printf( "Error:  Unexpected end of file\n" ); +			return FALSE; +		} + +		wBlkStart = cfIn.readLEw(); + +		if ( wBlkStart == AT_HEADER ) +		{ +			if ( !g_bSilent ) +				printf( "     :  Unexpected second 0xffff format header\n" ); +		} + +	} while ( wBlkStart == AT_HEADER ); + +	if ( cfIn.Tell() >= g_lFileLen ) +	{ +		printf( "Error:  Unexpected end of file in load range start address\n" ); +		return FALSE; +	} + +	wBlkEnd = cfIn.readLEw(); + +	wBlkLen = wBlkEnd - wBlkStart + 1; + +	if ( cfIn.Tell() >= g_lFileLen ) +	{ +		printf( "Error:  Unexpected end of file in load range end address\n" ); +		return FALSE; +	} + +	if ( ( wBlkStart == wBlkEnd ) && ( ( wBlkStart >> 8 ) == ( wBlkStart & 0xFF ) ) ) +	{ +		WORD wLen = g_lFileLen - cfIn.Tell() + 4; + +		//garbage was limited to be max $500 long, run address must exist! +		if ( ( wLen < 0x500 ) && ( wBlkStart ) ) +		{ +			printf( "Error:  Apparent garbage fill at end of file (%04X bytes)\n", wLen ); +			return FALSE; +		} + +	} + +	if ( wBlkEnd < wBlkStart ) +	{ +		if ( !g_bSilent ) +			printf( "Block:  %04X-%04X (%04X)\n", wBlkStart, wBlkEnd, wBlkLen ); + +		printf( "Error:  %ld bytes in file after invalid load range\n", g_lFileLen - cfIn.Tell() ); +		return FALSE; +	} + +	if ( g_lFileLen < cfIn.Tell() + wBlkLen ) +	{ +		if ( !g_bSilent ) +			printf( "Block:  %04X-%04X (%04X)\n", wBlkStart, wBlkEnd, wBlkLen ); + +		printf( "Error:  Truncated file:  missing data in load block (%04lX bytes missing)\n", cfIn.Tell() + wBlkLen - g_lFileLen ); +		return FALSE; +	} + +	// Read in the data for this block +	cfIn.Read( &g_pbtPool[wBlkStart], wBlkLen ); + +	// Check for run address +	if ( wBlkStart <= AT_RUNH && wBlkStart + wBlkLen >= AT_RUNL ) +	{ +		if (wBlkStart==AT_RUNH || wBlkStart+wBlkLen==AT_RUNL) +		{ +			if ( !g_bSilent ) +				printf( "     :  Partial run address\n" ); +		} +		if ( g_bHasRunAddress ) +			if ( !g_bSilent ) +				printf( "     :  Unexpected second run address\n" ); + +		g_bHasRunAddress = TRUE; + +		if ( !g_bSilent ) +			printf( "Run  :  %04X\n", g_pbtPool[ AT_RUNL ] + 256 * g_pbtPool[ AT_RUNH ] ); + +		if ( ( wBlkStart >= AT_RUNL ) && ( wBlkEnd <= AT_RUNH ) ) +			return TRUE; + +		// Other data in this block +		if ( wBlkStart == AT_RUNL || wBlkStart == AT_RUNH ) +		{ +			// Run and init in the same block--split +			wBlkStart = AT_INITL; +			wBlkLen = wBlkEnd - wBlkStart + 1; +		} +		else if ( wBlkEnd == AT_RUNL || wBlkEnd==AT_RUNH) +		{ +			// other stuff before the run address--split +			wBlkEnd = AT_RUNPREV; +			wBlkLen = wBlkEnd - wBlkStart + 1; +		} +		else +		{ +			// Run address in the middle of the block +			if ( !g_bSilent ) +				printf( "Block:  %04X-%04X (%04X)\n", wBlkStart, AT_RUNPREV, AT_RUNPREV - wBlkStart + 1 ); + +			BlockInsert( wBlkStart, AT_RUNPREV ); +			wBlkStart = AT_INITL; +			wBlkLen = wBlkEnd - wBlkStart + 1; +		} +	} + +	// Check for init address +	// We know there's nothing before the address in the block, +	// as we would have split it off above as a run address. +	if ( wBlkStart <= AT_INITH && wBlkStart + wBlkLen >= AT_INITL ) +	{ +		if ( wBlkStart == AT_INITH || wBlkStart + wBlkLen == AT_INITL ) +		{ +			if ( !g_bSilent ) +				printf( "     :  Partial init address\n" ); +		} +		if ( !g_bSilent ) +			printf( "Init :  %04X\n", g_pbtPool[ AT_INITL ] + 256 * g_pbtPool[ AT_INITH ] ); + +		// Other data in this block? +		if ( wBlkEnd > AT_INITH ) +		{ +			// More stuff past init--split +			if ( !g_bSilent ) +				printf( "Block:  %04X-%04X (%04X)\n", AT_INITPAST, wBlkEnd, wBlkLen ); + +			BlockInsert( AT_INITPAST, wBlkEnd ); +			wBlkEnd = AT_INITH; +			wBlkLen = wBlkEnd - wBlkStart + 1; +		} + +		BlockInsert( wBlkStart, wBlkEnd ); + +		if ( g_bDisassemble ) +			BlockDisassemble( wBlkStart, wBlkEnd ); + +		// Write everything out to avoid cross-init merges +		BlocksWrite( cfOut ); +		return TRUE; +	} + +	// Print data block load message +	if ( !g_bSilent ) +		printf( "Block:  %04X-%04X (%04X)\n", wBlkStart, wBlkEnd, wBlkLen ); + +	if ( ( !wBlkStart ) && ( !wBlkEnd ) ) +		return TRUE; + +	BlockInsert( wBlkStart, wBlkEnd ); + +	if ( g_bDisassemble ) +		BlockDisassemble( wBlkStart, wBlkEnd ); + +	return TRUE; +} + + +void BlockInsert(WORD wBlkStart,WORD wBlkEnd) +{ +	if ( g_bSplit ) +	{ +		char szPom[ 255 ]; +		sprintf( szPom, "blk%04X.blk", g_iSplitNum ); + +		CFile cf; +		if ( cf.Create( szPom ) ) +		{ +			cf.writeLEw( AT_HEADER ); +			cf.writeLEw( wBlkStart ); +			cf.writeLEw( wBlkEnd ); +			cf.Write( g_pbtPool + wBlkStart, wBlkEnd - wBlkStart + 1 ); +			cf.Close(); +		} + +		g_iSplitNum++; +	} + +	FILE_BLOCK *b,*bp; + +	bp = NULL; // previous block +	b = g_pBlocks; + +	while( b ) +	{ +		//this fills the ultra short blks +		if ( ( ( b->wBlkEnd + 1 ) >= 0x400 ) && ( b->wBlkStart < 0xC000 ) ) +		{ +			if ( ( b->wBlkEnd + 1 ) < wBlkStart ) +			{ +				if ( ( wBlkStart - ( b->wBlkEnd + 1 ) ) < g_wGapFill ) +				{ +					if ( !g_bSilent ) +						printf( "\t\tBlock merges with a previous block (gap fill)\n" ); + +					b->wBlkEnd = wBlkEnd; +					return; +				} +			} + +		} + +		// Check for merge +		if ( b->wBlkEnd + 1 == wBlkStart ) +		{ +			if ( !g_bSilent ) +				printf( "\t\tBlock merges with a previous block\n" ); + +			b->wBlkEnd = wBlkEnd; +			return; +		} +		if ( b->wBlkStart - 1 == wBlkEnd ) +		{ +			if ( !g_bSilent ) +				printf( "\t\tBlock merges with a previous block (unexpected ordering)\n" ); + +			b->wBlkStart = wBlkStart; +			return; +		} +		// Check for overlap +		if ( b->wBlkStart <= wBlkStart && wBlkEnd <= b->wBlkEnd ) +		{ +			if ( !g_bSilent ) +				printf( "\t\tWarning:  Completely overlaps a previous block--merged\n" ); + +			return; +		} +		if (b->wBlkStart <= wBlkEnd && b->wBlkStart >= wBlkStart) +		{ +			b->wBlkStart = wBlkStart; +			if (b->wBlkEnd<wBlkEnd) b->wBlkEnd = wBlkEnd; +			if ( !g_bSilent ) +				printf( "\t\tWarning:  Partially overlaps a previous block--merged\n" ); + +			return; +		} +		if ( b->wBlkEnd <= wBlkEnd && b->wBlkEnd >= wBlkStart ) +		{ +			b->wBlkEnd = wBlkEnd; + +			if ( b->wBlkStart > wBlkStart ) +				b->wBlkStart = wBlkStart; + +			if ( !g_bSilent ) +				printf( "\t\tWarning:  Partially overlaps a previous block--merged\n" ); + +			return; +		} +		bp = b; +		b = b->pNext; +	} + +	// Add this block to the end of the list +	b = new FILE_BLOCK; + +	if( !b ) +	{ +		fprintf(stderr,"Unable to alloc memory--aborted\n" ); +	} + +	b->wBlkStart = wBlkStart; +	b->wBlkEnd = wBlkEnd; +	b->pNext = NULL; + +	if (bp) +		bp->pNext = b; +	else +		g_pBlocks = b; +} + + +void BlocksWrite( CFile& cf ) +{ +	FILE_BLOCK* b; +	FILE_BLOCK* bp; + +	b = g_pBlocks; +	while (b) +	{ +		if ( g_bOut) +		{ +			cf.writeLEw( b->wBlkStart ); +			cf.writeLEw( b->wBlkEnd ); + +			cf.Write( &g_pbtPool[ b->wBlkStart ], b->wBlkEnd - b->wBlkStart + 1 ); +		} +		bp = b; // To allow free call after last use +		b = b->pNext; +		delete bp; +	} +	g_pBlocks = NULL; +} + + +void BlockDisassemble(WORD wBlkStart,WORD wBlkEnd) +{ +	//don't disassemble run & init block +	if ( ( wBlkStart >= AT_RUNL )	&& ( wBlkEnd <= AT_INITH ) ) +		goto BDEND; + +	//don't disassemble hw addresses +	if ( ( wBlkStart >= AT_HWSTART ) && ( wBlkEnd <= AT_HWEND ) ) +		goto BDEND; + +	OutputBlockDiss( g_pbtPool + wBlkStart, wBlkStart, wBlkEnd ); + +BDEND: +	printf( "\n" ); +	return; +} + +void PrintOffset( CFile& cf ) +{ +	if ( !g_bSilent ) +		printf( "[%04lX] ", cf.Tell() ); +} + diff --git a/jindroush/chkexe/pub.def b/jindroush/chkexe/pub.def new file mode 100644 index 0000000..eb3d2fb --- /dev/null +++ b/jindroush/chkexe/pub.def @@ -0,0 +1,31 @@ +//    This program is free software; you can redistribute it and/or modify +//    it under the terms of the GNU General Public License as published by +//    the Free Software Foundation; either version 2 of the License, or +//    any later version. +// +//    This program is distributed in the hope that it will be useful, +//    but WITHOUT ANY WARRANTY; without even the implied warranty of +//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +//    GNU General Public License for more details. +// +//    You should have received a copy of the GNU General Public License +//    along with this program; if not, write to the Free Software +//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#define PRG_NAME	"chkexe"	 +#define PRG_VERSION	"2.62" +#define PRG_COPYRIGHT	"1998-1999" +#define PRG_UNDERGPL	"1" +#define PRG_AUTHOR	"Jindrich Kubec <kubecj@asw.cz>" + +#define PRG_URL 	"http://www.asw.cz/~kubecj" + +#define PRG_DESC	"Atari executable checker/decompiler." +#define PRG_USAGE	"[options] sourcefile [destfile]"  + +#define PRG_ARCH	"PC" +#define PRG_TOOLS	"PERL" + +#define PRG_SRCS "!GENERATED!" +#define PRG_BINS "rel/chkexe.exe" diff --git a/jindroush/chkexe/readme.txt b/jindroush/chkexe/readme.txt new file mode 100644 index 0000000..7d92c8f --- /dev/null +++ b/jindroush/chkexe/readme.txt @@ -0,0 +1,100 @@ +ChkExe v2.62 (c) 1998-1999 Jindrich Kubec <kubecj@asw.cz> +Latest version can be found at http://www.asw.cz/~kubecj + +This program is provided 'as is', no warranty will be taken +for any damage caused by it or by any use of it. + +The whole package is placed under the GNU Public License, for further +information on redistribution see the included file "GPL.TXT". + + +Description: +------------ +Atari executable checker/decompiler. +Based on Preston Crow's binload utility. Better command line switches, +better disassembler and gap filing. + +Disassembler is only very simple - single pass, no data recognition. + + +Usage: +------ +ChkExe [options] sourcefile [destfile] + +sourcefile is Atari DOS exe file. + +destfile is optional output file with changed blocks. + +gaps is for changing the size of maximum 'gap' fill. It's the destination +  of two blocks under which blocks will be 'glued' together by zeroes. + +silent outputs only OK/errors + +split creates also blkXXXX.blk files with only one block inside + +d creates also disassembly of each block + + +History: +-------- +Date, Author, Version +6/2/1995, crow, 1.00 +Initial public release + +6/4/1995, crow, 2.00 +Create fixed version of the file + +6/7/1995, crow, 2.10 +Use separate functions +Merge overlapping and adjacent blocks + +6/9/1995, cmwagner, 2.20 +Ported to MS-DOS machines, should compile and work under +MS-DOS,compile in COMPACT model. + +11/11/1995, cmwagner, 2.30 +Added d switch, which allow disassembly of blocks to stdout +disassemble_block() function added, outins() function added, instable[] added + +11/16/1995, cmwagner, 2.40 +Fixed bogus operands on output when operands extend beyond +end of block, just puts out a bogus instruction symbol now (???). + +9/24/1998, kubecj, 2.50 +Modularized, added symbol resolving in disassembler +Added -silent switch for batch processing +Added gap filling +Rewritten in CPP under DJGPP only, no portability + +7/7/1999, kubecj, 2.60 +Added file blocks splitting + +8/20/1999, kubecj, 2.61 +Fixed signedness bug concerning branches :( + +10/10/1999, kubecj, 2.62 +Changed switches processing. + + +To Do: +------ +Maybe better disassembler. + + +Known Bugs: +----------- +None. + + +Compiling Tools: +---------------- +For scripts: Perl. +URL: http://www.perl.com + +For PC executables: DJGPP. +Sources were written/tested on GCC/Intel only. There should be only +slight problems to port it to different architectures/environments. +Makefile should need only slight changes. +URL: http://www.delorie.com + + diff --git a/jindroush/chkexe/switches.def b/jindroush/chkexe/switches.def new file mode 100644 index 0000000..4c2bf20 --- /dev/null +++ b/jindroush/chkexe/switches.def @@ -0,0 +1,21 @@ +d, dis +disassembles +=g_bDisassemble = TRUE; += + +silent, s +silent operation +=g_bSilent = TRUE; += + +gaps +length of gap fill (hexadecimal) +=int iTemp; +hexnum=bRet = SWFN_NUMH( &iTemp ); +=g_wGapFill = iTemp; += + +split +split into blocks +=g_bSplit = TRUE; += | 
