From 7579bdadadc75a914e65148bc908190b14addcb5 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Fri, 26 Apr 2024 03:03:26 -0400 Subject: xexamine: fix init addresses being printed as Run (introduced in 7a7b256), support multiple files. --- Makefile | 1 - xexamine.1 | 16 +++++++---- xexamine.c | 89 ++++++++++++++++++++++++++++++------------------------------ xexamine.rst | 14 +++++++--- 4 files changed, 65 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index a3e27ad..c2c059f 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,6 @@ xexcat: xexcat.c xex.o get_address.o blob2xex: blob2xex.c xex.o get_address.o -# This is a work-in-progress, not ready yet. xexamine: xexamine.c xex.o get_address.o unmac65.xex: unmac65.c diff --git a/xexamine.1 b/xexamine.1 index e8e2b4b..1a4d68e 100644 --- a/xexamine.1 +++ b/xexamine.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "XEXAMINE" 1 "2024-04-25" "0.2.1" "Urchlay's Atari 8-bit Tools" +.TH "XEXAMINE" 1 "2024-04-26" "0.2.1" "Urchlay's Atari 8-bit Tools" .SH NAME xexamine \- Show information on Atari 8-bit executables (XEX) .\" RST source for xexamine(1) man page. Convert with: @@ -36,13 +36,13 @@ xexamine \- Show information on Atari 8-bit executables (XEX) . .SH SYNOPSIS .sp -xexamine [ [\fB\-h\fP] | [ [\fB\-v\fP] [\fB\-d\fP] [\fB\-s\fP \fIsegment\fP] \fIxexfile\fP ] +xexamine [ [\fB\-h\fP] | [ [\fB\-v\fP] [\fB\-d\fP] [\fB\-s\fP \fIsegment\fP] \fIxexfile\fP ... ] .SH DESCRIPTION .sp -\fBxexamine\fP reads an Atari 8\-bit executable (.xex file) and prints -the following information on each segment in the file: +\fBxexamine\fP reads Atari 8\-bit executables (.xex files) and prints +the following information on each segment in each file: .sp -Segment number (1\-based). +Segment number (in decimal, first segment is #1). .sp Offset in bytes from the start of the file (in decimal). .sp @@ -101,6 +101,12 @@ The code\-detection could be smarter, and probably will be pretty soon. Static analysis will never be 100% perfect, but the heuristics could be improved (e.g. by using something like Markov chain or Bayesian analysis). +.sp +The CRC32 sum is handy for comparing different releases of the same +program. Example would be a game that was cracked more than once +by different cracking groups, and each crack has a different title +screen. Often, the 2nd or some further segment contains the actual +code/data, and is identical. .SH EXIT STATUS .sp Exit status is zero if \fIxexfile\fP is a valid Atari .xex file, non\-zero otherwise. diff --git a/xexamine.c b/xexamine.c index d47993e..3c277e5 100644 --- a/xexamine.c +++ b/xexamine.c @@ -309,7 +309,7 @@ int main(int argc, char **argv) { xex_segment seg; unsigned char buffer[65536]; char *filename; - int opt, offset, segcount = 0, only_segment = 0, header_printed = 0, decimal = 0; + int opt, offset, segcount = 0, only_segment = 0, header_printed = 0, decimal = 0, print_filenames = 0; uint32_t crc; while((opt = getopt(argc, argv, "vhs:d")) != -1) { @@ -337,65 +337,64 @@ int main(int argc, char **argv) { } } - if(argv[optind + 1]) { - fprintf(stderr, SELF ": don't know what to do with excess argument '%s'.\n", argv[optind + 1]); - usage(1); - } - if(optind >= argc) { fprintf(stderr, SELF ": no xex file argument.\n"); usage(1); } - filename = argv[optind]; - if( !(f = fopen(filename, "rb")) ) { - fprintf(stderr, "%s: ", SELF); - perror(filename); - exit(1); - } + if(argc > optind + 1) print_filenames = 1; + while(optind < argc) { + filename = argv[optind++]; + if( !(f = fopen(filename, "rb")) ) { + fprintf(stderr, "%s: ", SELF); + perror(filename); + exit(1); + } + if(print_filenames) printf("%s:\n", filename); - seg.object = buffer; + seg.object = buffer; - offset = 0; - while(xex_fread_seg(&seg, f)) { - segcount++; + offset = segcount = 0; + while(xex_fread_seg(&seg, f)) { + segcount++; - crc = 0; - crc32(seg.object, seg.len, &crc); + crc = 0; + crc32(seg.object, seg.len, &crc); - if(!only_segment || (only_segment == segcount)) { - if(!header_printed) { - printf("Seg | Offset | Start | End | Bytes | CRC32 | Type\n"); - header_printed++; - } + if(!only_segment || (only_segment == segcount)) { + if(!header_printed) { + printf("Seg | Offset | Start | End | Bytes | CRC32 | Type\n"); + header_printed++; + } - printf((decimal ? - "%3d | %6d | %5d | %5d | %5d | %08x | " : - "%3d | %6d | $%04x | $%04x | %5d | %08x | "), - segcount, offset, seg.start_addr, seg.end_addr, seg.len, crc); + printf((decimal ? + "%3d | %6d | %5d | %5d | %5d | %08x | " : + "%3d | %6d | $%04x | $%04x | %5d | %08x | "), + segcount, offset, seg.start_addr, seg.end_addr, seg.len, crc); - /* TODO: what if there's a >=4 byte segment that loads at RUNAD? - the next 2 bytes are INITAD, we would silently ignore that fact. */ - if(seg.start_addr == XEX_RUNAD && seg.len > 1) - printf((decimal ? "Run %5d" : "Run $%04x"), (seg.object[0] | (seg.object[1] << 8))); - else if(seg.start_addr == XEX_INITAD && seg.len > 1) - printf((decimal ? "Init %5d" : "Run $%04x"), (seg.object[0] | (seg.object[1] << 8))); - else printf("%d%% code", classify_seg(seg)); + /* TODO: what if there's a >=4 byte segment that loads at RUNAD? + the next 2 bytes are INITAD, we would silently ignore that fact. */ + if(seg.start_addr == XEX_RUNAD && seg.len > 1) + printf((decimal ? "Run %5d" : "Run $%04x"), (seg.object[0] | (seg.object[1] << 8))); + else if(seg.start_addr == XEX_INITAD && seg.len > 1) + printf((decimal ? "Init %5d" : "Init $%04x"), (seg.object[0] | (seg.object[1] << 8))); + else printf("%d%% code", classify_seg(seg)); - putchar('\n'); - } + putchar('\n'); + } - offset = ftell(f); - } + offset = ftell(f); + } - if(only_segment && (segcount < only_segment)) { - fprintf(stderr, SELF ": can't show segment %d, only %d segments in file.\n", only_segment, segcount); - return 1; - } + if(only_segment && (segcount < only_segment)) { + fprintf(stderr, SELF ": can't show segment %d, only %d segments in file.\n", only_segment, segcount); + return 1; + } - if(!segcount) { - fprintf(stderr, SELF ": %s is not an Atari 8-bit executable.\n", filename); - return 1; + if(!segcount) { + fprintf(stderr, SELF ": %s is not an Atari 8-bit executable.\n", filename); + return 1; + } } return 0; diff --git a/xexamine.rst b/xexamine.rst index 65c6ed6..aff53fb 100644 --- a/xexamine.rst +++ b/xexamine.rst @@ -14,15 +14,15 @@ Show information on Atari 8-bit executables (XEX) SYNOPSIS ======== -xexamine [ [**-h**] | [ [**-v**] [**-d**] [**-s** *segment*] *xexfile* ] +xexamine [ [**-h**] | [ [**-v**] [**-d**] [**-s** *segment*] *xexfile* ... ] DESCRIPTION =========== -**xexamine** reads an Atari 8-bit executable (.xex file) and prints -the following information on each segment in the file: +**xexamine** reads Atari 8-bit executables (.xex files) and prints +the following information on each segment in each file: -Segment number (1-based). +Segment number (in decimal, first segment is #1). Offset in bytes from the start of the file (in decimal). @@ -75,6 +75,12 @@ Static analysis will never be 100% perfect, but the heuristics could be improved (e.g. by using something like Markov chain or Bayesian analysis). +The CRC32 sum is handy for comparing different releases of the same +program. Example would be a game that was cracked more than once +by different cracking groups, and each crack has a different title +screen. Often, the 2nd or some further segment contains the actual +code/data, and is identical. + EXIT STATUS =========== -- cgit v1.2.3