From a4cc3ad3504d634e379369862c9f9fd8eed379f3 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 16 May 2024 01:43:09 -0400 Subject: Add Jindrich Kubec's tools. --- jindroush/chkexe/Makefile | 55 +++++ jindroush/chkexe/chkexe.cpp | 504 ++++++++++++++++++++++++++++++++++++++++++ jindroush/chkexe/pub.def | 31 +++ jindroush/chkexe/readme.txt | 100 +++++++++ jindroush/chkexe/switches.def | 21 ++ 5 files changed, 711 insertions(+) create mode 100644 jindroush/chkexe/Makefile create mode 100644 jindroush/chkexe/chkexe.cpp create mode 100644 jindroush/chkexe/pub.def create mode 100644 jindroush/chkexe/readme.txt create mode 100644 jindroush/chkexe/switches.def (limited to 'jindroush/chkexe') 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->wBlkEndwBlkEnd = 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 " + +#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 +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; += -- cgit v1.2.3