From 98ddbffe6e88f1d496d6113e634340b1b9e85201 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Mon, 4 Oct 2010 13:26:53 +0000 Subject: [PATCH] dis386 - a disassembler for ack - it can disassemble object files (dis386o) and executables (dis386a) - only useful for as long as we still have ack --- commands/Makefile | 2 +- commands/dis386/Makefile | 9 + commands/dis386/const.h | 56 ++ commands/dis386/dis386.doc | 77 ++ commands/dis386/dis386.h | 46 ++ commands/dis386/dise.c | 1036 ++++++++++++++++++++++++++ commands/dis386/diso.c | 1322 +++++++++++++++++++++++++++++++++ commands/dis386/misc.c | 937 ++++++++++++++++++++++++ commands/dis386/out.h | 127 ++++ commands/dis386/type.h | 212 ++++++ commands/dis386/unasm.c | 1418 ++++++++++++++++++++++++++++++++++++ commands/dis386/var.h | 14 + 12 files changed, 5255 insertions(+), 1 deletion(-) create mode 100644 commands/dis386/Makefile create mode 100644 commands/dis386/const.h create mode 100644 commands/dis386/dis386.doc create mode 100644 commands/dis386/dis386.h create mode 100644 commands/dis386/dise.c create mode 100644 commands/dis386/diso.c create mode 100644 commands/dis386/misc.c create mode 100644 commands/dis386/out.h create mode 100644 commands/dis386/type.h create mode 100644 commands/dis386/unasm.c create mode 100644 commands/dis386/var.h diff --git a/commands/Makefile b/commands/Makefile index a55e7c826..dc561826c 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -9,7 +9,7 @@ SUBDIR= aal add_route adduser advent arp ash at autil awk \ chmod chown chroot ci cksum cleantmp clear cmp co \ comm compress cp crc cron crontab cut date \ dd de decomp16 DESCRIBE dev2name devsize df dhcpd \ - dhrystone diff dirname dis88 diskctl du dumpcore \ + dhrystone diff dirname dis386 dis88 diskctl du dumpcore \ ed eject elle elvis env expand factor file \ find finger fingerd fix fold format fortune fsck.mfs \ fsck1 ftp101 ftpd200 gcov-pull getty grep gomoku head hexdump host \ diff --git a/commands/dis386/Makefile b/commands/dis386/Makefile new file mode 100644 index 000000000..c81337284 --- /dev/null +++ b/commands/dis386/Makefile @@ -0,0 +1,9 @@ +# Makefile for dis386 + +PROGS= dis386e dis386o +SRCS.dis386e=dise.c misc.c unasm.c +SRCS.dis386o=diso.c misc.c unasm.c +MAN.dis386e= +MAN.dis386o= + +.include diff --git a/commands/dis386/const.h b/commands/dis386/const.h new file mode 100644 index 000000000..98cd093a5 --- /dev/null +++ b/commands/dis386/const.h @@ -0,0 +1,56 @@ +/* const.h - constants for db. + * + * $Id: const.h,v 1.0 1990/10/06 12:00:00 cwr Exp cwr $ + */ + +/* general constants */ +#define FALSE 0 +#undef NULL +#define NULL 0 +#define TRUE 1 + +/* C tricks */ +#define EXTERN extern +#define FORWARD static +#define PRIVATE static +#define PUBLIC + +/* ASCII codes */ +#define CAN 24 +#define CR 13 +#define EOF (-1) +#define LF 10 +#define XOFF 19 + +/* hardware processor-specific for 8088 through 80386 */ +#ifndef HCLICK_SIZE +#define HCLICK_SIZE 0x10 +#endif +#define IF 0x0200 /* interrupt disable bit in flags */ +#define INT_BREAKPOINT 0xCC /* byte for breakpoint interrupt */ +#define LINEARADR(seg, off) \ + (HCLICK_SIZE * (physoff_t) (segment_t) (seg) + (off)) +#define TF 0x0100 /* trap bit in flags */ + +/* hardware processor-specific for 80386 and emulated for others */ +#define BS 0x4000 /* single-step bit in dr6 */ + +/* use hardware codes for segments for simplest decoding */ +#define CSEG 0x2E /* 8088 through 80386 */ +#define DSEG 0x3E +#define ESEG 0x26 +#define FSEG 0x64 +#define GSEG 0x65 /* 80386 only */ +#define SSEG 0x36 + +/* software machine-specific for PC family */ +#define BIOS_DATA_SEG 0x40 +# define KB_FLAG 0x17 /* offset to 16-bits of keyboard shift flags */ + +/* switches to handle non-conforming compilers */ +#define UCHAR_BUG /* compiler converts unsigned chars wrong */ + +#ifdef UCHAR_BUG +# define UCHAR(x) ((x) & 0xFF) +#endif + diff --git a/commands/dis386/dis386.doc b/commands/dis386/dis386.doc new file mode 100644 index 000000000..44e7ef94e --- /dev/null +++ b/commands/dis386/dis386.doc @@ -0,0 +1,77 @@ +Dis36: a static disassembler for Minix 2.0. C W Rose, 20 Oct 97. + +SUMMARY + +This is the second release of dis386, a disassembler for Minix 2.0 At present +it is comprised of two programs, dise which understands executable files, and +diso which understands object files. The programs have been written using as +much common code as possible, and in time they will be merged. Meantime, they +are easier to debug separately. + +The two programs are both front ends for Bruce Evan's x86 disassembler. The +disassembler can handle both 16-bit and 32-bit code, but since the programs +use large data tables (kept in memory for speedy access) they have been tested +only on 32-bit Minix. + +The changes between versions 1.0 and 1.1 are small, but add to the ease of +use: addresses can now be entered in decimal or hexadecimal (leading 0x), +and starting offset and program counter now have more intelligble values. + +OPTIONS + +Object, executable and core files have the following structures, where +Name is the section name, and Option the option needed to display the section. + +Object file Executable file Core file +Name Option Name Option Name Option +Header } h Header h Memory map m +Section headers } Process table p +Sections - Sections - Sections - + text t text t text t + rom m + data d data d data d + bss - stack k +Relocation structures r +Symbol table s Symbol table s +Symbol names n + +Other options are: + -A str set executable file name + -C str set core file name + -O str set object file name + -a display all sections + -b dump in straight binary + -f # set the first address to be displayed + -l # set the last address to be displayed + -x # set debugging level + +Not all these options are functional at present; in particular, the file type +override of -A/C/O isn't implemented (since the programs are single-purpose). + +The default option is -h. The default input file is a.out for dise, and test.o +for diso. Otherwise, input is taken from the first file option on the command +line. Output is always written to standard output, and error messages to +standard error. + +BUGS AND FEATURES + +The programs search the data area for possible local symbols; generally, these +are the start of strings. At the moment this search is limited, and accepts +even single printing characters as strings; it should probably accept only +runs of three or more characters. + +There is no search for local text symbols, as opposed to data symbols; this +would need two full passes over the text with the disassembler, and doesn't +seem worthwhile. Once the data symbols are out of the way, the disassembled +text is fairly easy to read. + +The programs do a fair amount of error checking to ensure that they are +using eg. addresses that are within scope, but if they do fail they tend +to abandon the task completely and bale out with a (supposedly informative) +error message. + +There are many apparent dead-ends in the code, left as hooks for later +additions. + +/* eof */ + diff --git a/commands/dis386/dis386.h b/commands/dis386/dis386.h new file mode 100644 index 000000000..b1ab4f85a --- /dev/null +++ b/commands/dis386/dis386.h @@ -0,0 +1,46 @@ +/* + * dis386.h: header file for dis386.c. + * + * $Id: dis386.h,v 1.1 1997/10/20 12:00:00 cwr Exp cwr $ + * + * Written by C W Rose. + */ + +#ifndef EXTERN +#define EXTERN extern +#endif + +/* Generally used variables */ +struct locname { /* local symbol table entry */ + char l_name[8]; /* symbol name */ + unsigned char l_sclass; /* storage class */ + long l_value; /* symbol value */ + struct locname *l_next; /* pointer to next entry */ +}; +EXTERN struct locname *locsym[MAXSECT]; /* local symbol tables */ + +EXTERN FILE *aoutfp; /* executable file pointer */ +EXTERN FILE *corefp; /* core file pointer */ +EXTERN FILE *disfp; /* disassembly file pointer */ +EXTERN FILE *objfp; /* object file pointer */ +EXTERN FILE *symfp; /* symbol file pointer */ + +/* executable file variables */ +EXTERN struct exec a_hdrbuf; /* executable header structure */ +EXTERN struct nlist *a_symtab; /* executable symbol table */ + +/* .o file variables */ +EXTERN struct outhead o_hdrbuf; /* object file header data */ +EXTERN struct outsect o_sectab[MAXSECT];/* object file section data */ +EXTERN char *o_secnam[MAXSECT]; /* object file section names */ +EXTERN struct outrelo *o_reltab; /* object file relocation table */ +EXTERN struct outname *o_symtab; /* object file symbol table */ +EXTERN char *o_strtab; /* object file symbol names */ + +/* Generally used functions */ +PUBLIC int dasm(unsigned long addr, unsigned long count); /* disassemble opcodes */ + +/* + * EOF + */ + diff --git a/commands/dis386/dise.c b/commands/dis386/dise.c new file mode 100644 index 000000000..6ab857663 --- /dev/null +++ b/commands/dis386/dise.c @@ -0,0 +1,1036 @@ +/* + * 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 + */ + diff --git a/commands/dis386/diso.c b/commands/dis386/diso.c new file mode 100644 index 000000000..79a70cf57 --- /dev/null +++ b/commands/dis386/diso.c @@ -0,0 +1,1322 @@ +/* + * 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 +#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" /* 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 + */ + diff --git a/commands/dis386/misc.c b/commands/dis386/misc.c new file mode 100644 index 000000000..760d1ccff --- /dev/null +++ b/commands/dis386/misc.c @@ -0,0 +1,937 @@ +/* + * misc.c: interface to Bruce Evan's dis86 package. + * + * $Id: misc.c,v 1.1 1997/10/20 12:00:00 cwr Exp cwr $ + * + * Heavily modified by C W Rose. + */ + +/* Version settings */ +#define MINIX +#undef OS2 +#undef TEST + +#include +#ifdef MINIX +#include +#include +#include +#endif +#ifdef OS2 +typedef unsigned char u8_t; +typedef unsigned int u16_t; +typedef unsigned long u32_t; +#include +#include +#include +#endif +#include +#include +#include +#include +#include "const.h" +#include "type.h" +#undef S_ABS /* clash with a.out.h */ +#include "out.h" /* ACK compiler output header */ +#include "var.h" /* db header */ +#include "dis386.h" /* dis386 package header */ + +/* Standard defines */ +#define FAILED -1 +#define MAYBE 0 +#define OK 1 + +/* Local defines */ + +#ifndef lint +static char *Version = "@(#) misc.c $Revision: 1.1 $ $Date: 1997/10/20 12:00:00 $"; +#endif + +/* Global variables */ +PRIVATE bool_t forceupper; +PRIVATE bool_t someupper = TRUE; +PRIVATE count_t stringcount = 0; +PRIVATE char *string_ptr = (char *)0; /* stringptr ambiguous at 8th char */ +PRIVATE char *stringstart = (char *)0; + +/* Externals */ + +/* Forward declarations */ +#if 0 +PUBLIC void closestring(void); /* */ +PUBLIC u8_pt get8(void); /* */ +PUBLIC u16_t get16(void); /* */ +PUBLIC u32_t get32(void); /* */ +PUBLIC void openstring(char *string, int len); /* */ +PUBLIC void outbyte(char_pt byte); /* */ +PUBLIC void outcolon(void); /* */ +PUBLIC void outcomma(void); /* */ +PUBLIC void outh4(u4_pt num); /* */ +PUBLIC void outh8(u8_pt num); /* */ +PUBLIC void outh16(u16_t num); /* */ +PUBLIC void outh32(u32_t num); /* */ +PUBLIC bool_pt outnl(void); /* */ +PUBLIC count_t outsegaddr(struct address_s *ap, offset_t addr); /* */ +PUBLIC count_t outsegreg(offset_t num); /* */ +PUBLIC void outspace(void); /* */ +PUBLIC void outstr(char *s); /* */ +PUBLIC void outtab(void); /* */ +PUBLIC void outustr(char *s); /* */ +PUBLIC count_t stringpos(void); /* */ +PUBLIC count_t stringtab(void); /* */ +PUBLIC void outrel(struct nlist *sp, offset_t off); /* */ +PUBLIC void outsym(struct nlist *sp, offset_t off); /* */ +PUBLIC struct nlist *findrval(offset_t value, int where);/* */ +PUBLIC struct nlist *findsval(offset_t value, int where);/* */ +PUBLIC int dasm(offset_t addr, offset_t count); /* */ +#endif + +PRIVATE u8_pt peek8(struct address_s *ap); /* */ +PRIVATE u16_t peek16(struct address_s *ap); /* */ +PRIVATE u32_t peek32(struct address_s *ap); /* */ +PRIVATE struct nlist *find_arval(offset_t value, int where); /* */ +PRIVATE struct nlist *find_orval(offset_t value, int where); /* */ +PRIVATE struct nlist *find_asval(offset_t value, int where); /* */ +PRIVATE struct nlist *find_osval(offset_t value, int where); /* */ +PRIVATE int dis_one(void); /* */ + + +/* + * Close string device. + */ +PUBLIC void closestring() +{ + stringcount = 0; + stringstart = string_ptr = (char *)0; +} + + +/* + * Get 8 bits from current instruction pointer and advance pointer. + */ +PUBLIC u8_pt get8() +{ + u8_pt temp; + + temp = peek8(&uptr); + ++uptr.off; + return temp; +} + + +/* + * Get 16 bits from current instruction pointer and advance pointer. + */ +PUBLIC u16_pt get16() +{ + u16_pt temp; + + temp = peek16(&uptr); + uptr.off += 2; + return temp; +} + + +/* + * Get 32 bits from current instruction pointer and advance pointer. + */ +PUBLIC u32_t get32() +{ + u32_t temp; + + temp = peek32(&uptr); + uptr.off += 4; + return temp; +} + + +/* + * Open string device. + */ +PUBLIC void openstring(string, len) +char *string; int len; +{ + while (--len >= 0) + string[len] = '\0'; + stringcount = 0; + stringstart = string_ptr = string; +} + + +/* + * Print char to currently open output devices. + */ +PUBLIC void outbyte(char_pt byte) +{ + /* convert to upper case if required */ + if (forceupper && byte >= 'a' && byte <= 'z') + byte += 'A' - 'a'; + + /* increment the output line character count, allowing for tab stops */ + if (string_ptr != NULL) { + if ((*string_ptr++ = byte) == '\t') + stringcount = 8 * (stringcount / 8 + 1); + else + ++stringcount; + } + else + (void) fputc(byte, stdout); +} + + +/* + * Print colon. + */ +PUBLIC void outcolon() +{ + outbyte(':'); +} + + +/* + * Print comma. + */ +PUBLIC void outcomma() +{ + outbyte(','); +} + + +/* + * Print 4 bits hex. + */ +PUBLIC void outh4(u4_pt num) +{ + static char hexdigits[] = "0123456789abcdef"; + + forceupper = someupper; + outbyte(hexdigits[num % 16]); + forceupper = FALSE; +} + + +/* + * Print 8 bits hex. + */ +PUBLIC void outh8(u8_pt num) +{ + outh4(num / 16); + outh4(num); +} + + +/* + * Print 16 bits hex. + */ +PUBLIC void outh16(u16_pt num) +{ + outh8(num / 256); + outh8(num); +} + + +/* + * Print 32 bits hex. + */ +PUBLIC void outh32(u32_t num) +{ + outh16((u16_t) (num >> 16)); + outh16((u16_t) num); +} + + +/* + * Print newline. + */ +PUBLIC bool_pt outnl() +{ + /* bool_pt avoids change in type.h */ + outstr("\n"); + return OK; +} + + +/* + * Print segmented address. + */ +PUBLIC count_t outsegaddr(struct address_s *ap, offset_t addr) +{ + count_t bytes_printed; + + bytes_printed = 2; + + if (ap->base == regs.csbase) + outustr("cs"); + else if (ap->base == regs.dsbase) + outustr("ds"); + else if (ap->base == regs.esbase) + outustr("es"); + else if (processor >= 386 && ap->base == regs.fsbase) + outustr("fs"); + else if (processor >= 386 && ap->base == regs.gsbase) + outustr("gs"); + else if (ap->base == regs.ssbase) + outustr("ss"); + else + bytes_printed = outsegreg(ap->base); + + if (bytes_printed > 4) + outbyte('+'); + else + outcolon(); + bytes_printed++; + + if (ap->off >= 0x10000) { + outh32(ap->off + addr); + return bytes_printed + 8; + } + else { + outh16((u16_pt) ap->off + addr); + return bytes_printed + 4; + } +} + + +/* + * Print segment register. + */ +PUBLIC count_t outsegreg(offset_t num) +{ + if ((num % HCLICK_SIZE) != 0 || num >= 0x100000) { + outh32(num); + return 8; + } + outh16((u16_pt) (num / HCLICK_SIZE)); + return 4; +} + + +/* + * Print space. + */ +PUBLIC void outspace() +{ + outbyte(' '); +} + + +/* + * Print string. + */ +PUBLIC void outstr(char *s) +{ + while (*s) + outbyte(*s++); +} + +/* + * Print tab. + */ +PUBLIC void outtab() +{ + outbyte('\t'); +} + + +/* + * Print string, perhaps converting case to upper. + */ +PUBLIC void outustr(char *s) +{ + forceupper = someupper; + while (*s) + outbyte(*s++); + forceupper = FALSE; +} + + +/* + * p e e k 8 + * + * Get a byte from the process. + * + * Returns: byte Success + * + * Note: aborts on read error. + */ +PRIVATE u8_pt peek8(struct address_s *ap) +{ + unsigned int uj; + + /* with luck buffering should make this fairly quick */ + if (fseek(disfp, (long)(ap->off), SEEK_CUR) != 0) { + fprintf(stderr, "Cannot seek forward in object file\n"); + exit(1); + } + uj = fgetc(disfp) & 0377; + if (fseek(disfp, -(long)(ap->off + 1), SEEK_CUR) != 0) { + fprintf(stderr, "Cannot seek backward in object file\n"); + exit(1); + } + + return uj; +} + + +/* + * p e e k 1 6 + * + * Get a 16-bit short from the process. + * + * Returns: 2 bytes Success + * + * Note: aborts on read error. + */ +PRIVATE u16_t peek16(struct address_s *ap) +{ + unsigned int uj; + + /* with luck buffering should make this fairly quick */ + if (fseek(disfp, (long)(ap->off), SEEK_CUR) != 0) { + fprintf(stderr, "Cannot seek forward in object file\n"); + exit(1); + } + /* Intel has right to left byte ordering */ +#if 1 + uj = fgetc(disfp) & 0377; + uj |= (fgetc(disfp) & 0377) << 8; +#else + uj = fgetc(disfp) & 0377; + uj <<= 8; + uj |= fgetc(disfp) & 0377; +#endif + if (fseek(disfp, -(long)(ap->off + 2), SEEK_CUR) != 0) { + fprintf(stderr, "Cannot seek backward in object file\n"); + exit(1); + } + + return uj; +} + + +/* + * p e e k 3 2 + * + * Get a 32-bit int from the process. + * + * Returns: 4 bytes Success + * + * Note: aborts on read error. + */ +PRIVATE u32_t peek32(struct address_s *ap) +{ + unsigned int uj; + + /* with luck buffering should make this fairly quick */ + if (fseek(disfp, (long)(ap->off), SEEK_CUR) != 0) { + fprintf(stderr, "Cannot seek forward in object file\n"); + exit(1); + } +#if 1 + /* Intel has right to left byte ordering */ + uj = fgetc(disfp) & 0377; + uj |= (fgetc(disfp) & 0377) << 8; + uj |= (fgetc(disfp) & 0377) << 16; + uj |= (fgetc(disfp) & 0377) << 24; +#else + uj = fgetc(disfp) & 0377; + uj <<= 8; + uj |= fgetc(disfp) & 0377; + uj <<= 8; + uj |= fgetc(disfp) & 0377; + uj <<= 8; + uj |= fgetc(disfp) & 0377; +#endif + if (fseek(disfp, -(long)(ap->off + 4), SEEK_CUR) != 0) { + fprintf(stderr, "Cannot seek backward in object file\n"); + exit(1); + } + + return uj; +} + + +/* + * Return current offset of string device. + */ +PUBLIC count_t stringpos() +{ + return string_ptr - stringstart; +} + + +/* + * Return current "tab" spot of string device. + */ +PUBLIC count_t stringtab() +{ + return stringcount; +} + +/******************** sym.c ***********************/ + +/* + * f i n d r v a l + * + * Check if an address refers to a relocation structure, + * and if so return the table entry. + * + * Returns: Pointer to struct nlist Success + * Null pointer Failure + * + * Note that the nlist interface must be maintained for use by unasm(). + */ +PUBLIC struct nlist *findrval(offset_t value, int where) +{ + if (aoutfp != (FILE *)NULL) + return (find_arval(value, where)); + else if (objfp != (FILE *)NULL) + return (find_orval(value, where)); + else + return (struct nlist *)NULL; +} + + +/* + * f i n d _ a r v a l + * + * Check if an address refers to an a.out file relocation structure, + * and if so return the table entry. + * + * Returns: Pointer to struct nlist Success + * Null pointer Failure + * + * Note that the nlist interface must be maintained for use by unasm(). + * ### Do any available ACK compilers have this feature? + */ +PRIVATE struct nlist *find_arval(offset_t value, int where) +{ + return (struct nlist *)NULL; +} + + +/* + * f i n d _ o r v a l + * + * Check if an address refers to an object file relocation structure, + * and if so return the table entry. + * + * Returns: Pointer to struct nlist Success + * Null pointer Failure + * + * Note that the nlist interface must be maintained for use by unasm(). + * The table entry is stored in a static buffer which is overwritten + * on successive calls. + */ +PRIVATE struct nlist *find_orval(offset_t value, int where) +{ + char data[20]; + int j, k, status; + long int lj; + static struct nlist sym; + + /* we need to have an object file */ + if (objfp == (FILE *)NULL) return (struct nlist *)NULL; + + /* Sections in an object file usually have the order text, rom, data, bss. + * The order is actually set out in the section data header. Assume that + * the first user section is text, and all else is data. + */ + if (where != CSEG && where != DSEG) + return(struct nlist *)NULL; + + /* check for a relocation entry */ + status = FAILED; + for (j = 0 ; j < o_hdrbuf.oh_nrelo ; j++) { + if (value == o_reltab[j].or_addr) { + /* abandon non-matching section entries */ + if (where == CSEG && (o_reltab[j].or_sect & S_TYP) != S_MIN) + continue; + if (where == DSEG && ((o_reltab[j].or_sect & S_TYP) <= S_MIN || + (o_reltab[j].or_sect & S_TYP) > (S_MIN + 3))) + continue; + /* the address is an offset from the symbol or section base */ + if (o_reltab[j].or_nami < o_hdrbuf.oh_nname) { + lj = o_symtab[o_reltab[j].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); + /* convert from rel table to executable symbol table format */ + for (k = 0 ; k < sizeof(sym.n_name) ; k++) { + sym.n_name[k] = data[k];/* 8 characters */ + } + sym.n_value = o_symtab[o_reltab[j].or_nami].on_valu; + /* long */ +#if 1 + sym.n_sclass = (where == CSEG) ? N_TEXT : N_DATA; +#else + sym.n_sclass = (o_symtab[o_reltab[j].or_nami].on_type & + S_TYP) - S_MIN; /* unsigned char */ +#endif + sym.n_numaux = 0; /* unsigned char */ + sym.n_type = 0; /* unsigned short */ + status = OK; + break; + } + /* the address is an absolute number relative to the pc */ + else if (o_reltab[j].or_nami == o_hdrbuf.oh_nname) { + strcpy(data, "Absolute"); + /* convert from relocation data to executable symbol table format */ + for (k = 0 ; k < sizeof(sym.n_name) ; k++) { + sym.n_name[k] = data[k]; + } + sym.n_value = 0; + sym.n_sclass = (where == CSEG) ? N_TEXT : N_DATA; + sym.n_numaux = 0; + sym.n_type = 0; + status = OK; + break; + } + } + } + return (status == OK ? &sym : (struct nlist *)NULL); +} + + +/* + * f i n d s v a l + * + * Check if an address refers to a symbol, + * and if so return the table entry. + * + * Returns: Pointer to struct nlist Success + * Null pointer Failure + * + * Note that the nlist interface must be maintained for use by unasm(). + */ +PUBLIC struct nlist *findsval(offset_t value, int where) +{ + if (aoutfp != (FILE *)NULL) + return (find_asval(value, where)); + else if (objfp != (FILE *)NULL) + return (find_osval(value, where)); + else + return (struct nlist *)NULL; +} + + +/* + * f i n d _ a s v a l + * + * Check if an address refers to an a.out file symbol, + * and if so return the table entry. + * + * Returns: Pointer to struct nlist Success + * Null pointer Failure + * + * Note that the nlist interface must be maintained for use by unasm(). + * The table entry is stored in a static buffer which is overwritten + * on successive calls. + */ +PRIVATE struct nlist *find_asval(offset_t value, int where) +{ + int j, status; + static struct nlist sym; + + /* Sections in an a.out file have the order text, data, bss + * but this function is called only with CSEG and DSEG. + */ + if (where != CSEG && where != DSEG) + return(struct nlist *)NULL; + + /* do a linear search for a symbol, as the symbol tables are unsorted */ + status = FAILED; + for (j = 0 ; j < (a_hdrbuf.a_syms / sizeof(struct nlist)) ; j++) { + if (value == a_symtab[j].n_value && + ((where == CSEG && (a_symtab[j].n_sclass & N_SECT) == N_TEXT) || + (where == DSEG && ((a_symtab[j].n_sclass & N_SECT) == N_DATA || + (a_symtab[j].n_sclass & N_SECT) == N_BSS)))) { + (void) memcpy(&sym, &a_symtab[j], sizeof(struct nlist)); + status = OK; + break; + } + } + return (status == OK) ? &sym : (struct nlist *)NULL; +} + + +/* + * f i n d _ o s v a l + * + * Check if an address refers to an object file symbol, + * and if so return the table entry. + * + * Returns: Pointer to struct nlist Success + * Null pointer Failure + * + * Note that the nlist interface must be maintained for use by unasm(). + * The table entry is stored in a static buffer which is overwritten + * on successive calls. + */ +PRIVATE struct nlist *find_osval(offset_t value, int where) +{ + int j, k, sec, status; + long int lj; + struct locname *np; + static struct nlist sym; + + /* Sections in an object file usually have the order text, rom, data, bss. + * The order is actually set out in the section data header. Assume that + * the first user section is text, and all else is data. + */ + if (where != CSEG && where != DSEG) + return(struct nlist *)NULL; + + /* do a linear search for a local symbol, as the tables are unsorted */ + status = FAILED; + if (where == DSEG) { + /* nb. hardcoded assumption of section order */ + for (sec = 1 ; status == FAILED && sec < 4 ; sec++) { + for (np = locsym[sec] ; status == FAILED && np != + (struct locname *)NULL ; np = np->l_next) { + if (np->l_value == value) { + for (k = 0 ; k < sizeof(sym.n_name) ; k++) { + sym.n_name[k] = np->l_name[k];/* 8 characters */ + } + sym.n_value = value; /* long */ + sym.n_sclass = N_DATA; /* unsigned char */ + sym.n_numaux = 0; /* unsigned char */ + sym.n_type = 0; /* unsigned short */ + status = OK; + } + } + } + } + + /* do a linear search for a symbol, as the symbol tables are unsorted */ + for (j = 0 ; status == FAILED && j < o_hdrbuf.oh_nname ; j++) { + if (value == o_symtab[j].on_valu) { + /* abandon non-matching section entries */ + if (where == CSEG && (o_symtab[j].on_type & S_TYP) != S_MIN) + continue; + if (where == DSEG && ((o_symtab[j].on_type & S_TYP) <= S_MIN || + (o_symtab[j].on_type & S_TYP) > (S_MIN + 3))) + continue; +#if 0 + ((where == CSEG && sect == (o_symtab[j].on_type & S_TYP)) || + (where == DSEG && sect <= (o_symtab[j].on_type & S_TYP)))) { +#endif + /* find the name in the object file symbol table */ + lj = o_symtab[j].on_foff - (long)OFF_CHAR(o_hdrbuf); + /* check that the offset addressing isn't messed up */ + assert(lj >= 0 && lj < o_hdrbuf.oh_nchar); + /* convert from object to executable symbol table format */ + for (k = 0 ; k < sizeof(sym.n_name) ; k++) { + sym.n_name[k] = *(o_strtab + lj + k); + /* 8 characters */ + } + sym.n_value = o_symtab[j].on_valu; /* long */ + sym.n_sclass = (where == CSEG) ? N_TEXT : N_DATA; + /* unsigned char */ + sym.n_numaux = 0; /* unsigned char */ + sym.n_type = 0; /* unsigned short */ + status = OK; + } + } + + return (status == OK ? &sym : (struct nlist *)NULL); +} + + +/* + * o u t r e l + * + * Output a symbol name from an nlist structure. + * + * Returns: Nothing Always + * + * Note that the nlist interface must be maintained for use by unasm(). + * The label may be a segment name, in which case the address is relative + * to that segment and must be dereferenced further. + */ +PUBLIC void outrel(struct nlist *sp, offset_t off) +{ + char data[20]; + int j, k; + struct nlist *spnew; + + /* get a local copy of the label */ + for (j = 0 ; j < 20 ; j++) { + data[j] = sp->n_name[j]; + if (data[j] == ' ' || data[j] == '\0') + break; + } + data[j] = '\0'; + data[8] = '\0'; + + /* see if we have a section name */ + for (k = 0 ; k < 4 ; k++) { + if (strcmp(data, o_secnam[k]) == 0) { + /* look up the name in the appropriate section */ + if ((spnew = findsval(off, (k ? DSEG : CSEG))) != (struct nlist *)NULL) { + /* get a local copy of the label */ + for (j = 0 ; j < 20 ; j++) { + data[j] = spnew->n_name[j]; + if (data[j] == '\0') break; + } + data[8] = '\0'; + } + } + } + + /* output the result */ + for (j = 0 ; data[j] != 0 ; j++) + outbyte(data[j]); +} + + +/* + * o u t s y m + * + * Output a symbol name from an nlist structure. + * + * Returns: Nothing Always + * + * Note that the nlist interface must be maintained for use by unasm(). + */ +PUBLIC void outsym(struct nlist *sp, offset_t off) +{ + char *s; + char *send; + + /* output the symbol name */ + for (s = sp->n_name, send = s + sizeof sp->n_name; *s != 0 && s < send; ++s) + outbyte(*s); + + /* if the required address is offset from the name, output that too */ + if ((off -= sp->n_value) != 0) { + outbyte('+'); + if (off >= 0x10000) + outh32(off); + else if (off >= 0x100) + outh16((u16_pt) off); + else + outh8((u8_pt) off); + } +} + + +/* + * d a s m + * + * Disassemble a stream of instructions. + * + * Returns: OK Success + * FAILED Otherwise + */ +PUBLIC int dasm(offset_t addr, offset_t count) +{ +#if (_WORD_SIZE == 4) + bits32 = TRUE; /* set mode */ +#else + bits32 = FALSE; +#endif + processor = bits32 ? 386 : 0; + uptr.off = 0; + uptr.base = 0; + + while (uptr.off < count) { + addrbase = addr; + /* assume that the object file text segment is first */ + if (objfp != (FILE *)NULL && uptr.off >= o_sectab[0].os_flen) + return FAILED; + if (aoutfp != (FILE *)NULL && uptr.off >= (A_DATAPOS(a_hdrbuf) - 1)) + return FAILED; + if (dis_one() == FAILED) + return FAILED; + } + return OK; +} + + +/* + * d i s _ o n e + * + * Disassemble a single instruction. + * + * Returns: OK Always + * + * File read failures are handled at a low level by simply + * baling out of the program; the startup checks on file + * readability should make this a rare occurrence. Hence + * there are no error returns from this routine. + * The output is written into a static line buffer, which + * is overwritten on successive calls. + */ +PRIVATE int dis_one() +{ + int idone, column, maxcol; + static char line[81]; + struct address_s newuptr; + struct address_s olduptr; + struct nlist *sp; + + do { + /* output a label */ + if ((sp = findsval(uptr.off + addrbase, CSEG)) != NULL + && sp->n_value == uptr.off + addrbase) { + outsym(sp, uptr.off + addrbase); + outbyte(':'); + (void) outnl(); + } + + /* park the current address */ + olduptr = uptr; + + /* initialise the string input */ + openstring(line, sizeof(line)); + + /* output an instruction */ + idone = puti(); + + /* terminate the line buffer */ + line[stringpos()] = 0; + + /* deinitialise the string input */ + closestring(); + + /* park the new address, set by puti() */ + newuptr = uptr; + + /* get back the current address */ + uptr = olduptr; + + /* output the segment data */ + column = outsegaddr(&uptr, addrbase); + outspace(); + outspace(); + column += 2; + + /* output the raw bytes of the current instruction */ + while (uptr.off != newuptr.off) { + outh8(get8()); + column += 2; + } + + /* format the disassembled output */ + maxcol = bits32 ? 24 : 16; + while (column < maxcol) { + outtab(); + column += 8; + } + outtab(); + + /* display the collected buffer */ + outstr(line); + (void) outnl(); + } while (!idone); /* eat all prefixes */ + + return OK; +} + +/* + * EOF + */ + diff --git a/commands/dis386/out.h b/commands/dis386/out.h new file mode 100644 index 000000000..d68938a86 --- /dev/null +++ b/commands/dis386/out.h @@ -0,0 +1,127 @@ +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* $Header: out.h,v 1.1 91/05/16 14:09:17 ceriel Exp $ */ + +#ifndef __OUT_H_INCLUDED +#define __OUT_H_INCLUDED +/* + * output format for ACK assemblers + */ +#ifndef ushort +#define ushort unsigned short +#endif /* ushort */ + +struct outhead { + ushort oh_magic; /* magic number */ + ushort oh_stamp; /* version stamp */ + ushort oh_flags; /* several format flags */ + ushort oh_nsect; /* number of outsect structures */ + ushort oh_nrelo; /* number of outrelo structures */ + ushort oh_nname; /* number of outname structures */ + long oh_nemit; /* sum of all os_flen */ + long oh_nchar; /* size of string area */ +}; + +#define O_MAGIC 0x0201 /* magic number of output file */ +#define O_STAMP 0 /* version stamp */ +#define MAXSECT 64 /* Maximum number of sections */ + +#define HF_LINK 0x0004 /* unresolved references left */ +#define HF_8086 0x0008 /* os_base specially encoded */ + +struct outsect { + long os_base; /* startaddress in machine */ + long os_size; /* section size in machine */ + long os_foff; /* startaddress in file */ + long os_flen; /* section size in file */ + long os_lign; /* section alignment */ +}; + +struct outrelo { + char or_type; /* type of reference */ + char or_sect; /* referencing section */ + ushort or_nami; /* referenced symbol index */ + long or_addr; /* referencing address */ +}; + +struct outname { + union { + char *on_ptr; /* symbol name (in core) */ + long on_off; /* symbol name (in file) */ + } on_u; +#define on_mptr on_u.on_ptr +#define on_foff on_u.on_off + ushort on_type; /* symbol type */ + ushort on_desc; /* debug info */ + long on_valu; /* symbol value */ +}; + +/* + * relocation type bits + */ +#define RELSZ 0x07 /* relocation length */ +#define RELO1 1 /* 1 byte */ +#define RELO2 2 /* 2 bytes */ +#define RELO4 4 /* 4 bytes */ +#define RELPC 0x08 /* pc relative */ +#define RELBR 0x10 /* High order byte lowest address. */ +#define RELWR 0x20 /* High order word lowest address. */ + +/* + * section type bits and fields + */ +#define S_TYP 0x007F /* undefined, absolute or relative */ +#define S_EXT 0x0080 /* external flag */ +#define S_ETC 0x7F00 /* for symbolic debug, bypassing 'as' */ + +/* + * S_TYP field values + */ +#define S_UND 0x0000 /* undefined item */ +#define S_ABS 0x0001 /* absolute item */ +#define S_MIN 0x0002 /* first user section */ +#define S_MAX (S_TYP-1) /* last user section */ +#define S_CRS S_TYP /* on_valu is symbol index which contains value */ + +/* + * S_ETC field values + */ +#define S_SCT 0x0100 /* section names */ +#define S_LIN 0x0200 /* hll source line item */ +#define S_FIL 0x0300 /* hll source file item */ +#define S_MOD 0x0400 /* ass source file item */ +#define S_COM 0x1000 /* Common name. */ +#define S_STB 0xe000 /* entries with any of these bits set are + reserved for debuggers + */ + +/* + * structure format strings + */ +#define SF_HEAD "22222244" +#define SF_SECT "44444" +#define SF_RELO "1124" +#define SF_NAME "4224" + +/* + * structure sizes (bytes in file; add digits in SF_*) + */ +#define SZ_HEAD 20 +#define SZ_SECT 20 +#define SZ_RELO 8 +#define SZ_NAME 12 + +/* + * file access macros + */ +#define BADMAGIC(x) ((x).oh_magic!=O_MAGIC) +#define OFF_SECT(x) SZ_HEAD +#define OFF_EMIT(x) (OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT)) +#define OFF_RELO(x) (OFF_EMIT(x) + (x).oh_nemit) +#define OFF_NAME(x) (OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO)) +#define OFF_CHAR(x) (OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME)) + +#endif /* __OUT_H_INCLUDED */ + diff --git a/commands/dis386/type.h b/commands/dis386/type.h new file mode 100644 index 000000000..f11b5e238 --- /dev/null +++ b/commands/dis386/type.h @@ -0,0 +1,212 @@ +/* type.h - types for db. + * + * $Id: type.h,v 1.1 1997/10/20 12:00:00 cwr Exp cwr $ + */ + +typedef unsigned long bigcount_t; +typedef unsigned long flags_t; +typedef int bool_pt; +typedef char bool_t; +typedef int char_pt; +typedef int char16_t; /* ASCII character possibly with scan code */ +typedef unsigned count_t; +typedef unsigned long offset_t; +typedef unsigned opcode_pt; /* promote to unsigned and not int */ +typedef int (*pfi_t)(); +typedef void (*pfv_t)(); +typedef unsigned long physoff_t; +typedef unsigned peekboff_t; +typedef unsigned peekoff_t; +typedef int peekseg_t; +typedef unsigned port_t; +typedef int reg_pt; +typedef unsigned char reg_t; +typedef unsigned segment_t; +typedef long soffset_t; +typedef int su8_pt; +typedef int su16_t; +typedef unsigned u4_pt; /* promote to unsigned and not int */ +typedef unsigned u8_pt; +typedef unsigned u16_pt; + +struct address_s +{ + offset_t off; + offset_t base; +}; + +struct desctableptr_s { + u16_t limit; + u32_t base; /* really u24_t + pad for 286 */ +}; + +struct regs_s +{ + offset_t ax; + offset_t bx; + offset_t cx; + offset_t dx; + offset_t si; + offset_t di; + offset_t bp; + offset_t sp; + offset_t dsbase; + offset_t esbase; + offset_t fsbase; + offset_t gsbase; + offset_t ssbase; + offset_t csbase; + offset_t ip; + flags_t f; + offset_t ds; + offset_t es; + offset_t fs; + offset_t gs; + offset_t ss; + offset_t cs; +}; + +struct specregs_s +{ + u32_t cr0; /* control regs, cr0 is msw + pad for 286 */ + u32_t cr2; + u32_t cr3; + u32_t dr0; /* debug regs */ + u32_t dr1; + u32_t dr2; + u32_t dr3; + u32_t dr6; + u32_t dr7; + u32_t tr6; /* test regs */ + u32_t tr7; + u16_t gdtlimit; + u32_t gdtbase; /* depend on 16-bit compiler so no long align */ + u16_t gdtpad; + u16_t idtlimit; + u32_t idtbase; + u16_t idtpad; + u16_t ldtlimit; + u32_t ldtbase; + u16_t ldt; + u16_t tr; /* task register */ + u16_t trpad; +}; + +/* prototypes */ + +#if __STDC__ +#define P(x) x +#else +#define P(x) () +#endif + +/* library, very few! */ +void *memcpy P((void *dst, const void *src, unsigned size)); +void *memmove P((void *dst, const void *src, unsigned size)); +unsigned strlen P((const char *s)); +char *strncpy P((char *dst, const char *src, unsigned size)); + +/* db.c */ +void db_main P((void)); +void get_kbd_state P(()); +void get_scr_state P(()); +void info P((void)); +void reboot P((void)); +void reset_kbd_state P(()); + +/* getline.c */ +char *getline P((char *startline, unsigned maxlength, unsigned offset)); + +/* ihexload.c */ +void ihexload P((void)); + +/* io.c */ +void can_itty P((void)); +void can_keyboard P((void)); +void can_otty P((void)); +void can_screen P((void)); +void closeio P((void)); +void closestring P((void)); +void enab_itty P((void)); +void enab_keyboard P((void)); +void enab_otty P((void)); +void enab_screen P((void)); +void flipcase P((void)); +u8_pt get8 P((void)); +u16_pt get16 P((void)); +u32_t get32 P((void)); +char16_t inchar P((void)); +char_pt mytolower P((char_pt ch)); +void openio P((void)); +void openstring P((char *string, int length)); +void outbyte P((char_pt byte)); +void outcomma P((void)); +void outh4 P((u4_pt num)); +void outh8 P((u8_pt num)); +void outh16 P((u16_pt num)); +void outh32 P((u32_t num)); +bool_pt outnl P((void)); +count_t outsegaddr P((struct address_s *ap, offset_t addr)); +count_t outsegreg P((offset_t num)); +void outspace P((void)); +void outstr P((char *s)); +void outtab P((void)); +void outustr P((char *s)); +void set_tty P((void)); +void show_db_screen P((void)); +void show_user_screen P((void)); +count_t stringpos P((void)); +count_t stringtab P((void)); +char_pt testchar P((void)); + +/* lib88.s */ +int get_privilege P((void)); +unsigned get_processor P((void)); +unsigned in16portb P((port_t port)); +physoff_t linear2addr P((segment_t segment, u16_pt offset)); +void oportb P((port_t port, u8_pt value)); +u8_pt peek_byte P((physoff_t offset)); +u16_pt peek_word P((physoff_t offset)); +u32_t peek_dword P((physoff_t offset)); +void poke_byte P((physoff_t offset, u8_pt value)); +void poke_word P((physoff_t offset, u16_pt value)); +#ifdef N_TEXT +void symswap P((struct nlist *left, struct nlist *right, + segment_t tableseg, unsigned length)); +#endif + +/* pcio.c */ +void kbdclose P((void)); +char_pt kbdin P((void)); +void kbdioctl P((int command)); +void kbdopen P((void)); +void kbdout P((int c)); + +/* screen.s */ +void scrclose P((void)); +void scrioctl P((int command)); +char_pt scrin P((void)); +void scropen P((void)); +void scrout P((char_pt c)); + +/* sym.c */ +#ifdef N_TEXT +struct nlist *findsname P((char *name, int where, bool_pt allflag)); +struct nlist *findsval P((offset_t value, int where)); +struct nlist *findrval P((offset_t value, int where)); +void outsym P((struct nlist *sp, offset_t off)); +void outrel P((struct nlist *sp, offset_t off)); +#endif +void setproc P((char_pt c, struct address_s *pdptr, struct address_s *pmptr)); +void syminit P((void)); + +/* tty.s */ +void ttyclose P((void)); +void ttyioctl P((int command)); +char_pt ttyin P((void)); +void ttyopen P((void)); +void ttyout P((char_pt c)); + +/* unasm.c */ +bool_pt puti P((void)); + diff --git a/commands/dis386/unasm.c b/commands/dis386/unasm.c new file mode 100644 index 000000000..629762198 --- /dev/null +++ b/commands/dis386/unasm.c @@ -0,0 +1,1418 @@ +/* + * unasm.c: Bruce Evan's dis86 package. + * + * $Id: unasm.c,v 1.1 1997/10/20 12:00:00 cwr Exp cwr $ + * + * Minimal changes by C W Rose. + */ + +/* Version settings */ +#define MINIX +#undef OS2 +#undef TEST + +#ifdef MINIX +#include +#include +#endif +#ifdef OS2 +typedef unsigned char u8_t; +typedef unsigned int u16_t; +typedef unsigned long u32_t; +#include +#endif +#include "const.h" +#include "type.h" +#undef EXTERN +#define EXTERN +#include "var.h" + +#define LINDIRECT '[' +#define RINDIRECT ']' + +#define BASE_MASK 0x07 +#define INDEX_MASK 0x38 +#define INDEX_SHIFT 3 +#define MOD_MASK 0xC0 /* mod reg r/m is mmrrrRRR */ +# define REG_MOD 0xC0 +# define MEM0_MOD 0x00 +# define MEM1_MOD 0x40 +# define MEM2_MOD 0x80 +#define REG_MASK 0x38 +#define REG_SHIFT 3 +#define RM_MASK 0x07 +#define RM_SHIFT 0 +#define SS_MASK 0xC0 +#define SS_SHIFT 6 + +#define SIGNBIT 0x02 /* opcode bits xxxxxxsw for immediates */ +#define WORDBIT 0x01 +#define TOREGBIT 0x02 /* opcode bit for non-immediates */ + +#define MAX_SIGNED_CHAR 0x7F /* will assume 2's complement */ +#define MAX_UNSIGNED_CHAR 0xFF + +FORWARD void CL P((void)); +FORWARD void Eb P((void)); +FORWARD void Ev P((void)); +FORWARD void EvGv P((void)); +FORWARD void EvIb P((void)); +FORWARD void Ew P((void)); +FORWARD void EwRw P((void)); +FORWARD void Gv P((void)); +FORWARD void Gv1 P((void)); +FORWARD void GvEv P((void)); +FORWARD void GvEw P((void)); +FORWARD void GvM P((void)); +FORWARD void GvMa P((void)); +FORWARD void GvMp P((void)); +FORWARD void Ib P((void)); +FORWARD void Iw P((void)); +FORWARD void Iv P((void)); +FORWARD void Jb P((void)); +FORWARD void Jv P((void)); +FORWARD void Ms P((void)); +FORWARD void checkmemory P((void)); +FORWARD su8_pt get8s P((void)); +FORWARD void getmodregrm P((void)); +FORWARD void i_00_to_3f P((opcode_pt opc)); +FORWARD void i_40_to_5f P((opcode_pt opc)); +FORWARD void i_60_to_6f P((opcode_pt opc)); +FORWARD void i_70_to_7f P((opcode_pt opc)); +FORWARD void i_80 P((opcode_pt opc)); +FORWARD void i_88 P((opcode_pt opc)); +FORWARD void i_90 P((opcode_pt opc)); +FORWARD void i_98 P((opcode_pt opc)); +FORWARD void i_a0 P((opcode_pt opc)); +FORWARD void i_a8 P((opcode_pt opc)); +FORWARD void i_b0 P((opcode_pt opc)); +FORWARD void i_b8 P((opcode_pt opc)); +FORWARD void i_c0 P((opcode_pt opc)); +FORWARD void i_c8 P((opcode_pt opc)); +FORWARD void i_d0 P((opcode_pt opc)); +FORWARD void i_d8 P((opcode_pt opc)); +FORWARD void i_e0 P((opcode_pt opc)); +FORWARD void i_e8 P((opcode_pt opc)); +FORWARD void i_f0 P((opcode_pt opc)); +FORWARD void i_f8 P((opcode_pt opc)); +FORWARD void outad P((opcode_pt opc)); +FORWARD void outad1 P((opcode_pt opc)); +FORWARD void outalorx P((opcode_pt opc)); +FORWARD void outax P((void)); +FORWARD void outbptr P((void)); +FORWARD void outbwptr P((opcode_pt opc)); +FORWARD void outea P((opcode_pt wordflags)); +FORWARD void outf1 P((void)); +FORWARD void outfishy P((void)); +FORWARD void outgetaddr P((void)); +FORWARD void outimmed P((opcode_pt signwordflag)); +FORWARD void outpc P((offset_t pc, int f)); +FORWARD void outsegpc P((void)); +FORWARD void oututstr P((char *s)); +FORWARD void outword P((void)); +FORWARD void outwptr P((void)); +FORWARD void outwsize P((void)); +FORWARD void pagef P((void)); +FORWARD void shift P((opcode_pt opc)); + +PRIVATE pfv_t optable[] = +{ + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_40_to_5f, + i_40_to_5f, + i_40_to_5f, + i_40_to_5f, + i_60_to_6f, + i_60_to_6f, + i_70_to_7f, + i_70_to_7f, + i_80, + i_88, + i_90, + i_98, + i_a0, + i_a8, + i_b0, + i_b8, + i_c0, + i_c8, + i_d0, + i_d8, + i_e0, + i_e8, + i_f0, + i_f8, +}; + +PRIVATE char fishy[] = "???"; +PRIVATE char movtab[] = "mov\t"; + +PRIVATE char *genreg[] = +{ + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", +}; +PRIVATE char *segreg[] = +{ + "es", "cs", "ss", "ds", "fs", "gs", "?s", "?s", +}; +PRIVATE char *indreg[] = +{ + "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx", +}; + +PRIVATE char *str_00_to_3f[] = +{ + /* index by (opcode >> 3) & 7 */ + "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp", +}; +PRIVATE char *sstr_00_to_3f[] = +{ + /* index ((opc>>2) & 0x0E) + (opc & 7) - 6 */ + "push\tes", "pop\tes", "push\tcs", "pop\tcs", + "push\tss", "pop\tss", "push\tds", "pop\tds", + "es:", "daa", "cs:", "das", "ss:", "aaa", "ds:", "aas", +}; +PRIVATE char *sstr_0f[] = +{ + "push\tfs", "pop\tfs", fishy, "bt\t", "shld\t", "shld\t", fishy, fishy, + "push\tgs", "pop\tgs", fishy, "bts\t", "shrd\t", "shrd\t", fishy, "imul\t", + fishy, fishy, "lss\t", "btr\t", "lfs\t", "lgs\t", "movzx\t", "movzx\t", + fishy, fishy, "", "btc\t", "bsf\t", "bsr\t", "movsx\t", "movsx\t", +}; +PRIVATE char *ssstr_0f[] = +{ + "sldt\t", "str\t", "lldt\t", "ltr\t", "verr\t", "verw\t", fishy, fishy, + "sgdt\t", "sidt\t", "lgdt\t", "lidt\t", "smsw\t", fishy, "lmsw\t", fishy, + fishy, fishy, fishy, fishy, "bt\t", "bts\t", "btr\t", "btc\t", +}; +PRIVATE char *str_40_to_5f[] = +{ + /* index by (opcode >> 3) & 3 */ + "inc\t", "dec\t", "push\t", "pop\t", +}; +PRIVATE char *str_60_to_6f[] = +{ + "pusha", "popa", "bound\t", "arpl\t", "fs:", "gs:", "os:", "as:", + "push\t", "imul\t", "push\t", "imul\t", "insb", "ins", "outsb", "outs", +}; +PRIVATE char *str_flags[] = +{ + /* opcodes 0x70 to 0x7F, and 0x0F80 to 0x0F9F */ + "o", "no", "b", "nb", "z", "nz", "be", "a", + "s", "ns", "pe", "po", "l", "ge", "le", "g", +}; +PRIVATE char *str_98[] = +{ + "cbw", "cwd", "call\t", "wait", "pushf", "popf", "sahf", "lahf", + "cwde", "cdq", "call\t", "wait", "pushfd", "popfd", "sahf", "lahf", +}; +PRIVATE char *str_a0[] = +{ + movtab, movtab, movtab, movtab, "movsb", "movs", "cmpsb", "cmps", +}; +PRIVATE char *str_a8[] = +{ + "test\t", "test\t", "stosb", "stos", "lodsb", "lods", "scasb", "scas", +}; +PRIVATE char *str_c0[] = +{ + "", "", "ret\t", "ret", "les\t", "lds\t", movtab, movtab, +}; +PRIVATE char *str_c8[] = +{ + "enter\t", "leave", "retf\t", "retf", "int\t3", "int\t", "into", "iret", +}; +PRIVATE char *str_d0[] = +{ + "aam", "aad", "db\td6", "xlat", +}; +PRIVATE char *sstr_d0[] = +{ + "rol", "ror", "rcl", "rcr", "shl", "shr", fishy, "sar", +}; +PRIVATE char *str_d8[] = +{ + "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", + "fld", NULL, "fst", "fstp", "fldenv", "fldcw", "fstenv", "fstcw", + "fiadd", "fimul", "ficom", "ficomp", "fisub", "fisubr", "fidiv", "fidivr", + "fild", NULL, "fist", "fistp", NULL, "fld", NULL, "fstp", + "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", + "fld", NULL, "fst", "fstp", "frstor", NULL, "fsave", "fstsw", + "fiadd", "fimul", "ficom", "ficomp", "fisub", "fisubr", "fidiv", "fidivr", + "fild", NULL, "fist", "fistp", "fbld", "fild", "fbstp", "fistp", +}; +PRIVATE char *str1_d8[] = +{ + "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", + "fld", "fxch", "\0\0", NULL, "\0\10", "\0\20", "\0\30", "\0\40", + NULL, NULL, NULL, NULL, NULL, "\0\50", NULL, NULL, + NULL, NULL, NULL, NULL, "\0\60", NULL, NULL, NULL, + "fadd", "fmul", NULL, NULL, "fsubr", "fsub", "fdivr", "fdiv", + "ffree", NULL, "fst", "fstp", "fucom", "fucomp", NULL, NULL, + "faddp", "fmulp", NULL, "\0\70", "fsubrp", "fsubp", "fdivrp", "fdivp", + NULL, NULL, NULL, NULL, "\0\100", NULL, NULL, NULL, +}; +PRIVATE unsigned char size_d8[] = +{ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 14-28, 2, 14-28, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 0, 10, 0, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 94-108, 0, 94-108, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 10, 8, 10, 8, +}; +PRIVATE char *sstr_d8[] = +{ + "fnop", NULL, NULL, NULL, /* D9D0 */ + NULL, NULL, NULL, NULL, + "fchs", "fabs", NULL, NULL, /* D9E0 */ + "ftst", "fxam", NULL, NULL, + "fld1", "fldl2t", "fldl2e", "fldpi", /* D9E8 */ + "fldlg2", "fldln2", "fldz", NULL, + "f2xm1", "fyl2x", "fptan", "fpatan", /* D9F0 */ + "fxtract", "fprem1", "fdecstp", "fincstp", + "fprem", "fyl2xp1", "fsqrt", "fsincos", /* D9F8 */ + "frndint", "fscale", "fsin", "fcos", + NULL, "fucompp", NULL, NULL, /* DAE8 */ + NULL, NULL, NULL, NULL, + "feni", "fdisi", "fclex", "finit", /* DBE0 */ + "fsetpm", NULL, NULL, NULL, + NULL, "fcompp", NULL, NULL, /* DED8 */ + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, /* DFE0 */ + "fstsw\tax", NULL, NULL, NULL, +}; +PRIVATE char *str_e0[] = +{ + "loopnz\t", "loopz\t", "loop\t", "jcxz\t", + "in\t", "in\t", "out\t", "out\t", +}; +PRIVATE char *str_e8[] = +{ + "call\t", "jmp\t", "jmp\t", "jmp\t", + "in\t", "in\t", "out\t", "out\t", +}; +PRIVATE char *str_f0[] = +{ + "lock\t", "db\tf1", "repnz\t", "repz\t", + "hlt", "cmc", + /* other 2 from sstr_f0 */ +}; +PRIVATE char *sstr_f0[] = +{ + "test\t", fishy, "not\t", "neg\t", + "mul\t", "imul\t", "div\t", "idiv\t", +}; +PRIVATE char *str_f8[] = +{ + "clc", "stc", "cli", "sti", + "cld", "std", + /* other 2 from sstr_f8 */ +}; +PRIVATE char *sstr_f8[] = +{ + "inc\t", "dec\t", "call\t", "call\tfar ", + "jmp\t", "jmp\tfar ", "push\t", "???\t", +}; + +PRIVATE int nop_flg; /* check for leading NOPs in opcodes */ +PRIVATE int data_seg; /* data segment (munged name for asld) */ +PRIVATE count_t hasize; /* half address size in bits */ +PRIVATE count_t hdefsize; +PRIVATE count_t hosize; /* half operand size in bits */ + /* for easy index into reg tables */ +PRIVATE opcode_pt mod; +PRIVATE offset_t offtable[2]; +PRIVATE offset_t *offptr; +PRIVATE offset_t *off1ptr; +PRIVATE opcode_pt reg; +PRIVATE opcode_pt rm; + +PRIVATE su8_pt get8s() +{ + u8_pt got; + + if ((got = get8()) > MAX_SIGNED_CHAR) + got -= (MAX_UNSIGNED_CHAR + 1); + return got; +} + +PRIVATE void getmodregrm() +{ + opcode_pt modregrm; + + modregrm = get8(); + mod = modregrm & MOD_MASK; + reg = (modregrm & REG_MASK) >> REG_SHIFT; + rm = (modregrm & RM_MASK) >> RM_SHIFT; +} + +PRIVATE void i_00_to_3f(opc) +opcode_pt opc; +{ + opcode_pt sub; + struct nlist *sp; + + /* attempt to step over linker padding */ + if (nop_flg && opc == 0 + && (sp = findsval(uptr.off + addrbase, CSEG)) != NULL + && sp->n_value == uptr.off + addrbase) { + outustr("nop"); + return; + } + if (opc == 15) + pagef(); + else if ((sub = opc & 7) >= 6) + { + outustr((sstr_00_to_3f - 6)[((opc >> 2) & 0x0E) + sub]); + if (!(opc & 1)) + data_seg = opc; + } + else + { + oututstr(str_00_to_3f[(opc >> 3) & 7]); + if (sub == 4) + { + outustr(genreg[0]); + outcomma(); + Ib(); + } + else if (sub == 5) + { + outax(); + outcomma(); + Iv(); + } + else + outad(sub); + } +} + +PRIVATE void i_40_to_5f(opc) +opcode_pt opc; +{ + outustr(str_40_to_5f[(opc >> 3) & 3]); + outustr(genreg[hosize + (opc & 7)]); +} + +PRIVATE void i_60_to_6f(opc) +opcode_pt opc; +{ + /* most for 386, some for 286 */ + + outustr((str_60_to_6f - 0x60)[opc]); + switch (opc) + { + case 0x60: + case 0x61: + if (hosize == 16) + outwsize(); + break; + case 0x62: + GvMa(); + break; + case 0x63: + EwRw(); + break; + case 0x64: + case 0x65: + data_seg = opc; + break; + case 0x66: + hosize = (16 + 8) - hdefsize; + break; + case 0x67: + hasize = (16 + 8) - hdefsize; + break; + case 0x68: + outword(); + Iv(); + break; + case 0x6A: + outword(); + outimmed(SIGNBIT | WORDBIT); + break; + case 0x69: + GvEv(); + outcomma(); + Iv(); + break; + case 0x6B: + GvEv(); + outcomma(); + outimmed(SIGNBIT | WORDBIT); + break; + case 0x6D: + case 0x6F: + outwsize(); + break; + default: + break; + } +} + +PRIVATE void i_70_to_7f(opc) +opcode_pt opc; +{ + outustr("j"); + oututstr((str_flags - 0x70)[opc]); + Jb(); +} + +PRIVATE void i_80(opc) +opcode_pt opc; +{ + if (opc >= 4) + { + outustr(opc >= 6 ? "xchg\t" : "test\t"); + outad(opc); + } + else + { + getmodregrm(); + oututstr(str_00_to_3f[reg]); + outbwptr(opc); + outea(opc); + outcomma(); + outimmed(opc); +#ifdef SIGNED_LOGICALS + if (opc & SIGNBIT && (reg == 1 || reg == 4 || reg == 6)) + /* and, or and xor with signe extension are not documented in some + * 8086 and 80286 manuals, but make sense and work + */ + outfishy(); +#endif + } +} + +PRIVATE void i_88(opc) +opcode_pt opc; +{ + if (opc < 4) + { + outustr(movtab); + outad(opc); + } + else if (opc == 5) + { + oututstr("lea"); + GvM(); + } + else if (opc == 7) + { + oututstr("pop"); + getmodregrm(); + outwptr(); + Ev(); + if (reg != 0) + outfishy(); + } + else + { + getmodregrm(); + outustr(movtab); + if (!(opc & TOREGBIT)) + { + Ev(); + outcomma(); + } + outustr(segreg[reg]); + if (opc & TOREGBIT) + { + outcomma(); + Ev(); + } + } +} + +PRIVATE void i_90(opc) +opcode_pt opc; +{ + if (opc == 0) + outustr("nop"); + else + { + outustr("xchg\t"); + outax(); + outcomma(); + outustr(genreg[hosize + opc]); + } +} + +PRIVATE void i_98(opc) +opcode_pt opc; +{ + outustr((str_98 - 8)[opc + hosize]); + if (opc == 2) + outsegpc(); +} + +PRIVATE void i_a0(opc) +opcode_pt opc; +{ + outustr(str_a0[opc]); + if (opc < 4) + { + mod = MEM0_MOD; /* fake */ + reg = 0; /* fake ax */ + if (hasize == 16) + rm = 5; /* fake [d16] */ + else + rm = 6; /* fake [d32] */ + outad1(opc ^ TOREGBIT); + } + else if (opc & 1) + outwsize(); +} + +PRIVATE void i_a8(opc) +opcode_pt opc; +{ + outustr(str_a8[opc]); + if (opc < 2) + { + outalorx(opc); + outcomma(); + outimmed(opc); + } + else if (opc & 1) + outwsize(); +} + +PRIVATE void i_b0(opc) +opcode_pt opc; +{ + outustr(movtab); + outustr(genreg[opc]); + outcomma(); + Ib(); +} + +PRIVATE void i_b8(opc) +opcode_pt opc; +{ + outustr(movtab); + outustr(genreg[hosize + opc]); + outcomma(); + Iv(); +} + +PRIVATE void i_c0(opc) +opcode_pt opc; +{ + outustr(str_c0[opc]); + if (opc >= 6) + { + getmodregrm(); + outbwptr(opc); + outea(opc); + outcomma(); + outimmed(opc & WORDBIT); + if (reg != 0) + /* not completely decoded (like DEBUG) */ + outfishy(); + } + else if (opc >= 4) + GvMp(); + else if (opc == 2) + Iv(); + else if (opc < 2) + shift(opc); +} + +PRIVATE void i_c8(opc) +opcode_pt opc; +{ + outustr(str_c8[opc]); + if (opc == 0) + { + Iw(); + outcomma(); + Ib(); + } + if (opc == 2) + Iv(); + else if (opc == 5) + Ib(); + else if (opc == 7 && hosize == 16) + outwsize(); +} + +PRIVATE void i_d0(opc) +opcode_pt opc; +{ + opcode_pt aabyte; + + if (opc < 4) + shift(opc | 0xD0); + else + { + outustr((str_d0 - 4)[opc]); + if (opc < 6 && (aabyte = get8()) != 0x0A) + { + outtab(); + outh8(aabyte); + outfishy(); + } + } +} + +PRIVATE void i_d8(opc) +opcode_pt opc; +{ + opcode_pt esc; + char *str; + + getmodregrm(); + esc = (opc << 3) | reg; + if ((str = (mod == REG_MOD ? str1_d8 : str_d8)[esc]) == NULL) + { +escape: + oututstr("esc"); + outh8(esc); + outcomma(); + outea(0); + return; + } + if (*str == 0) + { + str = sstr_d8[str[1] + rm]; + if (str == NULL) + goto escape; + outustr(str); + return; + } + outustr(str); + outtab(); + if (mod == REG_MOD) + { + if (opc == 0 && reg != 2 && reg != 3) + outustr("st,"); + outf1(); + if (opc == 4 || opc == 6) + outustr(",st"); + return; + } + switch(size_d8[esc]) + { + case 4: + outustr("d"); + /* FALL THROUGH */ + case 2: + outwptr(); + break; + case 8: + outustr("q"); + outwptr(); + break; + case 10: + outustr("t"); + outbptr(); + break; + default: + break; + } + outea(opc); +} + +PRIVATE void i_e0(opc) +opcode_pt opc; +{ + outustr(str_e0[opc]); + if (opc < 4) + Jb(); + else if (opc < 6) + { + outalorx(opc); + outcomma(); + Ib(); + } + else + { + Ib(); + outcomma(); + outalorx(opc); + } +} + +PRIVATE void i_e8(opc) +opcode_pt opc; +{ + outustr(str_e8[opc]); + if (opc < 2) + Jv(); + else if (opc == 2) + outsegpc(); + else if (opc == 3) + Jb(); + else + { + if (opc & TOREGBIT) + { + outustr(genreg[10]); + outcomma(); + outalorx(opc); + } + else + { + outalorx(opc); + outcomma(); + outustr(genreg[10]); + } + } +} + +PRIVATE void i_f0(opc) +opcode_pt opc; +{ + if (opc < 6) + outustr(str_f0[opc]); + else + { + getmodregrm(); + outustr(sstr_f0[reg]); + outbwptr(opc); + outea(opc); + if (reg == 0) + { + outcomma(); + outimmed(opc & WORDBIT); + } + } +} + +PRIVATE void i_f8(opc) +opcode_pt opc; +{ + if (opc < 6) + outustr(str_f8[opc]); + else + { + getmodregrm(); + if (opc == 6 && reg >= 2) + outustr("fishy\t"); + else + outustr(sstr_f8[reg]); + outbwptr(opc); + outea(opc); + } +} + +PRIVATE void outad(opc) +opcode_pt opc; +{ + getmodregrm(); + outad1(opc); +} + +PRIVATE void outad1(opc) +opcode_pt opc; +{ + if (!(opc & TOREGBIT)) + { + outea(opc); + outcomma(); + } + if (opc & WORDBIT) + Gv1(); + else + outustr(genreg[reg]); + if (opc & TOREGBIT) + { + outcomma(); + outea(opc); + } +} + +PRIVATE void outalorx(opc) +opcode_pt opc; +{ + if (opc & WORDBIT) + outax(); + else + outustr(genreg[0]); +} + +PRIVATE void outax() +{ + outustr(genreg[hosize]); +} + +PRIVATE void outbptr() +{ + outustr("byte ptr "); +} + +PRIVATE void outbwptr(opc) +opcode_pt opc; +{ + if (mod != REG_MOD) + { + if (opc & WORDBIT) + outwptr(); + else + outbptr(); + } +} + +PRIVATE void outea(wordflags) +opcode_pt wordflags; +{ + reg_pt base = 0; + reg_pt index = 0; + opcode_pt ss = 0; + opcode_pt ssindexbase = 0; + + if (mod == REG_MOD) + outustr(genreg[hosize * (wordflags & WORDBIT) + rm]); + else + { + outbyte(LINDIRECT); + if (hasize == 16) + { + if (rm == 4) + { + base = (ssindexbase = get8()) & BASE_MASK; + if (mod == MEM0_MOD && base == 5) + outgetaddr(); + else + outustr((genreg + 16)[base]); + ss = (ssindexbase & SS_MASK) >> SS_SHIFT; + if ((index = (ssindexbase & INDEX_MASK) >> INDEX_SHIFT) != 4) + { + outbyte('+'); + outustr((genreg + 16)[index]); + outstr("\0\0\0*2\0*4\0*8\0" + (3 * ss)); + } + } + else if (mod == MEM0_MOD && rm == 5) + outgetaddr(); + else + outustr((genreg + 16)[rm]); + } + else if (mod == MEM0_MOD && rm == 6) + outgetaddr(); + else + outustr(indreg[rm]); + if (mod == MEM1_MOD) + /* fake sign extension to get +- */ + outimmed(SIGNBIT | WORDBIT); + else if (mod == MEM2_MOD) + { + outbyte('+'); + outgetaddr(); + } + outbyte(RINDIRECT); + if (hasize == 16 && rm == 4 && index == 4 && ss != 0) + outfishy(); + } +} + +PRIVATE void outf1() +{ + outustr("st("); + outbyte((int) (rm + '0')); + outbyte(')'); +} + +PRIVATE void outfishy() +{ + outustr("\t???"); +} + +PRIVATE void outgetaddr() +{ + offset_t off; + struct nlist *sp; + + if (hasize == 16) + off = get32(); + else + off = get16(); + + /* do we ever need to call finrval with DSEG ? */ + if ((sp = findrval(uptr.off - (hasize / 4), CSEG)) != NULL) + { + outrel(sp, off); + *offptr++ = off; + } + else if ((sp = findsval(off, data_seg)) != NULL) + { + outsym(sp, off); + *offptr++ = off; + } + else if (hasize == 16) + outh32(off); + else + outh16((u16_pt) off); +} + +PRIVATE void outimmed(signwordflag) +opcode_pt signwordflag; +{ + su8_pt byte; + + if (signwordflag & WORDBIT) + { + if (signwordflag & SIGNBIT) + { + if ((byte = get8s()) < 0) + { + outbyte('-'); + byte = -byte; + } + else + outbyte('+'); + outh8((u8_pt) byte); + } + else + Iv(); + } + else + Ib(); +} + +PRIVATE void outpc(pc, f) +offset_t pc; +int f; +{ + struct nlist *sp; + + if (hosize == 8) + pc = (u16_t) pc; + if ((sp = findrval(uptr.off - (hosize / 4), CSEG)) != NULL) + { + if (f == 1) pc -= uptr.off; + outrel(sp, pc); + *offptr++ = pc; + } + else if ((sp = findsval(pc, CSEG)) != NULL) + { + outsym(sp, pc); + *offptr++ = pc; + } + else if (hosize == 16) + outh32(pc); + else + outh16((u16_pt) pc); +} + +PRIVATE void outsegpc() +{ + offset_t oldbase; + offset_t pc; + + if (hosize == 16) + pc = get32(); + else + pc = get16(); + oldbase = uptr.base; + outh16((u16_t) (uptr.base = get16())); /* fake seg for lookup of pc */ + /* TODO - convert to offset in protected mode */ + /* ### can this ever be a reloc structure ? */ + outbyte(':'); + outpc(pc, 0); + uptr.base = oldbase; +} + +PRIVATE void oututstr(s) +char *s; +{ + outustr(s); + outtab(); +} + +PRIVATE void outword() +{ + outustr("dword " + ((16 - hosize) >> 3)); +} + +PRIVATE void outwptr() +{ + outword(); + outustr("ptr "); +} + +PRIVATE void outwsize() +{ + if (hosize == 16) + outustr("d"); + else + outustr("w"); +} + +PRIVATE void pagef() +{ + opcode_pt opc; + bool_t regbad; + + if ((opc = get8()) <= 1 || opc == 0xBA) + { + if (opc == 0xBA) + opc = 16; + else + opc *= 8; + getmodregrm(); + outustr(ssstr_0f[opc += reg]); + if (opc < 6 || opc == 12 || opc == 14) + Ew(); + else if (opc >= 8 && opc < 13) + Ms(); + else if (opc >= 20) + { + outbwptr(WORDBIT); + EvIb(); + } + } + else if (opc < 4) + { + oututstr("lar\0lsl" + 4 * (opc - 2)); + GvEw(); + } + else if (opc == 5) + { + outustr("loadall"); + outfishy(); + } + else if (opc == 6) + outustr("clts"); + else if (opc < 0x20) + outstr(fishy); + else if (opc < 0x27 && opc != 0x25) + { + outustr(movtab); + getmodregrm(); + hosize = 16; + if (!(opc & TOREGBIT)) + { + Ev(); /* Rd() since hosize is 16 */ + outcomma(); + } + regbad = FALSE; + if (opc & 1) + { + outustr("dr"); + if (reg == 4 || reg == 5) + regbad = TRUE; + } + else if (opc < 0x24) + { + outustr("cr"); + if (reg >= 4 || reg == 1) + regbad = TRUE; + } + else + { + outustr("tr"); + if (reg < 6) + regbad = TRUE; + } + outbyte((int) (reg + '0')); + if (opc & TOREGBIT) + { + outcomma(); + Ev(); + } + if (regbad || mod != REG_MOD) + outfishy(); + } + else if (opc < 0x80) + outstr(fishy); + else if (opc < 0x90) + { + outustr("j"); + oututstr((str_flags - 0x80)[opc]); + Jv(); + } + else if (opc < 0xA0) + { + outustr("set"); + oututstr((str_flags - 0x90)[opc]); + getmodregrm(); + outbwptr(0); + Eb(); + } + else if (opc < 0xC0) + { + outustr((sstr_0f - 0xA0)[opc]); + switch (opc) + { + case 0xA3: + case 0xAB: + case 0xB3: + case 0xBB: + EvGv(); + break; + case 0xA4: + case 0xAC: + EvGv(); + outcomma(); + Ib(); + break; + case 0xA5: + case 0xAD: + EvGv(); + outcomma(); + CL(); + break; + case 0xAF: + case 0xBC: + case 0xBD: + GvEv(); + break; + case 0xB2: + case 0xB4: + case 0xB5: + GvMp(); + break; + case 0xB6: + case 0xBE: + Gv(); + outcomma(); + outbwptr(opc); + Eb(); + break; + case 0xB7: + case 0xBF: + Gv(); + outcomma(); + hosize = 8; /* done in Ew(), but too late */ + outbwptr(opc); + Ew(); + break; + default: + break; + } + } + else + outstr(fishy); +} + +PUBLIC bool_pt puti() +{ + static bool_t hadprefix = FALSE; + opcode_pt opcode; + + nop_flg = TRUE; + +more: + offptr = offtable; + opcode = get8(); + nop_flg = (nop_flg && (opcode == '\0')); + if (!hadprefix) + { + data_seg = DSEG; + hdefsize = 8; + if (bits32) + hdefsize = 16; + hosize = hasize = hdefsize; + } + (*optable[opcode >> 3])(opcode < 0x80 ? opcode : opcode & 7); + if (offptr > offtable) + { + if (stringtab() >= 31) + { + outspace(); + outspace(); + } + else + while (stringtab() < 32) + outtab(); + outbyte(';'); + for (off1ptr = offtable; off1ptr < offptr; ++off1ptr) + { + outspace(); + if (*off1ptr < 0x10000) + outh16((u16_t) *off1ptr); + else + outh32(*off1ptr); + } + offptr = offtable; + } + if ((opcode & 0xE7) == 0x26 || + opcode >= 0x64 && opcode < 0x68 || + opcode == 0xF0 || opcode == 0xF2 || opcode == 0xF3) + /* not finished instruction for 0x26, 0x2E, 0x36, 0x3E seg overrides + * and 0x64, 0x65 386 seg overrides + * and 0x66, 0x67 386 size prefixes + * and 0xF0 lock, 0xF2 repne, 0xF3 rep + */ + { + hadprefix = TRUE; + goto more; /* TODO - print prefixes better */ + return FALSE; + } + hadprefix = FALSE; + return TRUE; +} + +PRIVATE void shift(opc) +opcode_pt opc; +{ + getmodregrm(); + oututstr(sstr_d0[reg]); + outbwptr(opc); + outea(opc); + outcomma(); + if (opc < 0xD0) + Ib(); + else if (opc & 2) + CL(); + else + outbyte('1'); +} + +PRIVATE void checkmemory() +{ + if (mod == REG_MOD) + outfishy(); +} + +PRIVATE void CL() +{ + outustr(genreg[1]); +} + +PRIVATE void Eb() +{ + outea(0); +} + +PRIVATE void Ev() +{ + outea(WORDBIT); +} + +PRIVATE void EvGv() +{ + getmodregrm(); + Ev(); + outcomma(); + Gv1(); +} + +PRIVATE void EvIb() +{ + Ev(); + outcomma(); + Ib(); +} + +PRIVATE void Ew() +{ + hosize = 8; + Ev(); +} + +PRIVATE void EwRw() +{ + hosize = 8; + EvGv(); +} + +PRIVATE void Gv() +{ + getmodregrm(); + Gv1(); +} + +PRIVATE void Gv1() +{ + outustr(genreg[hosize + reg]); +} + +PRIVATE void GvEv() +{ + Gv(); + outcomma(); + Ev(); +} + +PRIVATE void GvEw() +{ + Gv(); + outcomma(); + Ew(); +} + +PRIVATE void GvM() +{ + GvEv(); + checkmemory(); +} + +PRIVATE void GvMa() +{ + GvM(); +} + +PRIVATE void GvMp() +{ + GvM(); +} + +PRIVATE void Ib() +{ + outh8(get8()); +} + +PRIVATE void Iw() +{ + outh16(get16()); +} + +PRIVATE void Iv() +{ +#if 1 + offset_t pcjump; + + if (hosize == 16) + pcjump = get32(); + else + pcjump = (su16_t) get16(); + outpc(pcjump, 0); +#else + if (hosize == 16) + outh32(get32()); + else + Iw(); +#endif +} + +PRIVATE void Jb() +{ + /* jump can be in either direction */ + int pcjump; + + pcjump = get8s(); + outpc(pcjump + uptr.off, 1); +} + +PRIVATE void Jv() +{ + offset_t pcjump; + + if (hosize == 16) + pcjump = get32(); + else + pcjump = (su16_t) get16(); + outpc((long)pcjump + uptr.off, 1); +} + +PRIVATE void Ms() +{ + Ev(); + checkmemory(); +} + +/* + * EOF + */ + diff --git a/commands/dis386/var.h b/commands/dis386/var.h new file mode 100644 index 000000000..ea48439ba --- /dev/null +++ b/commands/dis386/var.h @@ -0,0 +1,14 @@ +/* var.h - variables for db. + * + * $Id: var.h,v 1.1 1997/10/20 12:00:00 cwr Exp cwr $ + */ + +EXTERN bool_t bits32; +EXTERN unsigned processor; +EXTERN char_pt prompt; +EXTERN bool_t protected; +EXTERN offset_t addrbase; +EXTERN struct regs_s regs; +EXTERN struct specregs_s specregs; +EXTERN struct address_s uptr; +