/************************************************************************* Copyright (c) 1984 by Nick de Smith This software is supplied for interest and non-profit making purposes only. Under no circumstance shall it be lent, copied or otherwise used for profit. All rights regarding the use and ownership of this software shall at all times remain with the author, who does not guarantee the accuracy or reliabilty of this software and who will not accept any liability for its use. This software may not be copied or distributed without the inclusion of the above copyright notice. January 31st 1984 *************************************************************************/ /************************************************************************* Program : STRIP.C Author : Nick de Smith December 1982 Description : Analyse a relocatable object file produced by either MAC.TSK or MACRO.SAV. Refer to TKB appendix A for an explanation of what is printed. This program will handle all knowen object record formats including complex relocation. *************************************************************************/ #define MAIN #define STRIP #define local static #include FILE *ip; /* Input filename */ char *version = "STRIP V1.4, Jan '84"; /* Version/id */ int debug; /* In debug mode */ int concat; /* Handle concatanated modules */ int eom; /* End of module flag */ int rec_num; /* Current record number */ char buff[7]; /* Expanded rad 50 buffer */ char wbuf[128]; /* Scratch working buffer */ char *w_ptr; /* Pointer into wbuf */ #define MAX_RECLEN 512 /* Absolute max buffer length */ typedef struct buffer { int b_next; /* Pointer to next byte */ int b_left; /* Number of bytes left */ int b_length; /* Length of record */ char b_text[MAX_RECLEN]; /* Actual data */ } BUFFER, *BUFFER_PTR; BUFFER buff_1; /* Input buffer */ BUFFER_PTR b_ptr = &buff_1; /* Pointer to ip buffer */ /************************************************************************* * * * o b j e c t r e c o r d t y p e s * ----------------------------------------- * * *************************************************************************/ #define T_GSD 01 /* Global symbol directory */ #define T_EGSD 02 /* End of GSD */ #define T_TEXT 03 /* Text information */ #define T_RELD 04 /* Relocation directory */ #define T_ISD 05 /* Internal symbol directory */ #define T_EOM 06 /* End of module */ char *rec_text[] = { "", "Declare global symbol directory", "End of global symbol directory", "Text information", "Relocation directory", "Internal symbol directory", "End of module" }; /************************************************************************* * * * g l o b a l s y m b o l d i r e c t o r y * ------------------------------------------------- * * *************************************************************************/ typedef struct { char *bitclr; /* Text if bit is clear */ char *bitset; /* Text if bit is set */ } BIT_TEXT; #define T_MODN 000 /* Module name */ #define T_CSECT 001 /* Control section name */ #define T_ISN 002 /* Internal symbol name */ #define T_TADDR 003 /* Transfer address */ #define T_GSN 004 /* Global symbol name */ BIT_TEXT gsn_flags[] = { "" , "Weak " , "" , "" , "" , "Lib " , "GS-Ref " , "GS-Def " , "" , "" , "Abs " , "Rel " , "" , "" , "" , "" }; #define T_PSECT 005 /* Program section name */ BIT_TEXT psect_flags[] = { "" , "Save " , "" , "Lib " , "Con " , "Ovr " , "" , "" , "RW " , "RO " , "Abs " , "Rel " , "Loc " , "Glo " , "I " , "D " }; #define T_IDENT 006 /* Program version id */ #define T_MARR 007 /* Mapped array declaration */ #define T_COMP 010 /* Completion routine address */ char *gsd_text[] = { "Module name", "Control section name", "Internal symbol name", "Transfer address", "Global symbol name", "Program section name", "Program version identification", "Mapped array declaration, Name", "Completion routine name" }; /************************************************************************* * * * r e l o c a t i o n d i r e c t o r y * ------------------------------------------ * * *************************************************************************/ #define T_IREL 001 /* Internal relocation */ #define T_GREL 002 /* Global relocation */ #define T_IDREL 003 /* Internal displaced relocation*/ #define T_GDREL 004 /* Global displaced relocation */ #define T_GAREL 005 /* Global additive relocation */ #define T_GADREL 006 /* Global additive disp. rel. */ #define T_LDEF 007 /* Location counter definition */ #define T_LMOD 010 /* Location counter modification*/ #define T_LIMIT 011 /* .LIMIT directive */ #define T_PREL 012 /* PSECT relocation */ #define T_PDREL 014 /* PSECT displaced relocation */ #define T_PAREL 015 /* PSECT additive relocation */ #define T_PADREL 016 /* PSECT additive disp. rel. */ #define T_CREL 017 /* Complex relocation (gosh!) */ #define T_RLREL 020 /* Resident library relocation */ char *cmd_text[] = { "", "Internal relocation, value = #", "Global relocation, symbol = #", "Internal displaced relocation, value = ", "Global displaced relocation, symbol = ", "Global additive relocation, expr = #", "Global additive displaced relocation, expr = ", "Location counter definition, PC = ", "Location counter modification, . = ", "Program limits, .LIMIT", "PSECT relocation, PSECT = #", "", "PSECT displaced relocation, PSECT = ", "PSECT additive relocation, PSECT+value = #", "PSECT additive displaced relocation, PSECT+value = ", "Complex relocation, expr ...\n", "Reslib/Task base relocation, value = base + " }; /************************************************************************* * * * c o m p l e x r e l o c a t i o n * ------------------------------------- * * *************************************************************************/ #define C_NOP 000 /* NOP */ #define C_PLUS 001 /* Binop plus */ #define C_MINUS 002 /* Binop minus */ #define C_MUL 003 /* Binop multiply */ #define C_DIV 004 /* Binop divide */ #define C_AND 005 /* Binop bitwise AND */ #define C_OR 006 /* Binop bitwise OR */ #define C_UMINUS 010 /* Unary op minus */ #define C_UCOMP 011 /* Unary op complement */ #define C_STORE 012 /* Store result */ #define C_DSTORE 013 /* Store result (displaced) */ #define C_FGLOB 016 /* Fetch global */ #define C_FREL 017 /* Fetch relocatable value */ #define C_FCONST 020 /* Fetch constant */ #define C_FRB 021 /* Fetch reslib/task base */ char *comp_text[] = { "", "+", "-", "*", "/", "&", "!", "", "-", "^C" }; int comp_prio[] = { 0, 1 , 1 , 1 , 1 , 1 , 1 , 0 , 5 , 5 }; #define MAX_C_LEN 128 /* Maximum length of one arg */ typedef struct c_elem { /* CREL atom */ int c_prio; /* Priority of this element */ char c_text[MAX_C_LEN]; /* Stacked text */ } C_ELEM; #define MAX_C_STACK 5 /* Depth of CREL eval stack */ C_ELEM c_stack[MAX_C_STACK]; /* CREL evaluation stack */ int c_sp; /* Index of c_stack[] */ /************************************************************************* * * * m a i n * ------- * * Main program start point. * *************************************************************************/ main(argc, argv) int argc; char *argv[]; { register int i,c; register char *p; char *file; file = NULL; for (i = 1; i < argc; ++i) { p = argv[i]; if (*p++ == '-') { while (c = *p++) { switch (isupper(c) ? tolower(c) : c) { case 'd': debug++; break; case 'c': concat++; break; default: usage(); } } } else if (file) usage(); else file = argv[i]; } if (!file) usage(); strip(file); } /************************************************************************* * * * s t r i p * --------- * * Analyse the internals of an object file. * *************************************************************************/ local strip(file) char *file; { open_file(file); do_header(file); rec_num = 0; eom = FALSE; while (!eom) { read_record(); process_record(); }; } /************************************************************************* * * * o p e n _ f i l e * ----------------- * * Open an object/stb file for read access. * *************************************************************************/ local open_file(file) char *file; { if (!(ip = fopen(file,"ru"))) error("Failed to open \"%s\"", file); } /************************************************************************* * * * d o _ h e a d e r * ----------------- * * Print the header for this run. * *************************************************************************/ local do_header(file) char *file; { char *ctime(); printf("Analysis of object file \"%s\" taken on %s\n", file, ctime(0)); printf("Produced by %s\n", version); } /************************************************************************* * * * p r o c e s s _ r e c o r d * --------------------------- * * Process an object record. * *************************************************************************/ local process_record() { int type; switch (type = next_word()) { case T_GSD: case T_EGSD: case T_TEXT: case T_RELD: case T_ISD: case T_EOM: printf("\n** %5d : %s\n", rec_num, rec_text[type]); break; default: bug("Bad object record, type = %o", type); } switch (type) { case T_GSD: dump_gsd(); break; case T_TEXT: dump_text(); break; case T_RELD: dump_reld(); break; case T_EOM: if (!concat) eom = TRUE; break; default: break; } } /************************************************************************* * * * d u m p _ g s d * --------------- * * Dump a GSD type record. * *************************************************************************/ local dump_gsd() { int flag, entry, value; char *bit_list(); while (b_ptr->b_left) { name_text(); flag = next_byte(); entry = next_byte(); value = next_word(); printf(" Entry : %s = %s", gsd_text[entry], buff); switch (entry) { case T_MODN: case T_IDENT: putchar('\n'); break; case T_CSECT: case T_COMP: printf(", maximum length = %o\n", value); break; case T_ISN: case T_TADDR: printf(", offset = %06o\n", value); break; case T_GSN: printf(", value = %06o, flags = %s\n", value, bit_list(gsn_flags,flag)); break; case T_MARR: printf(", value = %06o, flags = %3o\n", value, flag); break; case T_PSECT: printf(", maximum length = %06o, flags = %s\n", value, bit_list(psect_flags,flag)); break; } } } /************************************************************************* * * * d u m p _ t e x t * ----------------- * * Dump a text record. * *************************************************************************/ local dump_text() { register int i; i = 0; printf(" Load address = %o\n", next_word()); while (b_ptr->b_left) { i++; if (b_ptr->b_left > 1) printf(" %06o", next_word()); else printf(" %03o", next_byte()); if (!(i & 7)) putchar('\n'); } if (i & 7) putchar('\n'); } /************************************************************************* * * * d u m p _ r e l d * ----------------- * * Dump a reloaction directory record. * *************************************************************************/ local dump_reld() { int command, displacement; while (b_ptr->b_left) { command = next_byte(); displacement = next_byte(); printf(" Disp = %3o", displacement); if (command & 128) { printf(", (byte)"); command &= 127; } printf(", Command = %s", cmd_text[command]); switch (command) { case T_IREL: case T_IDREL: case T_LMOD: case T_RLREL: printf("%o\n", next_word()); break; case T_GREL: case T_GDREL: case T_PREL: case T_PDREL: name_text(); printf("%s\n", buff); break; case T_GAREL: case T_GADREL: case T_LDEF: case T_PAREL: case T_PADREL: name_min(); printf("%s+%o\n", buff, next_word()); break; case T_LIMIT: putchar('\n'); break; case T_CREL: eval_crel(); break; default: bug("Bad relocation command, %o", command); } } } /************************************************************************* * * * e v a l _ c r e l * ----------------- * * Evaluate a complex relocation RLD entry. * *************************************************************************/ local eval_crel() { register int type, i; register char *temp; int j; c_sp = 0; while ((type = next_byte()) != C_STORE && type != C_DSTORE) { switch (type) { case C_NOP: if (debug) printf(" NOP\n"); break; case C_PLUS: case C_MINUS: case C_MUL: case C_DIV: case C_AND: case C_OR: temp = cpystr(wbuf, c_stack[c_sp -= 2].c_text); temp = cpystr(temp, comp_text[type]); if (comp_prio[type] >= c_stack[++c_sp].c_prio) *temp++ = '<'; temp = cpystr(temp, c_stack[c_sp].c_text); if (comp_prio[type] >= c_stack[c_sp--].c_prio) *temp++ = '>'; *temp = '\0'; cpystr(c_stack[c_sp].c_text, wbuf); c_stack[c_sp++].c_prio = comp_prio[type]; if (debug) printf(" Binop '%s'\n", comp_text[type]); break; case C_UMINUS: case C_UCOMP: temp = cpystr(wbuf, comp_text[type]); if (comp_prio[type] > c_stack[--c_sp].c_prio) *temp++ = '<'; temp = cpystr(temp, c_stack[c_sp].c_text); if (comp_prio[type] > c_stack[c_sp].c_prio) *temp++ = '>'; *temp = '\0'; cpystr(c_stack[c_sp].c_text, wbuf); c_stack[c_sp++].c_prio = comp_prio[type]; if (debug) printf(" Unary op '%s'\n", comp_text[type]); break; case C_FGLOB: name_min(); cpystr(c_stack[c_sp].c_text, buff); c_stack[c_sp++].c_prio = 10; if (debug) printf(" Fetch global %s\n", buff); break; case C_FREL: i = next_byte(); sprintf(c_stack[c_sp].c_text, "{%03o:%o}", i, j = next_two_bytes()); c_stack[c_sp++].c_prio = 10; if (debug) printf(" Fetch relocatable value, Seg %03o, offset %o\n", i, j); break; case C_FCONST: sprintf(c_stack[c_sp].c_text, "%o", i = next_two_bytes()); c_stack[c_sp++].c_prio = 10; if (debug) printf(" Fetch constant %o\n", i); break; case C_FRB: sprintf(c_stack[c_sp].c_text, "%s", "{reslib/task base}"); c_stack[c_sp++].c_prio = 10; if (debug) printf(" Fetch reslib/task base\n"); break; default: bug("Bad complex reclocation entry, %o", type); } } if (c_sp != 1) printf("** Invalid RPN expression\n"); for (i = 0; i < c_sp; i++) if (!strlen(c_stack[i].c_text)) printf(" ** Null **\n"); else printf(" %s\n", c_stack[i].c_text); } /************************************************************************* * * * b i t _ l i s t * --------------- * * Return a pointer to a buffer containing a list of bits of text. * *************************************************************************/ local char * bit_list(bit_text, flags) BIT_TEXT bit_text[]; register int flags; { register int i; arg_i(); for (i = 0; i <= 7 ; i++ ) arg_s(flags & 1<"); } /************************************************************************* * * * a r g _ i * --------- * * Initialise the argument working buffer. * *************************************************************************/ local arg_i() { w_ptr = wbuf; *w_ptr = '\0'; } /************************************************************************* * * * a r g _ n * --------- * * Return the number of characters in the argument buffer. * *************************************************************************/ local arg_n() { return(w_ptr - wbuf); } /************************************************************************* * * * a r g _ s * --------- * * Put a string into the argument working buffer. * *************************************************************************/ local arg_s(t_ptr) register char *t_ptr; { while (*t_ptr) *w_ptr++ = *t_ptr++; *w_ptr = '\0'; } /************************************************************************* * * * r e a d _ r e c o r d * --------------------- * * Read the next input record. * *************************************************************************/ local read_record() { b_ptr->b_left = b_ptr->b_length = fget(b_ptr->b_text, MAX_RECLEN, ip); b_ptr->b_next = 0; if (feof(ip)) bug("End of input file"); rec_num += 1; } /************************************************************************* * * * n e x t _ b y t e * ----------------- * * Get the next byte from the current input record. * *************************************************************************/ local next_byte() { b_ptr->b_left--; return(b_ptr->b_text[b_ptr->b_next++] & 0377); } /************************************************************************* * * * n e x t _ w o r d * ------------------ * * Get the next aligned word from the current input record. * *************************************************************************/ local next_word() { b_ptr->b_next += (b_ptr->b_next & 1); /* Align to next word */ b_ptr->b_left = b_ptr->b_length - b_ptr->b_next; return(next_two_bytes(b_ptr)); } /************************************************************************* * * * n e x t _ t w o _ b y t e s * --------------------------- * * Get the next two bytes from the current input record as * a non-aligned word. * *************************************************************************/ local next_two_bytes() { register int temp; temp = next_byte(); /* Force order of evaluation */ return ( temp | ( 0400 * next_byte() ) ); } /************************************************************************* * * * n a m e _ t e x t * ----------------- * * Get an un-aligned name from the current input record. * *************************************************************************/ local name_text() { int tbuff[2]; tbuff[0] = next_two_bytes(); tbuff[1] = next_two_bytes(); r50toa(buff, tbuff, 2); return(buff[6] = 0); } /************************************************************************* * * * n a m e _ m i n * --------------- * * Get an un-aligned name from the current input record. Ignore * all trailing spaces. * *************************************************************************/ local name_min() { int tbuff[2]; tbuff[0] = next_two_bytes(); tbuff[1] = next_two_bytes(); radmin(tbuff); } /************************************************************************* * * * r a d m i n * ----------- * * Convert two radix 50 integers into ascii text. Trailing spaces * are removed. * *************************************************************************/ local radmin(i_ptr) register int *i_ptr; { register char *t_ptr; r50toa(buff, i_ptr, 2); t_ptr = &buff[6]; while (t_ptr != &buff[0] && *--t_ptr == '\040') ; if (*t_ptr != '\040') t_ptr++; *t_ptr = '\0'; } /************************************************************************* * * * u s a g e * --------- * * How to luse this utility. * *************************************************************************/ local usage() { error("Usage: strip -c file.ext"); } /************************************************************************* * * * b u g * ----- * * Report a BUG (well.. a mis-feature actually!) * *************************************************************************/ local bug(args) { error("*STRIP* -F- at record %d, %r", rec_num, &args); }