1323 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1323 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * dis_o386: disassemble 386 object files.
 | |
|  *
 | |
|  * $Id: diso.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"	/* useful default file names */
 | |
| #define CORE		"core"
 | |
| #define OBJF		"test.o"
 | |
| #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_o386.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 */
 | |
| 
 | |
| /* Forward declarations */
 | |
| /* _PROTOTYPE(void usage, (void)); */
 | |
| unsigned long int atoaddr(char *sp);			/* Convert ascii hex/dec to ulong */
 | |
| int dump_hex(FILE *fp, long s, long n);			/* Dump bytes in hex and ascii */
 | |
| int dump_odata(FILE *fp, long s, long n, int sec);	/* Dump object file data section */
 | |
| int dump_ohdr(struct outhead *ph);			/* Dump object file header */
 | |
| int dump_orel(FILE *fp, long s, long n);		/* Dump object file relocation section */
 | |
| int dump_osec(long b, long e, int sec, int flg);	/* Dump object file section */
 | |
| int dump_oshdr(FILE *fp, long s, long n);		/* Dump object file section headers */
 | |
| int dump_ostr(FILE *fp, long s, long n);		/* Dump object file string data */
 | |
| int dump_osym(FILE *fp, long s, long n);		/* Dump object file symbol table data */
 | |
| int find_osym(long val, int sec);			/* Find object file symbol index */
 | |
| int gen_locsym(FILE *fp, int sec);			/* Generate local symbols */
 | |
| int getstruct(FILE *fp, char *bp, char *s);		/* Get values from the input file */
 | |
| int init_objf(FILE *fp);				/* Initialise object 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 int 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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, long start, long 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 = '.';
 | |
| 		fputc(c, stdout);
 | |
| 	}
 | |
| 
 | |
| 	fprintf(stdout, "\n");
 | |
| 	if (quit)
 | |
| 		break;
 | |
|   }
 | |
| 
 | |
|   return(status);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d u m p _ o d a t a
 | |
|  *
 | |
|  * Dump object file data section.
 | |
|  *
 | |
|  * Returns:	OK	Success
 | |
|  *		FAILED	File read failure, invalid arguments
 | |
|  *
 | |
|  * The o_hdrbuf and o_sectab structures are read to determine section addresses.
 | |
|  * The o_symtab and o_strtab structures are read to determine symbol names.
 | |
|  */
 | |
| int dump_odata(FILE *fp, long start, long count, int sec)
 | |
| {
 | |
|   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 lj, addr;
 | |
|   unsigned long int ulj;
 | |
|   struct locname *np;
 | |
| 
 | |
|   if (start < 0 || (start + count) > o_sectab[sec].os_flen)
 | |
| 	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[sec] ; !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_osym(ulj, sec)) != -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 */
 | |
| 			lj = o_symtab[index].on_foff - (long)OFF_CHAR(o_hdrbuf);
 | |
| 			for (k = 0 ; k < 8 ; k++)
 | |
| 				label[k] = *(o_strtab + lj + k);
 | |
| 			label[k] = '\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 _ o h d r
 | |
|  *
 | |
|  * Dump object file header data.
 | |
|  *
 | |
|  * Returns:	OK	Always
 | |
|  */
 | |
| int dump_ohdr(struct outhead *ph)
 | |
