aboutsummaryrefslogtreecommitdiff
path: root/jindroush/chkexe
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-05-16 01:43:09 -0400
committerB. Watson <urchlay@slackware.uk>2024-05-16 01:43:09 -0400
commita4cc3ad3504d634e379369862c9f9fd8eed379f3 (patch)
tree7b6f55c352a4ca62dddaa1b4a6854799111d2d2f /jindroush/chkexe
parentb33c25d1363110e6e4a714530f460b0ff951f56b (diff)
downloadbw-atari8-tools-a4cc3ad3504d634e379369862c9f9fd8eed379f3.tar.gz
Add Jindrich Kubec's tools.
Diffstat (limited to 'jindroush/chkexe')
-rw-r--r--jindroush/chkexe/Makefile55
-rw-r--r--jindroush/chkexe/chkexe.cpp504
-rw-r--r--jindroush/chkexe/pub.def31
-rw-r--r--jindroush/chkexe/readme.txt100
-rw-r--r--jindroush/chkexe/switches.def21
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;
+=