/* * (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 #include #ifdef _WIN32 # include # include # include #endif #include "util_io.h" #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; typedef enum {PACKED, UNPACKED} PACKMODE; #define CARDTYPE_COREIMAGE 0x00 #define CARDTYPE_ABS 0x01 #define CARDTYPE_REL 0x02 #define CARDTYPE_LIB 0x03 #define CARDTYPE_SUB 0x04 #define CARDTYPE_ISSL 0x05 #define CARDTYPE_ISSC 0x06 #define CARDTYPE_ILS 0x07 #define CARDTYPE_END 0x0F #define CARDTYPE_ENDC 0x80 #define CARDTYPE_81 0x81 #define CARDTYPE_DATA 0x0A BOOL verbose = FALSE; BOOL phid = FALSE; BOOL sort = FALSE; unsigned short card[80], buf[54]; // 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 *icard, unsigned short *obuf, int nwords); void pack (unsigned short *ocard, unsigned short *ibuf); void verify_checksum(unsigned short *buf); int type_of_card(unsigned short *buf, PACKMODE packed); char *card_type_name (unsigned short cardtype); 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 (ncards <= 0) { fprintf(stderr, "%s: can't sort, empty deck\n"); fclose(fd); return; } 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 (fxread(deck[i].card, sizeof(card[0]), 80, fd) != 80) { free(deck); fprintf(stderr, "%s: error reading deck\n"); fclose(fd); return; } deck[i].seq = seq++; // store current sequence deck[i].phid = phid; // store current phase ID cardtype = type_of_card(deck[i].card, PACKED); switch (cardtype) { case CARDTYPE_ABS: // start of deck is same as sector break saw_sbrk = TRUE; // (though I don't ever expect to get a REL deck) break; case CARDTYPE_DATA: if (saw_sbrk) { unpack(deck[i].card, buf, 0); verify_checksum(buf); 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 (START or SBRK card) saw_sbrk = FALSE; } break; case CARDTYPE_END: break; default: fprintf(stderr, "%s is a %s deck, can't sort\n", card_type_name(cardtype)); free(deck); fclose(fd); return; } } 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 cardtype = type_of_card(deck[i].card, PACKED); if (cardtype != CARDTYPE_END || (i == (ncards-1))) // don't write embedded END cards fxwrite(deck[i].card, sizeof(deck[i].card[0]), 80, stdout); } if (cardtype != CARDTYPE_END) { // fudge an end card memset(buf, 0, sizeof(buf)); buf[2] = CARDTYPE_END; pack(card, buf); fxwrite(card, sizeof(card[0]), 80, stdout); } free(deck); } void dump_phids (char *fname) { FILE *fp; BOOL saw_sbrk = FALSE, neg; unsigned short cardtype; short id; if ((fp = fopen(fname, "rb")) == NULL) { perror(fname); return; } printf("\n%s:\n", fname); while (fxread(card, sizeof(card[0]), 80, fp) > 0) { cardtype = type_of_card(card, PACKED); if (saw_sbrk && cardtype != CARDTYPE_DATA) { printf("DECK STRUCTURE ERROR: ABS/SBRK card was followed by %s, not DATA", card_type_name(cardtype)); } switch (cardtype) { case CARDTYPE_ABS: // beginning of absolute deck, or SBRK card (which spoofs an ABS start card) saw_sbrk = TRUE; break; case CARDTYPE_END: break; case CARDTYPE_DATA: if (saw_sbrk) { // first data card after a SBRK or new deck has the phase ID unpack(card, buf, 11); 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; case CARDTYPE_COREIMAGE: case CARDTYPE_REL: case CARDTYPE_LIB: case CARDTYPE_SUB: case CARDTYPE_ISSL: case CARDTYPE_ISSC: case CARDTYPE_ILS: printf("%s module not expected in a system load deck\n", card_type_name(cardtype)); break; default: show_raw("??? "); } } fclose(fp); } void dump_data (char *fname) { FILE *fp; BOOL first = TRUE; unsigned short cardtype; char str[80]; int i; if ((fp = fopen(fname, "rb")) == NULL) { perror(fname); return; } printf("\n%s:\n", fname); while (fxread(card, sizeof(card[0]), 80, fp) > 0) { unpack(card, buf, 0); verify_checksum(buf); cardtype = type_of_card(buf, UNPACKED); 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 CARDTYPE_COREIMAGE: if (first) show_raw("CORE"); if (verbose) show_core(); break; case CARDTYPE_ABS: show_raw("ABS "); show_main(); break; case CARDTYPE_REL: show_raw("REL "); show_main(); break; case CARDTYPE_LIB: show_raw("LIB "); show_sub(); break; case CARDTYPE_SUB: show_raw("SUB "); show_sub(); break; case CARDTYPE_ISSL: show_raw("ISSL"); show_iss(); break; case CARDTYPE_ISSC: show_raw("ISSC"); show_iss(); break; case CARDTYPE_ILS: show_raw("ILS "); show_ils(); break; case CARDTYPE_END: show_raw("END "); show_end(); break; case CARDTYPE_ENDC: show_raw("ENDC"); show_endc(); break; case CARDTYPE_81: show_raw("81 "); show_81(); break; case CARDTYPE_DATA: 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); } // unpack nwords of data from card image icard into buffer obuf void unpack (unsigned short *icard, unsigned short *obuf, int nwords) { int i, j; unsigned short wd1, wd2, wd3, wd4; if (nwords <= 0 || nwords > 54) nwords = 54; // the default is to unpack all 54 words for (i = j = 0; i < nwords; i++) { wd1 = icard[j++]; wd2 = icard[j++]; wd3 = icard[j++]; wd4 = icard[j++]; obuf[i] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F); if (++i >= nwords) break; obuf[i] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF); if (++i >= nwords) break; obuf[i] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF); } } // pack - pack 54 words of data in ibuf into card image icard void pack (unsigned short *ocard, unsigned short *ibuf) { int i, j; for (i = j = 0; i < 54; i += 3, j += 4) { ocard[j ] = ( ibuf[i] & 0xFFF0); ocard[j+1] = ((ibuf[i] << 12) & 0xF000) | ((ibuf[i+1] >> 4) & 0x0FF0); ocard[j+2] = ((ibuf[i+1] << 8) & 0xFF00) | ((ibuf[i+2] >> 8) & 0x00F0); ocard[j+3] = ((ibuf[i+2] << 4) & 0xFFF0); } } 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; } int type_of_card (unsigned short *buf, PACKMODE packed) { unsigned short unp[3]; // card type is the 3rd unpacked word on the card if (packed == PACKED) { unpack(buf, unp, 3); // unpack the first 3 words only buf = unp; } return (buf[2] >> 8) & 0xFF; } char * card_type_name (unsigned short cardtype) { switch (cardtype) { case CARDTYPE_COREIMAGE: return "core image"; case CARDTYPE_ABS: return "absolute"; case CARDTYPE_REL: return "relative"; case CARDTYPE_LIB: return "LIB"; case CARDTYPE_SUB: return "SUB"; case CARDTYPE_ISSL: return "ISSL"; case CARDTYPE_ISSC: return "ISSC"; case CARDTYPE_ILS: return "ILS"; case CARDTYPE_END: return "END"; case CARDTYPE_ENDC: return "ENDC"; case CARDTYPE_81: return "81"; case CARDTYPE_DATA: return "data"; } return "unknown"; }