/* * dis_e386: disassemble 386 executable files. * * $Id: dise.c,v 1.1 1997/10/20 12:00:00 cwr Exp cwr $ * * Written by C W Rose. */ /* Version settings */ #define MINIX #undef OS2 #undef TEST #ifdef MINIX #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef S_ABS /* used in a.out.h */ #include "out.h" /* ACK compiler output header */ #undef EXTERN #define EXTERN #include "dis386.h" /* dis386 header */ #endif #ifdef OS2 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef S_ABS /* used in a.out.h */ #include "out.h" /* ACK compiler output header */ #undef EXTERN #define EXTERN #include "dis386.h" /* dis386 header */ #endif /* Standard defines */ #define FALSE 0 #undef TRUE #define TRUE !FALSE #define FAILED -1 #define MAYBE 0 #define OK 1 #define SAME 0 /* Local defines */ #define L_BUFF_LEN 1024 #define BUFF_LEN 256 #define S_BUFF_LEN 20 #define L_BUFF_MAX (L_BUFF_LEN-1) #define BUFF_MAX (BUFF_LEN-1) #define S_BUFF_MAX (S_BUFF_LEN-1) #define PSEP '\\' #define AOUT "a.out" #define CORE "core" #define STAB "symbol.tab" #define LINE_LEN 16 #define SYMLEN 8 #define TEXT 0 /* section indices for locsym[] */ #define ROM 1 #define DATA 2 #define BSS 3 #ifndef lint static char *Version = "@(#) dis_e386.c $Revision: 1.1 $ $Date: 1997/10/20 12:00:00 $"; #endif /* Global variables */ int opt_C = FALSE; /* core file name */ int opt_E = FALSE; /* executable file name */ int opt_O = FALSE; /* object file name */ int opt_S = FALSE; /* symbol table name */ int opt_a = FALSE; /* dump tables and disassemble segments */ int opt_b = FALSE; /* dump straight binary */ int opt_d = FALSE; /* dump the data segment */ int opt_f = FALSE; /* first address of dump */ int opt_h = FALSE; /* dump the header structure */ int opt_l = FALSE; /* last address of dump */ int opt_m = FALSE; /* dump the rom segment */ int opt_n = FALSE; /* dump the symbol names */ int opt_r = FALSE; /* dump the relocation structures */ int opt_s = FALSE; /* dump the symbol table */ int opt_t = FALSE; /* dump the text segment */ int opt_u = FALSE; /* dump the bss segment */ int opt_x = FALSE; /* debugging flag */ char progname[BUFF_LEN]; /* program name */ int dbglvl = 0; /* debugging level */ struct a_sec { /* a.out section data */ char *name; /* section name */ int first; /* first index */ int last; /* last index */ int total; } a_sectab[] = { /* all known a.out sections */ "undefined", 0, 0, 0, "absolute", 0, 0, 0, "text", 0, 0, 0, "data", 0, 0, 0, "bss", 0, 0, 0, "common", 0, 0, 0, "rom", 0, 0, 0, /* this one is unknown */ (char *)NULL, 0, 0, 0 }; /* Forward declarations */ unsigned long atoaddr(char *); /* Convert ascii hex/dec to unsigned long */ int binary(unsigned char, char*); /* Binary output of 8-bit number */ int dump_ahdr(struct exec *ep); /* Dump an a.out file header */ int dump_adata(FILE *fp, int start, int count); /* Dump an a.out file data section */ int dump_asym(struct nlist *np, int start, int count); /* Dump an a.out file symbol table */ int dump_hex(FILE *fp, int start, int count); /* Dump bytes in hex and ascii */ int find_asym(long value, int section); /* Find an a.out symbol */ int gen_locsym(FILE *fp, int sec); /* Generate local symbols */ int init_aout(FILE *fp); /* Initialise the a.out file tables */ void usage(void); /* Usage message */ /* * a t o a d d r * * Convert ascii hex/dec to unsigned long. * * Returns: Conversion result Always */ unsigned long atoaddr(char *sp) { char c, *cp, buff[S_BUFF_LEN]; int j; unsigned long int result = 0; /* flip to upper */ for (j = 0 ; j < S_BUFF_MAX && *(sp + j) != '\0' ; j++) buff[j] = toupper(*(sp + j)); buff[j] = '\0'; /* lose leading whitespace */ cp = buff; while isspace(*cp) cp++; /* check for hexadecimal entry */ if (*cp == '0' && *(cp + 1) == 'X') { cp += 2; while (isxdigit(*cp)) { c = *cp++; j = (c < 'A') ? c - '0' : c - 'A' + 10; result = (result << 4) + (c < 'A' ? c - '0' : c - 'A' + 10); } } else result = atol(buff); return result; } /* * b i n a r y * * Produce a binary representation of an 8-bit number. * * Returns: 0 Always */ int binary(unsigned char uc, char *sp) { int j; unsigned char k; for (k = 0x80, j = 0 ; j < 8 ; j++) { if ((uc & k) == 0) *sp++ = '0'; else *sp++ = '1'; if (j == 3) *sp++ = '$'; k >>= 1; } *sp = '\0'; return(0); } /* * d u m p _ a h d r * * Dump an a.out file header. * * Returns: OK Always */ int dump_ahdr(struct exec *ep) { char buff[BUFF_LEN]; fprintf(stdout, "Magic number is: 0x%02x%02x\n", ep->a_magic[0], ep->a_magic[1]); sprintf(buff, "Flags are: 0x%02x", ep->a_flags); if (ep->a_flags & A_UZP) strcat(buff, " A_UZP"); if (ep->a_flags & A_PAL) strcat(buff, " A_PAL"); if (ep->a_flags & A_NSYM) strcat(buff, " A_NSYM"); if (ep->a_flags & A_EXEC) strcat(buff, " A_EXEC"); if (ep->a_flags & A_SEP) strcat(buff, " A_SEP"); if (ep->a_flags & A_PURE) strcat(buff, " A_PURE"); if (ep->a_flags & A_TOVLY) strcat(buff, " A_TOVLY"); if (ep->a_flags & ~(A_UZP | A_PAL | A_NSYM | A_EXEC | A_SEP | A_PURE | A_TOVLY)) strcat(buff, " UNKNOWN"); fprintf(stdout, "%s\n", buff); sprintf(buff, "CPU type is: 0x%02x", ep->a_cpu); if (ep->a_cpu == A_NONE) strcat(buff, " A_NONE"); else if (ep->a_cpu == A_I8086) strcat(buff, " A_I8086"); else if (ep->a_cpu == A_M68K) strcat(buff, " A_M68K"); else if (ep->a_cpu == A_NS16K) strcat(buff, " A_NS16K"); else if (ep->a_cpu == A_I80386) strcat(buff, " A_I80386"); else if (ep->a_cpu == A_SPARC) strcat(buff, " A_SPARC"); else strcat(buff, " UNKNOWN"); fprintf(stdout, "%s\n", buff); fprintf(stdout, "Byte order is: %s\n", A_BLR(ep->a_cpu) ? "left to right" : "right to left"); fprintf(stdout, "Word order is: %s\n", A_WLR(ep->a_cpu) ? "left to right" : "right to left"); fprintf(stdout, "Header length is: 0x%02x\n", ep->a_hdrlen); fprintf(stdout, "Reserved byte is: 0x%02x\n", ep->a_unused); fprintf(stdout, "Version stamp is: 0x%04x\n", ep->a_version); fprintf(stdout, "Size of text segment is: 0x%08.8x\n", ep->a_text); fprintf(stdout, "Size of data segment is: 0x%08.8x\n", ep->a_data); fprintf(stdout, "Size of bss segment is: 0x%08.8x\n", ep->a_bss); fprintf(stdout, "Entry point is: 0x%08.8x\n", ep->a_entry); fprintf(stdout, "Total memory allocated is: 0x%08.8x\n", ep->a_total); fprintf(stdout, "Size of symbol table is: 0x%08.8x bytes, %d entries\n", ep->a_syms, ep->a_syms / sizeof(struct nlist)); /* SHORT FORM ENDS HERE */ #if 0 fprintf(stdout, "Size of text relocation is 0x%08.8x\n", ep->a_trsize); fprintf(stdout, "Size of data relocation is 0x%08.8x\n", ep->a_drsize); fprintf(stdout, "Base of text relocation is 0x%08.8x\n", ep->a_tbase); fprintf(stdout, "Base of data relocation is 0x%08.8x\n", ep->a_dbase); #endif return(OK); } /* * d u m p _ a d a t a * * Dump an a.out data section. * * Returns: OK Success * FAILED File read failure, invalid arguments * * The a_hdrbuf structure is read to determine section addresses. * The a_symtab structure is read to determine symbol names (if available). */ int dump_adata(FILE *fp, int start, int count) { char label[S_BUFF_LEN], data[S_BUFF_LEN], buff[BUFF_LEN]; char *hex = "0123456789ABCDEF"; int j, k, newflg, index, last, status, found, quit; long int addr; unsigned long int ulj; struct locname *np; if (start < 0 || (start + count) > (A_SYMPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen)) return(FAILED); ulj = start; quit = FALSE; status = OK; for (addr = start ; addr < (start + count) ; addr += 16) { /* get a line's worth of data */ for (j = 0 ; j < 16 ; j++) { if (j == (start + count - addr)) { quit = TRUE; break; } if ((k = fgetc(fp)) == EOF) { status = FAILED; quit = TRUE; break; } data[j] = (char)k; } /* adjust for an unexpected EOF */ if (quit && status == FAILED) { if (j == 0) break; else j--; } last = j; /* write out the address and clear the rest of the buffer */ sprintf(buff, "%06lx", ulj); for (k = strlen(buff) ; k < BUFF_MAX ; k++) buff[k] = ' '; /* build the hex and ascii data representations */ newflg = TRUE; found = FALSE; for (j = 0 ; j < last ; j++ ) { /* find a local symbol, one per address */ for (np = locsym[DATA] ; !found && np != (struct locname *)NULL ; np = np->l_next) { if (ulj == np->l_value) { /* write out any outstanding data */ if (j != 0) { buff[75] = '\0'; fprintf(stdout, "%s\n", buff); for (k = 8 ; k < 75 ; k++) buff[k] = ' '; } /* write out the symbol name */ for (k = 0 ; k < 8 ; k++) label[k] = np->l_name[k]; label[k] = '\0'; fprintf(stdout, "%s\n", label); found = TRUE; } } /* find any global symbols, several per address */ while (!found && (index = find_asym(ulj, N_DATA)) != -1) { /* for the first symbol, write out any outstanding data */ if (newflg && j != 0) { buff[75] = '\0'; fprintf(stdout, "%s\n", buff); for (k = 8 ; k < 75 ; k++) buff[k] = ' '; newflg = FALSE; } /* write out the symbol name */ for (k = 0 ; k < 8 ; k++) label[k] = a_symtab[index].n_name[k]; label[k] = '\0'; /* for some reason, some table entries are empty */ if (label[0] != '\0') fprintf(stdout, "%s\n", label); } /* set up for the next pass */ newflg = TRUE; found = FALSE; ulj++; /* hex digits */ buff[8 + (3 * j) + (j < 8 ? 0 : 2)] = hex[(data[j] >> 4) & 0x0f]; buff[9 + (3 * j) + (j < 8 ? 0 : 2)] = hex[data[j] & 0x0f]; /* ascii conversion */ if (data[j] < 32 || data[j] > 127) buff[59 + j] = '.'; else buff[59 + j] = data[j]; if (j == 8) buff[32] = '-'; } buff[75] = '\0'; /* write out the result */ fprintf(stdout, "%s\n", buff); if (quit) break; } return(status); } /* * d u m p _ a s y m * * Dump an a.out file symbol table. * * Returns: OK Success * FAILED Invalid arguments * * The a_hdrbuf structure is read to determine section addresses. */ int dump_asym(struct nlist *np, int start, int count) { char buff[BUFF_LEN], data[S_BUFF_LEN]; unsigned char uc; int j, k; if (start < 0 || (start + count) > (a_hdrbuf.a_syms / sizeof(struct nlist))) return(FAILED); for (j = start ; j < (start + count) ; j++) { sprintf(buff, "%-4d ", j); for (k = 0 ; k < SYMLEN ; k++) data[k] = (np[j].n_name[k] == '\0') ? ' ' : np[j].n_name[k]; data[k] = '\0'; strcat(buff, data); sprintf(data, " Val: 0x%08x", np[j].n_value); strcat(buff, data); sprintf(data, " Sto: 0x%02x", np[j].n_sclass); strcat(buff, data); uc = np[j].n_sclass; if ((uc & N_SECT) == N_UNDF) strcat(buff, " N_UNDF"); else if ((uc & N_SECT) == N_ABS) strcat(buff, " N_ABS "); else if ((uc & N_SECT) == N_TEXT) strcat(buff, " N_TEXT"); else if ((uc & N_SECT) == N_DATA) strcat(buff, " N_DATA"); else if ((uc & N_SECT) == N_BSS) strcat(buff, " N_BSS "); else if ((uc & N_SECT) == N_COMM) strcat(buff, " N_COMM"); else strcat(buff, " UNKNOWN"); if ((uc & N_CLASS) == 0) strcat(buff, " C_NULL"); else if ((uc & N_CLASS) == C_EXT) strcat(buff, " C_EXT "); else if ((uc & N_CLASS) == C_STAT) strcat(buff, " C_STAT"); else strcat(buff, " UNKNOWN"); sprintf(data, " Aux: 0x%02x", np[j].n_numaux); strcat(buff, data); sprintf(data, " Typ: 0x%04x", np[j].n_type); strcat(buff, data); fprintf(stdout, "%s\n", buff); } return(OK); } /* * d u m p _ h e x * * Dump bytes in hex and ascii. * * Returns: OK Success * FAILED File read failure, invalid arguments */ int dump_hex(FILE *fp, int start, int count) { char c, buff[S_BUFF_LEN]; int j, k, status, quit, last; unsigned long int ulj; if (start < 0) return(FAILED); ulj = 0; quit = FALSE; status = OK; while (TRUE) { /* get 16 bytes of data */ for (j = 0 ; j < 16 ; j++) { if ((k = fgetc(fp)) == EOF) { quit = TRUE; break; } else buff[j] = (char)k; } /* set up to dump any remaining data */ if (quit) { status = FAILED; if (j == 0) break; else j--; } last = j; /* print the address */ fprintf(stdout, "%06lx ", start + ulj); ulj += 16; if (ulj >= count) { quit = TRUE; if (last == 16) last = (count - 1) % 16; } /* print a line of hex data */ for (j = 0 ; j < 16 ; j++ ) { if (j <= last) fprintf(stdout, " %02x", buff[j] & 0xff); else fprintf(stdout, " "); if (j == 7) fprintf(stdout, " -"); } /* print a trailer of ascii data */ fprintf(stdout, " "); for (j = 0 ; j < 16 ; j++ ) { if (j <= last) c = buff[j]; else c = ' '; if (c < 32 || c > 127) c = '.'; (void) fputc(c, stdout); } fprintf(stdout, "\n"); if (quit) break; } return(status); } /* * f i n d _ a s y m * * Find an a.out symbol index in a sorted list. * There may be several symbols with the same value: * return the first in the sequence. * * Returns: index Success * -1 Failure * * The a_sectab structure is read to determine section indices. * The a_symtab structure is read to determine symbol names. */ int find_asym(long value, int sec) { static int index = 0; static long oldval = 0; static int oldsec = 0; int j; /* check for a repeated search */ if (value != oldval || sec != oldsec) { oldval = value; oldsec = sec; index = a_sectab[sec].first; } /* never happen */ else if (index == -1) return(FAILED); /* do a linear search for a symbol, since repeated searches may be needed */ for (j = index ; j < a_sectab[sec].last ; j++) { if (value == a_symtab[j].n_value) break; } /* set up the index for the next pass */ if (j == a_sectab[sec].last) { index = a_sectab[sec].first; return(-1); } else { index = j + 1; return(j); } /* NOTREACHED */ } /* * g e n _ l o c s y m * * Generate local symbols. * * Returns: OK Success * FAILED Invalid arguments, malloc failure * * This works only for data and bss segments. Text symbols need * a disassembly of the text section, and intelligent guesses as * to whether a local address refers to text or data. In fact, * this routine is hardwired to the data area, and the bss area * is ignored. */ int gen_locsym(FILE *fp, int sec) { char data[20]; int j, txtflg, hdrflg; long int addrcount; struct locname *np, *current; /* check that all offsets are valid - this routine won't work for text */ if (sec < ROM || sec > BSS) { fprintf(stderr, "Invalid section %s\n", a_sectab[sec & 7].name); return(FAILED); } /* initialise the label string */ strncpy(data, ".DAT", 4); data[4] = '\0'; /* initialise the in-memory local name table pointers */ current = (struct locname *)(NULL); /* read the data area and load the symbols */ (void) fseek(aoutfp, A_DATAPOS(a_hdrbuf), SEEK_SET); addrcount = 0; txtflg = hdrflg = FALSE; while (addrcount < a_hdrbuf.a_data) { j = fgetc(fp); if (j < 040 || j > 0177) { txtflg = FALSE; hdrflg = FALSE; } else txtflg = TRUE; /* ensure that the start of each apparent string has a related symbol */ if (txtflg && !hdrflg) { if (find_asym(addrcount, sec) == -1) { /* if malloc fails, just collapse */ if ((np = (struct locname *)malloc(sizeof(struct locname))) == (struct locname *)NULL) { fprintf(stderr, "%s: malloc failed\n", progname); return(FAILED); } /* update the current record */ sprintf(np->l_name, "%s%04x", data, (a_hdrbuf.a_text + addrcount) & 0xffff); /* nb. must follow l_name update */ if (sec == TEXT) np->l_sclass = S_TEXT & 0xff; else if (sec == ROM) np->l_sclass = S_DATA & 0xff; else if (sec == DATA) np->l_sclass = S_DATA & 0xff; else if (sec == BSS) np->l_sclass = S_BSS & 0xff; else sec = 0; np->l_value = a_hdrbuf.a_text + addrcount; np->l_next = (struct locname *)NULL; /* and add it to the list */ if (current == (struct locname *)NULL) locsym[sec] = np; else current->l_next = np; current = np; } hdrflg = TRUE; } addrcount++; } return(OK); } /* * i n i t _ a o u t * * Initialise the a.out file tables. * * Returns: OK Success * FAILED File read failure * * The a_hdrbuf and a_symtab and a_sectab structures are * all initialised here. Also, the ability to read the * entire file is checked; no read checking is done * later in the program. */ int init_aout(FILE *fp) { char *cp; int j, k, maxsym; struct nlist *np; struct nlist ntmp; /* load the header into memory for fast access. * the header length is the fifth byte of the header. */ cp = (char *)&a_hdrbuf; if (fread(cp, sizeof(char), 5, aoutfp) != 5) { fprintf(stderr, "Cannot read executable header.\n"); return(FAILED); } j = cp[4] - 5; cp += 5; if (fread(cp, sizeof(char), j, aoutfp) != j) { fprintf(stderr, "Cannot read executable header.\n"); return(FAILED); } if(BADMAG(a_hdrbuf)) { fprintf(stderr, "%s: bad magic number.\n", progname); return(FAILED); } /* check that the whole file can be read */ if (fseek(aoutfp, A_SYMPOS(a_hdrbuf) + a_hdrbuf.a_syms, SEEK_SET) != 0) { fprintf(stderr, "%s: cannot seek to end of file.\n", progname); return(FAILED); } /* load the symbol table into memory for fast access */ a_symtab = (struct nlist *)NULL; if (a_hdrbuf.a_syms != 0) { /* get space for the nlist data */ if ((cp = (char *)malloc(a_hdrbuf.a_syms)) == (char *)NULL) { fprintf(stderr, "%s: malloc failed\n", progname); return(FAILED); } if (fseek(aoutfp, -a_hdrbuf.a_syms, SEEK_CUR) != 0) { fprintf(stderr, "%s: cannot seek to symbol area.\n", progname); return(FAILED); } /* load the symbols into a sorted list */ np = (struct nlist *)cp; maxsym = 0; for (j = 0 ; j < a_hdrbuf.a_syms / sizeof(struct nlist) ; j++) { if (fread(&ntmp, sizeof(struct nlist), 1, aoutfp) != 1) { fprintf(stderr, "%s: cannot read symbol area.\n", progname); return(FAILED); } /* insertion sort, by class and value */ for (k = maxsym ; k > 0 ; k--) { if ((ntmp.n_sclass & N_SECT) < (np[k-1].n_sclass & N_SECT)) np[k] = np[k - 1]; else if ((ntmp.n_sclass & N_SECT) == (np[k-1].n_sclass & N_SECT) && ntmp.n_value < np[k-1].n_value) np[k] = np[k - 1]; else break; } np[k] = ntmp; maxsym++; } /* finally, we have a valid symbol table */ a_symtab = (struct nlist *)cp; /* update the symbol section index list */ a_sectab[a_symtab[0].n_sclass & N_SECT].first = 0; for (j = 1 ; j < (a_hdrbuf.a_syms / sizeof(struct nlist)) ; j++) { if ((a_symtab[j].n_sclass & N_SECT) != (a_symtab[j-1].n_sclass & N_SECT)) { a_sectab[a_symtab[j-1].n_sclass & N_SECT].last = j - 1; a_sectab[a_symtab[j-1].n_sclass & N_SECT].total = j - a_sectab[a_symtab[j-1].n_sclass & N_SECT].first; a_sectab[a_symtab[j].n_sclass & N_SECT].first = j; } } a_sectab[a_symtab[j-1].n_sclass & N_SECT].last = j - 1; /* build the local symbol tables */ for (j = 0 ; j < MAXSECT ; j++) locsym[j] = (struct locname *)NULL; /* build the local .text symbol table */ /* ### full disassembly ? */ /* build the local data symbol table */ if (gen_locsym(fp, DATA) == FAILED) return(FAILED); } return(OK); } /* * m a i n * * Main routine of dis_a386. */ int main(int argc, char *argv[]) { char *cp, binfile[BUFF_LEN], symbfile[BUFF_LEN]; int j, errors; unsigned long int addrfirst, addrlast, addrcount; struct stat statbuff; /* initial set up */ if ((cp = strrchr(argv[0], PSEP)) == (char *)NULL) cp = argv[0]; else cp++; strncpy(progname, cp, BUFF_MAX); strncpy(binfile, AOUT, BUFF_MAX); addrfirst = addrlast = addrcount = 0; /* check for an MSDOS-style option */ if (argc == 2 && argv[1][0] == '/') { usage(); exit(0); } /* parse arguments */ errors = opterr = 0; while ((j = getopt(argc, argv, "E:abdf:hl:stx:")) != EOF) { switch (j & 0177) { #if 0 case 'C': /* core file name */ opt_C = TRUE; if (optarg != (char *)NULL) strncpy(binfile, optarg, BUFF_MAX); else errors++; break; #endif case 'E': /* executable file name */ opt_E = TRUE; if (optarg != (char *)NULL) strncpy(binfile, optarg, BUFF_MAX); else errors++; break; #if 0 case 'O': /* object file name */ opt_O = TRUE; if (optarg != (char *)NULL) strncpy(binfile, optarg, BUFF_MAX); else errors++; break; case 'S': /* symbol table name */ opt_S = TRUE; if (optarg != (char *)NULL) strncpy(symbfile, optarg, BUFF_MAX); else errors++; break; #endif case 'a': /* dump tables and disassemble segments */ opt_a = TRUE; break; case 'b': /* dump straight binary */ opt_b = TRUE; break; case 'd': /* dump the data segment */ opt_d = TRUE; break; case 'f': /* first address of dump */ opt_f = TRUE; if (optarg != (char *)NULL) addrfirst = atoaddr(optarg); else errors++; break; case 'h': /* dump the header */ opt_h = TRUE; break; case 'l': /* last address of dump */ opt_l = TRUE; if (optarg != (char *)NULL) addrlast = atoaddr(optarg); else errors++; break; #if 0 case 'm': /* dump the rom segment */ opt_m = TRUE; break; case 'n': /* dump the symbol names */ opt_n = TRUE; break; case 'r': /* dump the relocation structures */ opt_r = TRUE; break; #endif case 's': /* dump the symbol table */ opt_s = TRUE; break; case 't': /* dump the text segment */ opt_t = TRUE; break; #if 0 case 'u': /* dump the bss segment */ opt_u = TRUE; break; #endif case 'x': /* debugging flag */ opt_x = TRUE; if (optarg != (char *)NULL) dbglvl = atoi(optarg); break; case '?': default: usage(); exit(1); break; } } /* check the flags */ if (errors > 0) { usage(); exit(1); } if (opt_a && (opt_d || opt_h || opt_s || opt_t)) { usage(); exit(1); } if ((opt_f || opt_l) && (addrlast != 0 && addrfirst > addrlast)) { usage(); exit(1); } /* check for a specific input file */ if (optind < argc) strncpy(binfile, argv[optind], BUFF_MAX); /* we must have a binary file of some sort */ if ((aoutfp = fopen(binfile, "rb")) == (FILE *)NULL || stat(binfile, &statbuff) == -1) { perror(binfile); exit(1); } /* initialise the a.out data structures */ if (init_aout(aoutfp) == FAILED) { perror(binfile); exit(1); } /* show the output file name and date */ fprintf(stdout, "File name: %s\nFile date: %s", binfile, ctime(&statbuff.st_ctime)); /* show the header section - default behaviour */ if (opt_a || opt_h || (!opt_d && !opt_s && !opt_t)) { fprintf(stdout, "\nHeader data:\n"); (void) dump_ahdr(&a_hdrbuf); } /* dump the data section */ if (opt_d && opt_b) { /* check that all offsets are valid */ if (addrfirst > a_hdrbuf.a_data || addrlast > a_hdrbuf.a_data) { fprintf(stderr, "Invalid data address range 0x%08.8lu to 0x%08.8lu\n", addrfirst, addrlast); } else { addrcount = (addrlast == 0) ? a_hdrbuf.a_data : addrlast; addrcount -= addrfirst; (void) fseek(aoutfp, A_DATAPOS(a_hdrbuf) + addrfirst, SEEK_SET); fprintf(stdout, "\nData:\n"); (void) dump_hex(aoutfp, A_DATAPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen + addrfirst, addrcount); } } /* disassemble the data section */ if (opt_a || (opt_d && !opt_b)) { /* check that all offsets are valid */ if (addrfirst > a_hdrbuf.a_data || addrlast > a_hdrbuf.a_data) { fprintf(stderr, "Invalid data address range 0x%08.8lu to 0x%08.8lu\n", addrfirst, addrlast); } else { addrcount = (addrlast == 0) ? a_hdrbuf.a_data : addrlast; addrcount -= addrfirst; (void) fseek(aoutfp, A_DATAPOS(a_hdrbuf) + addrfirst, SEEK_SET); fprintf(stdout, "\nDisassembled data:\n"); (void) dump_adata(aoutfp, A_DATAPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen + addrfirst, addrcount); } } /* dump the text section */ if (opt_t && opt_b) { /* check that all offsets are valid */ if (addrfirst > a_hdrbuf.a_text || addrlast > a_hdrbuf.a_text) { fprintf(stderr, "Invalid text address range 0x%08.8lu to 0x%08.8lu\n", addrfirst, addrlast); } else { addrcount = (addrlast == 0) ? a_hdrbuf.a_text : addrlast; addrcount -= addrfirst; (void) fseek(aoutfp, A_TEXTPOS(a_hdrbuf) + addrfirst, SEEK_SET); fprintf(stdout, "\nText:\n"); (void) dump_hex(aoutfp, A_TEXTPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen + addrfirst, addrcount); } } /* disassemble the text section */ if (opt_a || (opt_t && !opt_b)) { /* check that all offsets are valid */ if (addrfirst > a_hdrbuf.a_text || addrlast > a_hdrbuf.a_text) { fprintf(stderr, "Invalid text address range 0x%08.8lu to 0x%08.8lu\n", addrfirst, addrlast); } else { addrcount = (addrlast == 0) ? a_hdrbuf.a_text : addrlast; addrcount -= addrfirst; disfp = aoutfp; /* file to be disassembled */ objfp = (FILE *)NULL; /* without relocation information */ (void) fseek(disfp, A_TEXTPOS(a_hdrbuf) + addrfirst, SEEK_SET); fprintf(stdout, "\nDisassembled text:\n"); (void) dasm(addrfirst, addrcount); } } /* show the symbol data */ if (opt_a || opt_s) { fprintf(stdout, "\nSymbol data:\n"); if (a_hdrbuf.a_syms == 0) fprintf(stdout, "No symbol table available.\n"); else (void) dump_asym(a_symtab, 0, a_hdrbuf.a_syms / sizeof(struct nlist)); } /* wrap up */ (void) fclose(aoutfp); exit(0); /* NOTREACHED */ } /* * u s a g e * * Usage message. * * Returns: Nothing Always */ void usage() { fprintf(stderr, "Usage: %s [-a|-dhst] [-b] [-f #] [-l #] [-E executable]\n", progname); } /* * EOF */