aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xexamine.131
-rw-r--r--xexamine.c59
-rw-r--r--xexamine.rst35
3 files changed, 91 insertions, 34 deletions
diff --git a/xexamine.1 b/xexamine.1
index 5b90e3e..e8e2b4b 100644
--- a/xexamine.1
+++ b/xexamine.1
@@ -36,7 +36,7 @@ xexamine \- Show information on Atari 8-bit executables (XEX)
.
.SH SYNOPSIS
.sp
-xexamine [ [\fB\-h\fP] | [ [\fB\-v\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
@@ -44,17 +44,19 @@ the following information on each segment in the file:
.sp
Segment number (1\-based).
.sp
-Start and end addresses (in hex).
+Offset in bytes from the start of the file (in decimal).
+.sp
+Start and end addresses (in hex by default).
.sp
Length in bytes (in decimal).
.sp
-CRC32 checksum of the segment.
+CRC32 checksum of the segment (in hex).
.sp
Segment type:
.INDENT 0.0
.INDENT 3.5
If the segment is a run address (loads at RUNAD) or an init address (loads at INITAD), the
-type is "Run" or "Init", with the actual run or init address.
+type is "Run" or "Init", with the actual run or init address, in hex by default.
.sp
Otherwise, the percentage of the segment that contains valid 6502 object
code is printed. This is an estimate based on static analysis and some
@@ -64,12 +66,17 @@ heuristics, and as such, isn\(aqt 100% accurate.
.SH OPTIONS
.\" TODO:
.
-.\" -d
+.\" -l
.
-.\" Disassemble
+.\" List code. Disassemble with da65?
.
.INDENT 0.0
.TP
+.B \-d
+Show addresses in decimal.
+.UNINDENT
+.INDENT 0.0
+.TP
.B \-s \fIsegment\-number\fP
Only show information on one segment. Segments are numbered starting
at one.
@@ -82,6 +89,18 @@ Print a short help message and exit.
.B \-v
Verbose operation.
.UNINDENT
+.SH NOTES
+.sp
+Currently, \fBxexamine\fP only works with .xex files. If you have a
+cartridge image as a .car file, you can use \fBxex2cart\fP to make a
+\&.xex from it (if it\(aqs a non\-bankswitched cart, anyway). If you have
+a raw chunk of object code, you can use \fBblob2xex\fP to make a .xex file
+from it.
+.sp
+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).
.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 fc600f1..d47993e 100644
--- a/xexamine.c
+++ b/xexamine.c
@@ -42,8 +42,7 @@ void crc32(const void *data, size_t n_bytes, uint32_t* crc) {
}
void usage(int status) {
- printf("Usage: " SELF " [-v] [-s segment] file.xex\n");
- if(status) fprintf(stderr, "Try '%s -h' for help\n", SELF);
+ printf("Usage: " SELF " [-h] [-d] [-v] [-s segment] file.xex\n");
exit(status);
}
@@ -310,11 +309,14 @@ int main(int argc, char **argv) {
xex_segment seg;
unsigned char buffer[65536];
char *filename;
- int opt, segcount = 0, only_segment = 0, header_printed = 0;
+ int opt, offset, segcount = 0, only_segment = 0, header_printed = 0, decimal = 0;
uint32_t crc;
- while((opt = getopt(argc, argv, "vhs:")) != -1) {
+ while((opt = getopt(argc, argv, "vhs:d")) != -1) {
switch(opt) {
+ case 'd':
+ decimal = 1;
+ break;
case 's':
if( (only_segment = get_address(SELF, optarg)) < 0 )
exit(1);
@@ -335,7 +337,13 @@ int main(int argc, char **argv) {
}
}
- if(optind >= argc || argv[optind + 1]) {
+ 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);
}
@@ -348,25 +356,36 @@ int main(int argc, char **argv) {
seg.object = buffer;
+ offset = 0;
while(xex_fread_seg(&seg, f)) {
segcount++;
- if(only_segment && (only_segment != segcount))
- continue;
- if(!header_printed) {
- printf("Seg | Start | End | Bytes | CRC32 | Type\n");
- header_printed++;
- }
+
crc = 0;
crc32(seg.object, seg.len, &crc);
- printf("%3d | $%04x | $%04x | %5d | %08x | ",
- segcount, seg.start_addr, seg.end_addr, seg.len, crc);
- if(seg.start_addr == XEX_RUNAD && seg.len > 1)
- printf("Run $%04x", (seg.object[0] | (seg.object[1] << 8)));
- else if(seg.start_addr == XEX_INITAD && seg.len > 1)
- printf("Init $%04x", (seg.object[0] | (seg.object[1] << 8)));
- else printf("%d%% code", classify_seg(seg));
-
- putchar('\n');
+
+ 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);
+
+ /* 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));
+
+ putchar('\n');
+ }
+
+ offset = ftell(f);
}
if(only_segment && (segcount < only_segment)) {
diff --git a/xexamine.rst b/xexamine.rst
index 60d217e..65c6ed6 100644
--- a/xexamine.rst
+++ b/xexamine.rst
@@ -14,7 +14,7 @@ Show information on Atari 8-bit executables (XEX)
SYNOPSIS
========
-xexamine [ [**-h**] | [ [**-v**] *xexfile* ]
+xexamine [ [**-h**] | [ [**-v**] [**-d**] [**-s** *segment*] *xexfile* ]
DESCRIPTION
===========
@@ -24,16 +24,18 @@ the following information on each segment in the file:
Segment number (1-based).
-Start and end addresses (in hex).
+Offset in bytes from the start of the file (in decimal).
+
+Start and end addresses (in hex by default).
Length in bytes (in decimal).
-CRC32 checksum of the segment.
+CRC32 checksum of the segment (in hex).
Segment type:
If the segment is a run address (loads at RUNAD) or an init address (loads at INITAD), the
- type is "Run" or "Init", with the actual run or init address.
+ type is "Run" or "Init", with the actual run or init address, in hex by default.
Otherwise, the percentage of the segment that contains valid 6502 object
code is printed. This is an estimate based on static analysis and some
@@ -43,18 +45,35 @@ OPTIONS
=======
.. TODO:
-.. -d
-.. Disassemble
+.. -l
+.. List code. Disassemble with da65?
+
+-d
+ Show addresses in decimal.
-s *segment-number*
Only show information on one segment. Segments are numbered starting
at one.
-h
- Print a short help message and exit.
+ Print a short help message and exit.
-v
- Verbose operation.
+ Verbose operation.
+
+NOTES
+=====
+
+Currently, **xexamine** only works with .xex files. If you have a
+cartridge image as a .car file, you can use **xex2cart** to make a
+.xex from it (if it's a non-bankswitched cart, anyway). If you have
+a raw chunk of object code, you can use **blob2xex** to make a .xex file
+from it.
+
+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).
EXIT STATUS
===========