aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--xexamine.116
-rw-r--r--xexamine.c89
-rw-r--r--xexamine.rst14
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
===========