/* | |
* (C) Copyright 2002, Brian Knittel. | |
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN | |
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the | |
* usual yada-yada. Please keep this notice and the copyright in any distributions | |
* or modifications. | |
* | |
* This is not a supported product, but I welcome bug reports and fixes. | |
* Mail to sim@ibm1130.org | |
*/ | |
// --------------------------------------------------------------------------------- | |
// BINDUMP - dumps card deck files in assembler object format | |
// | |
// Usage: | |
/// bindump deckfile lists object header info & sector break cards | |
// bindump -v deckfile lists object data records as well | |
// bindump -p deckfile for system program, lists phase IDs in the deck | |
// bindump -s deckfile >outfile for system program, sorts the phases & writes to stdout | |
#include <stdio.h> | |
#include <stdlib.h> | |
#ifdef WIN32 | |
# include <windows.h> | |
# include <io.h> | |
# include <fcntl.h> | |
#endif | |
#ifndef TRUE | |
#define BOOL int | |
#define TRUE 1 | |
#define FALSE 0 | |
#endif | |
typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC; | |
BOOL verbose = FALSE; | |
BOOL phid = FALSE; | |
BOOL sort = FALSE; | |
unsigned short card[80], buf[54], cardtype; | |
// bindump - dump a binary (card format) deck to verify sbrks, etc | |
void bail (char *msg); | |
void dump (char *fname); | |
void dump_data (char *fname); | |
void dump_phids (char *fname); | |
char *getname (unsigned short *ptr); | |
char *getseq (void); | |
int hollerith_to_ascii (unsigned short h); | |
void process (char *fname); | |
void show_raw (char *name); | |
void show_data (void); | |
void show_core (void); | |
void show_endc (void); | |
void show_81 (void); | |
void show_main (void); | |
void show_sub (void); | |
void show_ils (void); | |
void show_iss (void); | |
void show_end (void); | |
void sort_phases (char *fname); | |
void trim (char *s); | |
void unpack (unsigned short *card, unsigned short *buf); | |
void verify_checksum(unsigned short *buf); | |
int main (int argc, char **argv) | |
{ | |
char *arg; | |
static char usestr[] = "Usage: bindump [-psv] filename..."; | |
int i; | |
for (i = 1; i < argc; i++) { | |
arg = argv[i]; | |
if (*arg == '-') { | |
arg++; | |
while (*arg) { | |
switch (*arg++) { | |
case 'v': | |
verbose = TRUE; | |
break; | |
case 'p': | |
phid = TRUE; // print only phase ID's | |
break; | |
case 's': | |
sort = TRUE; // sort deck by phases, writing to stdout | |
break; | |
default: | |
bail(usestr); | |
} | |
} | |
} | |
} | |
for (i = 1; i < argc; i++) { | |
arg = argv[i]; | |
if (*arg != '-') | |
process(arg); | |
} | |
return 0; | |
} | |
void process (char *nm) | |
{ | |
#ifdef WIN32 | |
WIN32_FIND_DATA fd; | |
HANDLE hFind; | |
char *c, buf[256]; | |
if (strchr(nm, '*') == NULL && strchr(nm, '?') == NULL) | |
dump(nm); | |
else if ((hFind = FindFirstFile(nm, &fd)) == INVALID_HANDLE_VALUE) | |
fprintf(stderr, "No files matching '%s'\n", nm); | |
else { | |
if ((c = strrchr(nm, '\\')) == NULL) | |
c = strrchr(nm, ':'); | |
do { | |
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
continue; | |
if (c == NULL) | |
dump(fd.cFileName); | |
else { | |
strcpy(buf, nm); | |
strcpy(buf + (c-nm+1), fd.cFileName); | |
dump(buf); | |
} | |
} while (FindNextFile(hFind, &fd)); | |
FindClose(hFind); | |
} | |
#else | |
dump(nm); // on unices, sh globs for us | |
#endif | |
} | |
void dump (char *fname) | |
{ | |
if (sort) | |
sort_phases(fname); | |
else if (phid) | |
dump_phids(fname); | |
else | |
dump_data(fname); | |
} | |
struct tag_card { | |
int phid, seq; | |
unsigned short card[80]; | |
}; | |
int cardcomp (const void *a, const void *b) | |
{ | |
short diff; | |
diff = ((struct tag_card *) a)->phid - ((struct tag_card *) b)->phid; | |
return diff ? diff : (((struct tag_card *) a)->seq - ((struct tag_card *) b)->seq); | |
} | |
void sort_phases (char *fname) | |
{ | |
int i, ncards, cardtype, len, seq = 0, phid; | |
struct tag_card *deck; | |
FILE *fd; | |
BOOL saw_sbrk = TRUE; | |
if ((fd = fopen(fname, "rb")) == NULL) { | |
perror(fname); | |
return; | |
} | |
fseek(fd, 0, SEEK_END); | |
len = ftell(fd); // get length of file | |
fseek(fd, 0, SEEK_SET); | |
if (len <= 0 || (len % 160) != 0) { | |
fprintf(stderr, "%s is not a binard deck image\n"); | |
fclose(fd); | |
return; | |
} | |
ncards = len / 160; | |
if ((deck = (struct tag_card *) malloc(ncards*sizeof(struct tag_card))) == NULL) { | |
fprintf(stderr, "%s: can't sort, insufficient memory\n"); | |
fclose(fd); | |
return; | |
} | |
phid = 0; | |
for (i = 0; i < ncards; i++) { | |
if (fread(deck[i].card, sizeof(card[0]), 80, fd) != 80) { | |
free(deck); | |
fprintf(stderr, "%s: error reading deck\n"); | |
fclose(fd); | |
return; | |
} | |
unpack(deck[i].card, buf); | |
deck[i].seq = seq++; | |
deck[i].phid = phid; | |
verify_checksum(buf); | |
cardtype = (buf[2] >> 8) & 0xFF; | |
if (cardtype == 1 || cardtype == 2) { // start of deck is same as sector break | |
saw_sbrk = TRUE; | |
} | |
else if (cardtype == 0) { | |
fprintf(stderr, "%s is a core image deck\n"); | |
free(deck); | |
fclose(fd); | |
return; | |
} | |
else if (cardtype == 0x0A && saw_sbrk) { | |
phid = (int) (signed short) buf[10]; | |
if (phid < 0) | |
phid = -phid; | |
deck[i].phid = phid; // this belongs to the new phase | |
deck[i-1].phid = phid; // as does previous card | |
saw_sbrk = FALSE; | |
} | |
} | |
fclose(fd); | |
qsort(deck, ncards, sizeof(struct tag_card), cardcomp); // sort the deck | |
#ifdef WIN32 | |
_setmode(_fileno(stdout), _O_BINARY); // set standard output to binary mode | |
#endif | |
for (i = 0; i < ncards; i++) // write to stdout | |
fwrite(deck[i].card, sizeof(card[0]), 80, stdout); | |
free(deck); | |
} | |
void dump_phids (char *fname) | |
{ | |
FILE *fp; | |
BOOL first = TRUE; | |
BOOL saw_sbrk = TRUE, neg; | |
short id; | |
if ((fp = fopen(fname, "rb")) == NULL) { | |
perror(fname); | |
return; | |
} | |
printf("\n%s:\n", fname); | |
while (fread(card, sizeof(card[0]), 80, fp) > 0) { | |
unpack(card, buf); | |
verify_checksum(buf); | |
cardtype = (buf[2] >> 8) & 0xFF; | |
if (cardtype == 1 && ! first) { // sector break | |
saw_sbrk = TRUE; | |
continue; | |
} | |
else { | |
switch (cardtype) { | |
case 0x00: | |
printf(" This is a core image deck\n"); | |
goto done; | |
break; | |
case 0x01: | |
case 0x02: | |
case 0x03: | |
case 0x04: | |
case 0x05: | |
case 0x06: | |
case 0x07: | |
case 0x0F: | |
break; | |
case 0x0A: | |
if (saw_sbrk) { | |
id = buf[10]; | |
if (id < 0) | |
id = -id, neg = TRUE; | |
else | |
neg = FALSE; | |
printf(" : %3d / %02x%s\n", id, id, neg ? " (neg)" : ""); | |
saw_sbrk = FALSE; | |
} | |
break; | |
default: | |
show_raw("??? "); | |
} | |
} | |
done: | |
first = FALSE; | |
} | |
fclose(fp); | |
} | |
void dump_data (char *fname) | |
{ | |
FILE *fp; | |
BOOL first = TRUE; | |
char str[80]; | |
int i; | |
if ((fp = fopen(fname, "rb")) == NULL) { | |
perror(fname); | |
return; | |
} | |
printf("\n%s:\n", fname); | |
while (fread(card, sizeof(card[0]), 80, fp) > 0) { | |
unpack(card, buf); | |
verify_checksum(buf); | |
cardtype = (buf[2] >> 8) & 0xFF; | |
if (cardtype == 1 && ! first) { // sector break | |
for (i = 4; i < 72; i++) | |
str[i] = hollerith_to_ascii(card[i]); | |
str[i] = '\0'; | |
trim(str+4); | |
printf("*SBRK %s\n", str+4); | |
continue; | |
} | |
else { | |
switch (cardtype) { | |
case 0x00: | |
if (first) | |
show_raw("CORE"); | |
if (verbose) | |
show_core(); | |
break; | |
case 0x01: | |
show_raw("ABS "); | |
show_main(); | |
break; | |
case 0x02: | |
show_raw("REL "); | |
show_main(); | |
break; | |
case 0x03: | |
show_raw("LIB "); | |
show_sub(); | |
break; | |
case 0x04: | |
show_raw("SUB "); | |
show_sub(); | |
break; | |
case 0x05: | |
show_raw("ISSL"); | |
show_iss(); | |
break; | |
case 0x06: | |
show_raw("ISSC"); | |
show_iss(); | |
break; | |
case 0x07: | |
show_raw("ILS "); | |
show_ils(); | |
break; | |
case 0x0F: | |
show_raw("END "); | |
show_end(); | |
break; | |
case 0x80: | |
show_raw("ENDC"); | |
show_endc(); | |
break; | |
case 0x81: | |
show_raw("81 "); | |
show_81(); | |
break; | |
case 0x0A: | |
if (verbose) | |
show_data(); | |
break; | |
default: | |
show_raw("??? "); | |
} | |
} | |
first = FALSE; | |
} | |
fclose(fp); | |
} | |
void show_data (void) | |
{ | |
int i, n, jrel, rflag, nout, ch, reloc; | |
BOOL first = TRUE; | |
n = buf[2] & 0x00FF; | |
printf("%04x: ", buf[0]); | |
jrel = 3; | |
nout = 0; | |
rflag = buf[jrel++]; | |
for (i = 0; i < n; i++) { | |
if (nout >= 8) { | |
rflag = buf[jrel++]; | |
if (first) { | |
printf(" %s", getseq()); | |
first = FALSE; | |
} | |
printf("\n "); | |
nout = 0; | |
} | |
reloc = (rflag >> 14) & 0x03; | |
ch = (reloc == R_ABSOLUTE) ? ' ' : | |
(reloc == R_RELATIVE) ? 'R' : | |
(reloc == R_LIBF) ? 'L' : '@'; | |
printf("%04x%c ", buf[9+i], ch); | |
rflag <<= 2; | |
nout++; | |
} | |
putchar('\n'); | |
} | |
void show_core (void) | |
{ | |
int i, n, nout; | |
BOOL first = TRUE; | |
n = buf[2] & 0x00FF; | |
printf("%04x: ", buf[0]); | |
nout = 0; | |
for (i = 0; i < n; i++) { | |
if (nout >= 8) { | |
if (first) { | |
printf(" %s", getseq()); | |
first = FALSE; | |
} | |
printf("\n "); | |
nout = 0; | |
} | |
printf("%04x ", buf[9+i]); | |
nout++; | |
} | |
putchar('\n'); | |
} | |
void info (int i, char *nm, char type) | |
{ | |
if (nm) | |
printf("%s ", nm); | |
switch (type) { | |
case 'd': | |
printf("%d ", buf[i]); | |
break; | |
case 'x': | |
printf("%04x ", buf[i]); | |
break; | |
case 'b': | |
printf("%02x ", buf[i] & 0xFF); | |
break; | |
case 'n': | |
printf("%s ", getname(buf+i)); | |
break; | |
default: | |
bail("BAD TYPE"); | |
} | |
} | |
void show_main (void) | |
{ | |
printf(" "); | |
info(2, "prec", 'b'); | |
info(4, "common", 'd'); | |
info(6, "work", 'd'); | |
info(8, "files", 'd'); | |
info(9, "name", 'n'); | |
info(11, "pta", 'x'); | |
putchar('\n'); | |
} | |
void show_sub (void) | |
{ | |
int i, n; | |
printf(" "); | |
info( 2, "prec", 'b'); | |
n = buf[5] / 3; | |
for (i = 0; i < n; i++) { | |
info( 9+3*i, "ent", 'n'); | |
info(11+3*i, NULL, 'x'); | |
} | |
putchar('\n'); | |
} | |
void show_iss (void) | |
{ | |
printf(" "); | |
info(12, "level", 'd'); | |
putchar('\n'); | |
} | |
void show_ils (void) | |
{ | |
printf(" "); | |
info( 2, "prec", 'b'); | |
info( 5, "nint6", 'd'); | |
info( 9, "ent", 'n'); | |
info(11, NULL, 'x'); | |
info(14, "nint", 'd'); | |
info(15, "il1", 'd'); | |
info(16, "il2", 'd'); | |
putchar('\n'); | |
} | |
void show_end (void) | |
{ | |
printf(" "); | |
info(0, "size", 'd'); | |
info(3, "pta", 'x'); | |
putchar('\n'); | |
} | |
void show_endc(void) | |
{ | |
printf(" "); | |
info(52, "IX3", 'x'); | |
info(53, "pta", 'x'); | |
putchar('\n'); | |
} | |
void show_81(void) | |
{ | |
} | |
void show_raw (char *name) | |
{ | |
int i; | |
printf("*%s", name); | |
for (i = 0; i < 12; i++) | |
printf(" %04x", buf[i]); | |
printf(" %s\n", getseq()); | |
} | |
char * getseq (void) | |
{ | |
static char seq[10]; | |
int i; | |
for (i = 0; i < 8; i++) | |
seq[i] = hollerith_to_ascii(card[72+i]); | |
seq[i] = '\0'; | |
return seq; | |
} | |
void bail (char *msg) | |
{ | |
fprintf(stderr, "%s\n", msg); | |
exit(1); | |
} | |
void unpack (unsigned short *icard, unsigned short *obuf) | |
{ | |
int i, j; | |
unsigned short wd1, wd2, wd3, wd4; | |
for (i = j = 0; i < 54; i += 3, j += 4) { | |
wd1 = icard[j]; | |
wd2 = icard[j+1]; | |
wd3 = icard[j+2]; | |
wd4 = icard[j+3]; | |
obuf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F); | |
obuf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF); | |
obuf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF); | |
} | |
} | |
void verify_checksum (unsigned short *obuf) | |
{ | |
// unsigned short sum; | |
if (obuf[1] == 0) // no checksum | |
return; | |
// if (sum != card[1]) | |
// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]); | |
} | |
typedef struct { | |
unsigned short hollerith; | |
char ascii; | |
} CPCODE; | |
static CPCODE cardcode_029[] = | |
{ | |
0x0000, ' ', | |
0x8000, '&', // + in 026 Fortran | |
0x4000, '-', | |
0x2000, '0', | |
0x1000, '1', | |
0x0800, '2', | |
0x0400, '3', | |
0x0200, '4', | |
0x0100, '5', | |
0x0080, '6', | |
0x0040, '7', | |
0x0020, '8', | |
0x0010, '9', | |
0x9000, 'A', | |
0x8800, 'B', | |
0x8400, 'C', | |
0x8200, 'D', | |
0x8100, 'E', | |
0x8080, 'F', | |
0x8040, 'G', | |
0x8020, 'H', | |
0x8010, 'I', | |
0x5000, 'J', | |
0x4800, 'K', | |
0x4400, 'L', | |
0x4200, 'M', | |
0x4100, 'N', | |
0x4080, 'O', | |
0x4040, 'P', | |
0x4020, 'Q', | |
0x4010, 'R', | |
0x3000, '/', | |
0x2800, 'S', | |
0x2400, 'T', | |
0x2200, 'U', | |
0x2100, 'V', | |
0x2080, 'W', | |
0x2040, 'X', | |
0x2020, 'Y', | |
0x2010, 'Z', | |
0x0820, ':', | |
0x0420, '#', // = in 026 Fortran | |
0x0220, '@', // ' in 026 Fortran | |
0x0120, '\'', | |
0x00A0, '=', | |
0x0060, '"', | |
0x8820, 'c', // cent | |
0x8420, '.', | |
0x8220, '<', // ) in 026 Fortran | |
0x8120, '(', | |
0x80A0, '+', | |
0x8060, '|', | |
0x4820, '!', | |
0x4420, '$', | |
0x4220, '*', | |
0x4120, ')', | |
0x40A0, ';', | |
0x4060, 'n', // not | |
0x2820, 'x', // what? | |
0x2420, ',', | |
0x2220, '%', // ( in 026 Fortran | |
0x2120, '_', | |
0x20A0, '>', | |
0x2060, '>', | |
}; | |
int hollerith_to_ascii (unsigned short h) | |
{ | |
int i; | |
h &= 0xFFF0; | |
for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) | |
if (cardcode_029[i].hollerith == h) | |
return cardcode_029[i].ascii; | |
return '?'; | |
} | |
// --------------------------------------------------------------------------------- | |
// trim - remove trailing whitespace from string s | |
// --------------------------------------------------------------------------------- | |
void trim (char *s) | |
{ | |
char *nb; | |
for (nb = s-1; *s; s++) | |
if (*s > ' ') | |
nb = s; | |
nb[1] = '\0'; | |
} | |
int ascii_to_ebcdic_table[128] = | |
{ | |
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, | |
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, | |
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, | |
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, | |
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, | |
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, | |
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, | |
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, | |
}; | |
char *getname (unsigned short *ptr) | |
{ | |
static char str[6]; | |
int i, j, ch; | |
long v; | |
v = (ptr[0] << 16L) | ptr[1]; | |
for (i = 0; i < 5; i++) { | |
ch = ((v >> 24) & 0x3F) | 0xC0; // recover those lost two bits | |
v <<= 6; | |
str[i] = ' '; | |
for (j = 0; j < (sizeof(ascii_to_ebcdic_table)/sizeof(ascii_to_ebcdic_table[0])); j++) { | |
if (ascii_to_ebcdic_table[j] == ch) { | |
str[i] = j; | |
break; | |
} | |
} | |
} | |
str[5] = '\0'; | |
return str; | |
} | |