| {
 | |
|   char buff[BUFF_LEN];
 | |
| 
 | |
|   sprintf(buff, "Magic number:          0x%04.4x", ph->oh_magic);
 | |
|   if (ph->oh_magic == O_MAGIC) strcat(buff, " O_MAGIC");
 | |
|   else strcat(buff, " UNKNOWN");
 | |
|   fprintf(stdout, "%s\n", buff);
 | |
| 
 | |
|   fprintf(stdout, "Version stamp:         0x%04.4x\n", ph->oh_stamp);
 | |
| 
 | |
|   sprintf(buff, "Format flags:          0x%04.4x", ph->oh_flags);
 | |
|   if (ph->oh_flags & HF_LINK) strcat(buff, " HF_LINK");
 | |
|   if (ph->oh_flags & HF_8086) strcat(buff, " HF_8086");
 | |
|   if (ph->oh_flags & ~(HF_LINK | HF_8086)) strcat(buff, " UNKNOWN");
 | |
|   fprintf(stdout, "%s\n", buff);
 | |
| 
 | |
|   fprintf(stdout, "Number of sections:    0x%04.4x\n", ph->oh_nsect);
 | |
|   fprintf(stdout, "Number of relocations: 0x%04.4x\n", ph->oh_nrelo);
 | |
|   fprintf(stdout, "Number of symbols:     0x%04.4x\n", ph->oh_nname);
 | |
|   fprintf(stdout, "Sum of section sizes:  0x%08.8x\n", ph->oh_nemit);
 | |
|   fprintf(stdout, "Size of string area:   0x%08.8x\n", ph->oh_nchar);
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d u m p _ o r e l
 | |
|  *
 | |
|  * Dump object file relocation data.
 | |
|  *
 | |
|  * Returns:	OK	Success
 | |
|  *		FAILED	Invalid arguments
 | |
|  *
 | |
|  * The o_hdrbuf and o_sectab structures are read to determine section addresses.
 | |
|  * The o_symtab and o_strtab structures are read to determine symbol values.
 | |
|  */
 | |
| int dump_orel(FILE *fp, long start, long count)
 | |
| {
 | |
|   char buff[BUFF_LEN], data[S_BUFF_LEN];
 | |
|   int j;
 | |
|   unsigned int uj;
 | |
|   long int lj;
 | |
|   struct outrelo relbuf;
 | |
| 
 | |
|   if (start < 0 || (start + count) > o_hdrbuf.oh_nrelo)
 | |
| 	return(FAILED);
 | |
| 
 | |
|   for (j = 0 ; j < count ; j++) {
 | |
| 	(void) getstruct(fp, (char *)&relbuf, SF_RELO);
 | |
| 	sprintf(buff, "%04d Type:", j + start);
 | |
| 	if (relbuf.or_type & RELO1) strcat(buff, " RELO1");
 | |
| 	if (relbuf.or_type & RELO2) strcat(buff, " RELO2");
 | |
| 	if (relbuf.or_type & RELO4) strcat(buff, " RELO4");
 | |
| 	if (relbuf.or_type & RELPC) strcat(buff, " RELPC");
 | |
| 	else strcat(buff, "      ");
 | |
| 	if (relbuf.or_type & RELBR) strcat(buff, " RELBR");
 | |
| 	if (relbuf.or_type & RELWR) strcat(buff, " RELWR");
 | |
| 	if (relbuf.or_type & ~(RELO1 | RELO2 | RELO4 | RELPC | RELBR | RELWR))
 | |
| 		strcat(buff, "UNKNOWN");
 | |
| 
 | |
| 	strcat(buff, " Sect:");
 | |
| 	uj = relbuf.or_sect & S_TYP;
 | |
| 	if (uj >= S_MIN && uj <= S_MAX) {
 | |
| #if 1
 | |
| 		/* use arbitrary names for Minix 386 */
 | |
| 		sprintf(data, " %-5s", o_secnam[uj - S_MIN]);
 | |
| #else
 | |
| 		sprintf(data, "  0x%02.2x", uj - S_MIN);
 | |
| #endif
 | |
| 		strcat(buff, data);
 | |
| 	}
 | |
| 	/* S_UND is the empty S_TYP field */
 | |
| 	if ((relbuf.or_sect & S_TYP) == S_UND) strcat(buff, " S_UND");
 | |
| 	if ((relbuf.or_sect & S_TYP) == S_ABS) strcat(buff, " S_ABS");
 | |
| 	if ((relbuf.or_sect & S_TYP) == S_CRS) strcat(buff, " S_CRS");
 | |
| 
 | |
| 	if ((relbuf.or_sect & S_EXT) == S_EXT) strcat(buff, " S_EXT");
 | |
| 	else strcat(buff, "      ");
 | |
| 
 | |
| 	if (relbuf.or_sect & ~(S_TYP | S_EXT))
 | |
| 		strcat(buff, " UNKNOWN");
 | |
| 
 | |
| 	strcat(buff, " Symb:");
 | |
| 	if (relbuf.or_nami < o_hdrbuf.oh_nname) {
 | |
| 		lj = o_symtab[relbuf.or_nami].on_foff - (long)OFF_CHAR(o_hdrbuf);
 | |
| 		/* check that addressing isn't messed up */
 | |
| 		assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
 | |
| 		/* name size is defined by SZ_NAME */
 | |
| 		sprintf(data, "%-13s", o_strtab + lj);
 | |
| 	}
 | |
| 	else
 | |
| 		sprintf(data, " 0x%04.4x", relbuf.or_nami);
 | |
| 	strcat(buff, data);
 | |
| 	strcat(buff, " Addr:");
 | |
| 	sprintf(data, " 0x%08.8x", relbuf.or_addr);
 | |
| 	strcat(buff, data);
 | |
| 	fprintf(stdout, "%s\n", buff);
 | |
| 
 | |
| #if 0
 | |
| 	printf("Type Section Symbol Address\n");
 | |
| 	printf("0x%02.2x 0x%02.2x 0x%04.4x 0x%08.8x\n",
 | |
| 		relbuf.or_type, relbuf.or_sect,
 | |
| 		relbuf.or_nami, relbuf.or_addr);
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d u m p _ o s e c
 | |
|  *
 | |
|  * Dump object file section.
 | |
|  *
 | |
|  * Returns:	OK	Success
 | |
|  *		FAILED	Invalid arguments
 | |
|  */
 | |
| int dump_osec(long addrfirst, long addrlast, int sec, int full)
 | |
| {
 | |
|   long int addrcount;
 | |
| 
 | |
|   /* check that all offsets are valid */
 | |
|   addrcount = o_sectab[sec].os_flen;
 | |
|   if (addrfirst > o_sectab[sec].os_flen || addrlast > o_sectab[sec].os_flen) {
 | |
| 	fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
 | |
| 					o_secnam[sec], addrfirst, addrlast);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   else {
 | |
| 	if (opt_l)
 | |
| 		addrcount = addrlast + 1;
 | |
| 	addrcount = addrcount - addrfirst;
 | |
| 	(void) fseek(objfp, o_sectab[sec].os_foff, SEEK_SET);
 | |
| 	fprintf(stdout, "\n%s%s:\n", full ? "Disassembled " : "", o_secnam[sec]);
 | |
| 	if (full)
 | |
| 		(void) dump_odata(objfp, addrfirst, addrcount, sec);
 | |
| 	else
 | |
| 		(void) dump_hex(objfp, addrfirst, addrcount);
 | |
| 	return(OK);
 | |
|   }
 | |
|   /* NOTREACHED */
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d u m p _ o s h d r
 | |
|  *
 | |
|  * Dump object file section headers.
 | |
|  *
 | |
|  * Returns:	OK	Always
 | |
|  *
 | |
|  * The o_secnam structure is read to determine section names.
 | |
|  */
 | |
| int dump_oshdr(FILE *fp, long start, long count)
 | |
| {
 | |
|   int j;
 | |
|   struct outsect secbuf;
 | |
| 
 | |
|   fprintf(stdout,
 | |
| 	"Name          Index Core start Core size  File start File size  Alignment\n");
 | |
|   for (j = 0 ; j < count ; j++) {
 | |
| 	(void) getstruct(fp, (char *)&secbuf, SF_SECT);
 | |
| 	if (j >= start)
 | |
| 		fprintf(stdout, "%-13s %4.4d  0x%08.8x 0x%08.8x 0x%08.8x 0x%08.8x 0x%08.8x\n",
 | |
| 			o_secnam[j], j, secbuf.os_base, secbuf.os_size, secbuf.os_foff,
 | |
| 			secbuf.os_flen, secbuf.os_lign);
 | |
|   }
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d u m p _ o s t r
 | |
|  *
 | |
|  * Dump object file string data.
 | |
|  *
 | |
|  * Returns:	OK	Success
 | |
|  *		FAILED	File read failure, invalid arguments
 | |
|  *
 | |
|  * The o_hdrbuf structure is read to determine section addresses.
 | |
|  */
 | |
| int dump_ostr(FILE *fp, long start, long count)
 | |
| {
 | |
|   int j, k;
 | |
| 
 | |
|   if (start < 0 || count > o_hdrbuf.oh_nname)
 | |
| 	return(FAILED);
 | |
| 
 | |
|   /* we cannot precalculate the offset of a name record */
 | |
|   for (j = 0 ; j < count ; j++) {
 | |
| 	fprintf(stdout, "%04d ", j + start);
 | |
| 	do {
 | |
| 		switch (k = fgetc(fp)) {
 | |
| 		case EOF:
 | |
| 			return(FAILED);
 | |
| 			break;
 | |
| 		case 0:
 | |
| 			fprintf(stdout, "\n");
 | |
| 			break;
 | |
| 		default:
 | |
| 			fprintf(stdout, "%c", k);
 | |
| 			break;
 | |
| 		}
 | |
| 	} while (k);
 | |
|   }
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d u m p _ o s y m
 | |
|  *
 | |
|  * Dump object file symbol table data.
 | |
|  *
 | |
|  * Returns:	OK	Success
 | |
|  *		FAILED	Invalid arguments
 | |
|  *
 | |
|  * The o_hdrbuf structure is read to determine section addresses.
 | |
|  * The o_strtab and o_secnam structures are read to determine symbol values.
 | |
|  */
 | |
| int dump_osym(FILE *fp, long start, long count)
 | |
| {
 | |
|   char buff[BUFF_LEN], data[S_BUFF_LEN];
 | |
|   int j;
 | |
|   unsigned int uj;
 | |
|   long lj;
 | |
|   struct outname nambuf;
 | |
| 
 | |
|   if (start < 0 || (start + count) > o_hdrbuf.oh_nname)
 | |
| 	return(FAILED);
 | |
| 
 | |
|   for (j = 0 ; j < count ; j++) {
 | |
| 	(void) getstruct(fp, (char *)&nambuf, SF_NAME);
 | |
| 	sprintf(buff, "%4.4d", j + start);
 | |
| #if 1
 | |
| 	lj = nambuf.on_foff - (long)OFF_CHAR(o_hdrbuf);
 | |
| 	/* check that addressing isn't messed up */
 | |
| 	assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
 | |
| 	/* name size is defined by SZ_NAME */
 | |
| 	sprintf(data, " %-13s", o_strtab + lj);
 | |
| 	strcat(buff, data);
 | |
| #else
 | |
| 	sprintf(data, " 0x%08.8x", nambuf.on_foff);
 | |
| 	strcat(buff, data);
 | |
| #endif
 | |
| 	strcat(buff, " Type:");
 | |
| 	uj = nambuf.on_type & S_TYP;
 | |
| 	if (uj >= S_MIN && uj <= S_MAX) {
 | |
| #if 1
 | |
| 		/* use arbitrary names for Minix 386 */
 | |
| 		sprintf(data, " %-5s", o_secnam[uj - S_MIN]);
 | |
| #else
 | |
| 		sprintf(data, "  0x%02.2x", uj - S_MIN);
 | |
| #endif
 | |
| 		strcat(buff, data);
 | |
| 	}
 | |
| 	/* S_UND is the empty S_TYP field */
 | |
| 	if ((nambuf.on_type & S_TYP) == S_UND) strcat(buff, " S_UND");
 | |
| 	if ((nambuf.on_type & S_TYP) == S_ABS) strcat(buff, " S_ABS");
 | |
| 	if ((nambuf.on_type & S_TYP) == S_CRS) strcat(buff, " S_CRS");
 | |
| 
 | |
| 	if ((nambuf.on_type & S_EXT) == S_EXT) strcat(buff, " S_EXT");
 | |
| 	else strcat(buff, "      ");
 | |
| 
 | |
| 	if ((nambuf.on_type & S_ETC) == S_SCT) strcat(buff, " S_SCT");
 | |
| 	if ((nambuf.on_type & S_ETC) == S_LIN) strcat(buff, " S_LIN");
 | |
| 	if ((nambuf.on_type & S_ETC) == S_FIL) strcat(buff, " S_FIL");
 | |
| 	if ((nambuf.on_type & S_ETC) == S_MOD) strcat(buff, " S_MOD");
 | |
| 	if ((nambuf.on_type & S_ETC) == S_COM) strcat(buff, " S_COM");
 | |
| 	if ((nambuf.on_type & S_ETC) == 0) strcat(buff, "      ");
 | |
| 
 | |
| 	if (nambuf.on_type &
 | |
| 		~(S_TYP | S_EXT | S_SCT | S_LIN | S_FIL | S_MOD | S_COM))
 | |
| 		strcat(buff, " UNKNOWN");
 | |
| 
 | |
| #if 1
 | |
| 	/* Desc is not used, so save space */
 | |
| 	strcat(buff, " Desc: 0x00");
 | |
| #else
 | |
| 	strcat(buff, " Desc:");
 | |
| 	sprintf(data, " 0x%04.4x", nambuf.on_desc);
 | |
| 	strcat(buff, data);
 | |
| #endif
 | |
| 	strcat(buff, " Valu:");
 | |
| 	sprintf(data, " 0x%08.8x", nambuf.on_valu);
 | |
| 	strcat(buff, data);
 | |
| 	fprintf(stdout, "%s\n", buff);
 | |
|   }
 | |
| #if 0
 | |
|   fprintf(stdout, "Name Type Debug Value\n");
 | |
|   fprintf(stdout, "0x%08.8x 0x%04.4x 0x%04.4x 0x%08.8x\n",
 | |
| 		nambuf.on_u.on_off, nambuf.on_type,
 | |
| 		nambuf.on_desc, nambuf.on_valu);
 | |
| #endif
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * f i n d _ o s y m
 | |
|  *
 | |
|  * Find an object file symbol name in a unsorted list.
 | |
|  *
 | |
|  * Returns:	index	Found
 | |
|  *		-1	Not found
 | |
|  *
 | |
|  * There may be several symbols with the same value:
 | |
|  * return each of them on successive calls.
 | |
|  *
 | |
|  */
 | |
| int find_osym(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 = 0;
 | |
|   }
 | |
|   /* never happen */
 | |
|   else if (index == -1)
 | |
| 	return(FAILED);
 | |
| 
 | |
|   /* do a linear search for a symbol, as the symbol table is unsorted */
 | |
|   for (j = index ; j < o_hdrbuf.oh_nname ; j++) {
 | |
| 	if (value == o_symtab[j].on_valu &&
 | |
| 			sec == ((o_symtab[j].on_type & S_TYP) - S_MIN))
 | |
| 		break;
 | |
|   }
 | |
| 
 | |
|   /* set up the index for the next pass */
 | |
|   if (j == o_hdrbuf.oh_nname)
 | |
| 	index = 0;
 | |
|   else
 | |
| 	index = j + 1;
 | |
| 
 | |
|  return(index - 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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, .rom and .bss.  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 can be usefully applied only to the .rom area.
 | |
|  */
 | |
| 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", o_secnam[sec]);
 | |
| 	return(FAILED);
 | |
|   }
 | |
| 
 | |
|   /* initialise the label string */
 | |
|   strncpy(data, o_secnam[sec], 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(fp, o_sectab[sec].os_foff, SEEK_SET);
 | |
|   addrcount = 0;
 | |
|   txtflg = hdrflg = FALSE;
 | |
|   while (addrcount < o_sectab[sec].os_flen) {
 | |
| 	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_osym(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, 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 = 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);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * g e t s t r u c t
 | |
|  *
 | |
|  * Returns:	0	Always
 | |
|  *
 | |
|  * Get 1, 2 and 4 byte values from the input file.
 | |
|  *
 | |
|  * Note that the bytes must be reordered and the
 | |
|  * read pointer incremented correctly for each value;
 | |
|  * hence the need for a structure format string.
 | |
|  *
 | |
|  * Called with:
 | |
|  * a file destcriptor
 | |
|  * a pointer to the output buffer
 | |
|  * a structure format string
 | |
|  */
 | |
| int getstruct(FILE *fp, char *bp, char *s)
 | |
| {
 | |
|   int j;
 | |
|   long lj;
 | |
| 
 | |
|   while (TRUE) {
 | |
| 	switch (*s++) {
 | |
| #if 0
 | |
| 	/* not used */
 | |
| 	case '0':
 | |
| 		bp++;
 | |
| 		continue;
 | |
| #endif
 | |
| 	case '1':
 | |
| 		*bp++ = (char) getc(fp);
 | |
| 		continue;
 | |
| 	case '2':
 | |
| 		j = getc(fp);
 | |
| 		j |= (getc(fp) << 8);
 | |
| 		*((short *)bp) = (short) j;
 | |
| 		bp += 2;
 | |
| 		continue;
 | |
| 	case '4':
 | |
| 		lj = (long)getc(fp);
 | |
| 		lj |= ((long)getc(fp) << 8);
 | |
| 		lj |= ((long)getc(fp) << 16);
 | |
| 		lj |= ((long)getc(fp) << 24);
 | |
| 		*((long *)bp) = lj;
 | |
| 		bp += 4;
 | |
| 		continue;
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 	break;
 | |
|   }
 | |
| 
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * i n i t _ o b j f
 | |
|  *
 | |
|  * Initialise object file tables.
 | |
|  *
 | |
|  * Returns:	OK	Success
 | |
|  *		FAILED	Otherwise
 | |
|  */
 | |
| int init_objf(FILE *fp)
 | |
| {
 | |
|   char *cp;
 | |
|   int j;
 | |
|   unsigned int uj;
 | |
|   long int lj;
 | |
| 
 | |
|   /* load the header into memory for fast access */
 | |
|   (void) getstruct(fp, (char *)&o_hdrbuf, SF_HEAD);
 | |
|   if (BADMAGIC(o_hdrbuf)) {
 | |
| 	fprintf(stderr, "%s: bad magic number.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if (o_hdrbuf.oh_nsect == 0) {
 | |
| 	fprintf(stderr, "%s: no sections present.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
| 
 | |
|   /* check that the whole file can be read */
 | |
|   if (fseek(fp, OFF_CHAR(o_hdrbuf) + o_hdrbuf.oh_nchar, SEEK_SET) != 0) {
 | |
| 	fprintf(stderr, "%s: cannot seek to end of file.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
| 
 | |
|   /* load the section data into memory for fast access */
 | |
|   uj = o_hdrbuf.oh_nsect * sizeof(struct outsect);
 | |
|   if (fseek(fp, OFF_SECT(o_hdrbuf), SEEK_SET) != 0) {
 | |
| 	fprintf(stderr, "%s: cannot seek to section area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if (fread(o_sectab, sizeof(char), uj, fp) != uj) {
 | |
| 	fprintf(stderr, "%s: cannot read section area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
| 
 | |
|   /* load the relocation data into memory for fast access */
 | |
|   /* ### Should this be left on disk and only the indices loaded ? */
 | |
|   uj = o_hdrbuf.oh_nrelo * sizeof(struct outrelo);
 | |
|   if (fseek(fp, OFF_RELO(o_hdrbuf), SEEK_SET) != 0) {
 | |
| 	fprintf(stderr, "%s: cannot seek to relocation area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if ((cp = (char *)malloc(uj)) == (char *)NULL) {
 | |
| 	fprintf(stderr, "%s: malloc failed\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if (fread(cp, sizeof(char), uj, fp) != uj) {
 | |
| 	fprintf(stderr, "%s: cannot read relocation area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   /* initialise the in-memory relocation table array pointers */
 | |
|   o_reltab = (struct outrelo *)cp;
 | |
| 
 | |
|   /* ### needs to be optional for files without symbol tables */
 | |
|   /* load the symbol table into memory for fast access */
 | |
|   uj = o_hdrbuf.oh_nname * sizeof(struct outname);
 | |
|   if ((cp = (char *)malloc(uj)) == (char *)NULL) {
 | |
| 	fprintf(stderr, "%s: malloc failed\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if (fseek(fp, OFF_NAME(o_hdrbuf), SEEK_SET) != 0) {
 | |
| 	fprintf(stderr, "%s: cannot seek to symbol area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if (fread(cp, sizeof(char), uj, fp) != uj) {
 | |
| 	fprintf(stderr, "%s: cannot read symbol area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   /* initialise the in-memory symbol table array pointers */
 | |
|   o_symtab = (struct outname *)cp;
 | |
| 
 | |
|   /* load the string area into memory for fast access */
 | |
|   uj = (unsigned int)o_hdrbuf.oh_nchar;
 | |
|   if ((o_strtab = (char *)malloc(uj)) == (char *)NULL) {
 | |
| 	fprintf(stderr, "%s: malloc failed\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if (fseek(fp, OFF_CHAR(o_hdrbuf), SEEK_SET) != 0) {
 | |
| 	fprintf(stderr, "%s: cannot seek to string area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
|   if (fread(o_strtab, sizeof(char), uj, fp) != uj) {
 | |
| 	fprintf(stderr, "%s: cannot read string area.\n", progname);
 | |
| 	return(FAILED);
 | |
|   }
 | |
| 
 | |
|   /* build the section name table */
 | |
|   for (j = 0 ; j < o_hdrbuf.oh_nname ; j++) {
 | |
| 	if ((o_symtab[j].on_type & S_ETC) == S_SCT) {
 | |
| 		lj = o_symtab[j].on_foff - (long)OFF_CHAR(o_hdrbuf);
 | |
| 		/* check that addressing isn't messed up */
 | |
| 		assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
 | |
| 		strncpy(o_secnam[(o_symtab[j].on_type & S_TYP) - S_MIN],
 | |
| 				o_strtab + lj, SZ_NAME + 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 .rom symbol table */
 | |
|   if (gen_locsym(fp, ROM) == FAILED)
 | |
| 	return(FAILED);
 | |
| 
 | |
|   /* there's no point in building the .data and .bss tables */
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * m a i n
 | |
|  *
 | |
|  * Main routine of dis_o386.
 | |
|  */
 | |
| int main(int argc, char *argv[])
 | |
| {
 | |
|   char *cp, objfile[BUFF_LEN], symbfile[BUFF_LEN];
 | |
|   char table[MAXSECT*(SZ_NAME+2)];
 | |
|   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(objfile, OBJF, BUFF_MAX);
 | |
|   addrfirst = addrlast = addrcount = 0;
 | |
| 
 | |
|   /* clear the in-core name tables */
 | |
|   o_strtab = (char *)NULL;
 | |
|   for (j = 0 ; j < MAXSECT ; j++)
 | |
| 	o_secnam[j] = table + j * (SZ_NAME + 2);	/* nb. leading '_' */
 | |
|   for (j = 0 ; j < sizeof(table) ; j++) table[j] = '\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, "O:S:abdf:hl:mnrstx:")) != 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;
 | |
| 	case 'E':			/* executable file name */
 | |
| 		opt_E = TRUE;
 | |
| 		if (optarg != (char *)NULL)
 | |
| 			strncpy(binfile, optarg, BUFF_MAX);
 | |
| 		else
 | |
| 			errors++;
 | |
| 		break;
 | |
| #endif
 | |
| 	case 'O':			/* object file name */
 | |
| 		opt_O = TRUE;
 | |
| 		if (optarg != (char *)NULL)
 | |
| 			strncpy(objfile, 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;
 | |
| 	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;
 | |
| 	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;
 | |
| 	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_m || opt_n ||
 | |
| 		opt_r || 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(objfile, argv[optind], BUFF_MAX);
 | |
| 
 | |
|   /* we must have a binary file of some sort */
 | |
|   if ((objfp = fopen(objfile, "rb")) == (FILE *)NULL ||
 | |
| 		stat(objfile, &statbuff) == -1) {
 | |
| 	perror(objfile);
 | |
| 	exit(1);
 | |
|   }
 | |
| 
 | |
|   /* initialise the object file data structures */
 | |
|   if (init_objf(objfp) == FAILED) {
 | |
| 	perror(objfile);
 | |
| 	exit(1);
 | |
|   }
 | |
| 
 | |
|   /* show the output file name and date */
 | |
|   fprintf(stdout, "File name: %s\nFile date: %s",
 | |
| 		objfile, ctime(&statbuff.st_ctime));
 | |
| 
 | |
|   /* show the header and section data - default behaviour */
 | |
|   if (opt_a || opt_h || (!opt_d && !opt_m && !opt_n &&
 | |
| 		!opt_r && !opt_s && !opt_t)) {
 | |
| 	fprintf(stdout, "\nHeader data:\n");
 | |
| 	(void) dump_ohdr(&o_hdrbuf);
 | |
| 	fprintf(stdout, "\nSection data:\n");
 | |
| 	(void) fseek(objfp, OFF_SECT(hdrbuf), SEEK_SET);
 | |
| 	(void) dump_oshdr(objfp, 0, o_hdrbuf.oh_nsect);
 | |
|   }
 | |
| 
 | |
|   /* The core start address is zero for every section.  What allowances
 | |
|    * should be made for the differences between file and core images?
 | |
|    */
 | |
| 
 | |
|   /* dump or disassemble the rom section */
 | |
|   if (opt_a || opt_m) {
 | |
| 	if (opt_b)
 | |
| 		(void) dump_osec(addrfirst, addrlast, ROM, FALSE);
 | |
| 	else
 | |
| 		(void) dump_osec(addrfirst, addrlast, ROM, TRUE);
 | |
|   }
 | |
| 
 | |
|   /* dump or disassemble the data section */
 | |
|   if (opt_a || opt_d) {
 | |
| 	if (opt_b)
 | |
| 		(void) dump_osec(addrfirst, addrlast, DATA, FALSE);
 | |
| 	else
 | |
| 		(void) dump_osec(addrfirst, addrlast, DATA, TRUE);
 | |
|   }
 | |
| 
 | |
|   /* dump or disassemble the text section */
 | |
|   if (opt_a || opt_t) {
 | |
| 	/* check that all offsets are valid */
 | |
| 	if (addrfirst > o_sectab[TEXT].os_flen || addrlast > o_sectab[TEXT].os_flen) {
 | |
| 		fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
 | |
| 						"text", addrfirst, addrlast);
 | |
| 	}
 | |
| 	else {
 | |
| 		if (opt_b)
 | |
| 			(void) dump_osec(addrfirst, addrlast, TEXT, FALSE);
 | |
| 		else {
 | |
| 			addrcount = (addrlast == 0) ? o_sectab[TEXT].os_flen : addrlast;
 | |
| 			addrcount -= addrfirst;
 | |
| 			disfp = objfp;			/* file to be disassembled */
 | |
| 			(void) fseek(disfp, o_sectab[TEXT].os_foff + addrfirst, SEEK_SET);
 | |
| 			fprintf(stdout, "\nDisassembled text:\n");
 | |
| 			(void) dasm(addrfirst, addrcount);
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   /* show the relocation data */
 | |
|   if (opt_a || opt_r) {
 | |
| 	if (opt_b)
 | |
| 		addrcount = o_hdrbuf.oh_nrelo * sizeof(struct outrelo);
 | |
| 	else
 | |
| 		addrcount = o_hdrbuf.oh_nrelo;
 | |
| 	/* check that all offsets are valid */
 | |
| 	if (addrfirst >= addrcount || addrlast >= addrcount) {
 | |
| 		fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
 | |
| 				"relocation", addrfirst, addrlast);
 | |
| 	}
 | |
| 	else {
 | |
| 		if (opt_l)
 | |
| 			addrcount = addrlast + 1;
 | |
| 		addrcount = addrcount - addrfirst;
 | |
| 		if (opt_b) {
 | |
| 			fprintf(stdout, "\nRelocation data dump:\n");
 | |
| 			(void) fseek(objfp, OFF_RELO(o_hdrbuf) + addrfirst, SEEK_SET);
 | |
| 			(void) dump_hex(objfp, addrfirst, addrcount);
 | |
| 		}
 | |
| 		else {
 | |
| 			fprintf(stdout, "\nRelocation data:\n");
 | |
| 			(void) fseek(objfp, OFF_RELO(o_hdrbuf) + addrfirst *
 | |
| 					sizeof(struct outrelo), SEEK_SET);
 | |
| 			(void) dump_orel(objfp, addrfirst, addrcount);
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   /* show the symbol data */
 | |
|   if (opt_a || opt_s) {
 | |
| 	if (opt_b)
 | |
| 		addrcount = o_hdrbuf.oh_nname * sizeof(struct outname);
 | |
| 	else
 | |
| 		addrcount = o_hdrbuf.oh_nname;
 | |
| 	/* check that all offsets are valid */
 | |
| 	if (addrfirst >= addrcount || addrlast >= addrcount) {
 | |
| 		fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
 | |
| 				"symbol", addrfirst, addrlast);
 | |
| 	}
 | |
| 	else {
 | |
| 		if (opt_l)
 | |
| 			addrcount = addrlast + 1;
 | |
| 		addrcount = addrcount - addrfirst;
 | |
| 		if (opt_b) {
 | |
| 			fprintf(stdout, "\nSymbol data dump:\n");
 | |
| 			(void) fseek(objfp, OFF_NAME(o_hdrbuf) + addrfirst, SEEK_SET);
 | |
| 			(void) dump_hex(objfp, addrfirst, addrcount);
 | |
| 		}
 | |
| 		else {
 | |
| 			fprintf(stdout, "\nSymbol data:\n");
 | |
| 			(void) fseek(objfp, OFF_NAME(o_hdrbuf) + addrfirst *
 | |
| 					sizeof(struct outname), SEEK_SET);
 | |
| 			(void) dump_osym(objfp, addrfirst, addrcount);
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   /* show the string data */
 | |
|   if (opt_a || opt_n) {
 | |
| 	if (opt_b)
 | |
| 		addrcount = o_hdrbuf.oh_nchar;
 | |
| 	else
 | |
| 		addrcount = o_hdrbuf.oh_nname;	/* assumes one name per symbol */
 | |
| 	/* check that all offsets are valid */
 | |
| 	if (addrfirst >= addrcount || addrlast >= addrcount) {
 | |
| 		fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
 | |
| 				"symbol", addrfirst, addrlast);
 | |
| 	}
 | |
| 	else {
 | |
| 		if (opt_l)
 | |
| 			addrcount = addrlast + 1;
 | |
| 		addrcount = addrcount - addrfirst;
 | |
| 		if (opt_b) {
 | |
| 			fprintf(stdout, "\nName data dump:\n");
 | |
| 			(void) fseek(objfp, OFF_CHAR(o_hdrbuf) + addrfirst, SEEK_SET);
 | |
| 			(void) dump_hex(objfp, addrfirst, addrcount);
 | |
| 		}
 | |
| 		else {
 | |
| 			fprintf(stdout, "\nName data:\n");
 | |
| 			(void) fseek(objfp, o_symtab[addrfirst].on_foff, SEEK_SET);
 | |
| 			(void) dump_ostr(objfp, addrfirst, addrcount);
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   /* wrap up */
 | |
|   fclose(objfp);
 | |
| 
 | |
|   exit(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * u s a g e
 | |
|  *
 | |
|  * Usage message.
 | |
|  *
 | |
|  * Returns:	Nothing		Always
 | |
|  */
 | |
| void usage()
 | |
| {
 | |
|   fprintf(stderr, "Usage: %s [-a|-dhmnrst] [-b] [-f #] [-l #] [-O objfile]\n",
 | |
| 		progname);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * EOF
 | |
|  */
 | |
| 
 | 
