1036 lines
26 KiB
C
1036 lines
26 KiB
C
/*
|
|
* 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 <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <minix/config.h>
|
|
#include <minix/const.h>
|
|
#include <a.out.h>
|
|
#include <minix/ansi.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#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 <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include </local/minix/minix/config.h>
|
|
#include </local/minix/minix/const.h>
|
|
#include </local/minix/a.out.h>
|
|
#include </local/minix/ansi.h>
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#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
|
|
*/
|
|
|