]> Zhao Yanbai Git Server - minix.git/commitdiff
dis386 - a disassembler for ack
authorBen Gras <ben@minix3.org>
Mon, 4 Oct 2010 13:26:53 +0000 (13:26 +0000)
committerBen Gras <ben@minix3.org>
Mon, 4 Oct 2010 13:26:53 +0000 (13:26 +0000)
  - it can disassemble object files (dis386o) and executables
    (dis386a)
  - only useful for as long as we still have ack

12 files changed:
commands/Makefile
commands/dis386/Makefile [new file with mode: 0644]
commands/dis386/const.h [new file with mode: 0644]
commands/dis386/dis386.doc [new file with mode: 0644]
commands/dis386/dis386.h [new file with mode: 0644]
commands/dis386/dise.c [new file with mode: 0644]
commands/dis386/diso.c [new file with mode: 0644]
commands/dis386/misc.c [new file with mode: 0644]
commands/dis386/out.h [new file with mode: 0644]
commands/dis386/type.h [new file with mode: 0644]
commands/dis386/unasm.c [new file with mode: 0644]
commands/dis386/var.h [new file with mode: 0644]

index a55e7c8265a7e75272bdf2b201bda1e18d016433..dc561826c2560257b7f5b98e27681e7012e07363 100644 (file)
@@ -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 (file)
index 0000000..c813372
--- /dev/null
@@ -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 <bsd.prog.mk>
diff --git a/commands/dis386/const.h b/commands/dis386/const.h
new file mode 100644 (file)
index 0000000..98cd093
--- /dev/null
@@ -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 (file)
index 0000000..44e7ef9
--- /dev/null
@@ -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 (file)
index 0000000..b1ab4f8
--- /dev/null
@@ -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 (file)
index 0000000..6ab8576
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/stat.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <a.out.h>
+#include <ansi.h>
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#undef S_ABS           /* used in a.out.h */
+#include "out.h"       /* ACK compiler output header */
+#undef EXTERN
+#define EXTERN
+#include "dis386.h"    /* dis386 header */
+#endif
+
+#ifdef OS2
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include </local/minix/minix/config.h>
+#include </local/minix/minix/const.h>
+#include </local/minix/a.out.h>
+#include </local/minix/ansi.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#undef S_ABS           /* used in a.out.h */
+#include "out.h"       /* ACK compiler output header */
+#undef EXTERN
+#define EXTERN
+#include "dis386.h"    /* dis386 header */
+#endif
+
+/* Standard defines */
+#define FALSE          0
+#undef TRUE
+#define TRUE           !FALSE
+#define FAILED         -1
+#define MAYBE          0
+#define OK             1
+#define SAME           0
+
+/* Local defines */
+#define L_BUFF_LEN     1024
+#define BUFF_LEN       256
+#define S_BUFF_LEN     20
+#define L_BUFF_MAX     (L_BUFF_LEN-1)
+#define BUFF_MAX       (BUFF_LEN-1)
+#define S_BUFF_MAX     (S_BUFF_LEN-1)
+#define PSEP           '\\'
+
+#define AOUT           "a.out"
+#define CORE           "core"
+#define STAB           "symbol.tab"
+#define LINE_LEN       16
+#define SYMLEN         8
+
+#define TEXT           0       /* section indices for locsym[] */
+#define ROM            1
+#define DATA           2
+#define BSS            3
+
+#ifndef lint
+static char *Version = "@(#) dis_e386.c $Revision: 1.1 $ $Date: 1997/10/20 12:00:00 $";
+#endif
+
+/* Global variables */
+int opt_C = FALSE;             /* core file name */
+int opt_E = FALSE;             /* executable file name */
+int opt_O = FALSE;             /* object file name */
+int opt_S = FALSE;             /* symbol table name */
+int opt_a = FALSE;             /* dump tables and disassemble segments */
+int opt_b = FALSE;             /* dump straight binary */
+int opt_d = FALSE;             /* dump the data segment */
+int opt_f = FALSE;             /* first address of dump */
+int opt_h = FALSE;             /* dump the header structure */
+int opt_l = FALSE;             /* last address of dump */
+int opt_m = FALSE;             /* dump the rom segment */
+int opt_n = FALSE;             /* dump the symbol names */
+int opt_r = FALSE;             /* dump the relocation structures */
+int opt_s = FALSE;             /* dump the symbol table */
+int opt_t = FALSE;             /* dump the text segment */
+int opt_u = FALSE;             /* dump the bss segment */
+int opt_x = FALSE;             /* debugging flag */
+
+char progname[BUFF_LEN];       /* program name */
+int dbglvl = 0;                        /* debugging level */
+
+struct a_sec {                 /* a.out section data */
+  char *name;                  /* section name */
+  int first;                   /* first index */
+  int last;                    /* last index */
+  int total;
+} a_sectab[] = {               /* all known a.out sections */
+  "undefined", 0, 0, 0,
+  "absolute", 0, 0, 0,
+  "text", 0, 0, 0,
+  "data", 0, 0, 0,
+  "bss", 0, 0, 0,
+  "common", 0, 0, 0,
+  "rom", 0, 0, 0,              /* this one is unknown */
+  (char *)NULL, 0, 0, 0
+};
+
+/* Forward declarations */
+unsigned long atoaddr(char *);                 /* Convert ascii hex/dec to unsigned long */
+int binary(unsigned char, char*);              /* Binary output of 8-bit number */
+int dump_ahdr(struct exec *ep);                        /* Dump an a.out file header */
+int dump_adata(FILE *fp, int start, int count);        /* Dump an a.out file data section */
+int dump_asym(struct nlist *np, int start, int count); /* Dump an a.out file symbol table */
+int dump_hex(FILE *fp, int start, int count);  /* Dump bytes in hex and ascii */
+int find_asym(long value, int section);                /* Find an a.out symbol */
+int gen_locsym(FILE *fp, int sec);             /* Generate local symbols */
+int init_aout(FILE *fp);                       /* Initialise the a.out file tables */
+void usage(void);                              /* Usage message */
+
+
+/*
+ * a t o a d d r
+ *
+ * Convert ascii hex/dec to unsigned long.
+ *
+ * Returns:    Conversion result       Always
+ */
+unsigned long atoaddr(char *sp)
+{
+  char c, *cp, buff[S_BUFF_LEN];
+  int j;
+  unsigned long int result = 0;
+
+  /* flip to upper */
+  for (j = 0 ; j < S_BUFF_MAX && *(sp + j) != '\0' ; j++)
+       buff[j] = toupper(*(sp + j));
+  buff[j] = '\0';
+
+  /* lose leading whitespace */
+  cp = buff;
+  while isspace(*cp)
+       cp++;
+
+  /* check for hexadecimal entry */
+  if (*cp == '0' && *(cp + 1) == 'X') {
+       cp += 2;
+       while (isxdigit(*cp)) {
+               c = *cp++;
+               j = (c < 'A') ? c - '0' : c - 'A' + 10;
+               result = (result << 4) + (c < 'A' ? c - '0' : c - 'A' + 10);
+       }
+  }
+  else
+       result = atol(buff);
+
+  return result;
+}
+
+
+/*
+ * b i n a r y
+ *
+ * Produce a binary representation of an 8-bit number.
+ *
+ * Returns:    0       Always
+ */
+int binary(unsigned char uc, char *sp)
+{
+  int j;
+  unsigned char k;
+
+  for (k = 0x80, j = 0 ; j < 8 ; j++) {
+       if ((uc & k) == 0) *sp++ = '0';
+       else *sp++ = '1';
+       if (j == 3) *sp++ = '$';
+       k >>= 1;
+  }
+  *sp = '\0';
+
+  return(0);
+}
+
+
+/*
+ * d u m p _ a h d r
+ *
+ * Dump an a.out file header.
+ *
+ * Returns:    OK      Always
+ */
+int dump_ahdr(struct exec *ep)
+{
+  char buff[BUFF_LEN];
+
+  fprintf(stdout, "Magic number is:             0x%02x%02x\n",
+               ep->a_magic[0], ep->a_magic[1]);
+  sprintf(buff, "Flags are:                   0x%02x", ep->a_flags);
+  if (ep->a_flags & A_UZP) strcat(buff, " A_UZP");
+  if (ep->a_flags & A_PAL) strcat(buff, " A_PAL");
+  if (ep->a_flags & A_NSYM) strcat(buff, " A_NSYM");
+  if (ep->a_flags & A_EXEC) strcat(buff, " A_EXEC");
+  if (ep->a_flags & A_SEP) strcat(buff, " A_SEP");
+  if (ep->a_flags & A_PURE) strcat(buff, " A_PURE");
+  if (ep->a_flags & A_TOVLY) strcat(buff, " A_TOVLY");
+  if (ep->a_flags & ~(A_UZP | A_PAL | A_NSYM | A_EXEC | A_SEP | A_PURE | A_TOVLY))
+       strcat(buff, " UNKNOWN");
+  fprintf(stdout, "%s\n", buff);
+
+  sprintf(buff, "CPU type is:                 0x%02x", ep->a_cpu);
+  if (ep->a_cpu == A_NONE) strcat(buff, " A_NONE");
+  else if (ep->a_cpu == A_I8086) strcat(buff, " A_I8086");
+  else if (ep->a_cpu == A_M68K) strcat(buff, " A_M68K");
+  else if (ep->a_cpu == A_NS16K) strcat(buff, " A_NS16K");
+  else if (ep->a_cpu == A_I80386) strcat(buff, " A_I80386");
+  else if (ep->a_cpu == A_SPARC) strcat(buff, " A_SPARC");
+  else strcat(buff, " UNKNOWN");
+  fprintf(stdout, "%s\n", buff);
+
+  fprintf(stdout, "Byte order is:               %s\n",
+               A_BLR(ep->a_cpu) ? "left to right" : "right to left");
+  fprintf(stdout, "Word order is:               %s\n",
+               A_WLR(ep->a_cpu) ? "left to right" : "right to left");
+
+  fprintf(stdout, "Header length is:            0x%02x\n", ep->a_hdrlen);
+  fprintf(stdout, "Reserved byte is:            0x%02x\n", ep->a_unused);
+  fprintf(stdout, "Version stamp is:            0x%04x\n", ep->a_version);
+  fprintf(stdout, "Size of text segment is:     0x%08.8x\n", ep->a_text);
+  fprintf(stdout, "Size of data segment is:     0x%08.8x\n", ep->a_data);
+  fprintf(stdout, "Size of bss segment is:      0x%08.8x\n", ep->a_bss);
+  fprintf(stdout, "Entry point is:              0x%08.8x\n", ep->a_entry);
+  fprintf(stdout, "Total memory allocated is:   0x%08.8x\n", ep->a_total);
+  fprintf(stdout, "Size of symbol table is:     0x%08.8x bytes, %d entries\n",
+               ep->a_syms, ep->a_syms / sizeof(struct nlist));
+
+  /* SHORT FORM ENDS HERE */
+#if 0
+  fprintf(stdout, "Size of text relocation is 0x%08.8x\n", ep->a_trsize);
+  fprintf(stdout, "Size of data relocation is 0x%08.8x\n", ep->a_drsize);
+  fprintf(stdout, "Base of text relocation is 0x%08.8x\n", ep->a_tbase);
+  fprintf(stdout, "Base of data relocation is 0x%08.8x\n", ep->a_dbase);
+#endif
+
+  return(OK);
+}
+
+
+/*
+ * d u m p _ a d a t a
+ *
+ * Dump an a.out data section.
+ *
+ * Returns:    OK      Success
+ *             FAILED  File read failure, invalid arguments
+ *
+ * The a_hdrbuf structure is read to determine section addresses.
+ * The a_symtab structure is read to determine symbol names (if available).
+ */
+int dump_adata(FILE *fp, int start, int count)
+{
+  char label[S_BUFF_LEN], data[S_BUFF_LEN], buff[BUFF_LEN];
+  char *hex = "0123456789ABCDEF";
+  int j, k, newflg, index, last, status, found, quit;
+  long int addr;
+  unsigned long int ulj;
+  struct locname *np;
+
+  if (start < 0 || (start + count) > (A_SYMPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen))
+       return(FAILED);
+
+  ulj = start;
+  quit = FALSE;
+  status = OK;
+  for (addr = start ; addr < (start + count) ; addr += 16) {
+       /* get a line's worth of data */
+       for (j = 0 ; j < 16 ; j++) {
+               if (j == (start + count - addr)) {
+                       quit = TRUE;
+                       break;
+               }
+               if ((k = fgetc(fp)) == EOF) {
+                       status = FAILED;
+                       quit = TRUE;
+                       break;
+               }
+               data[j] = (char)k;
+       }
+
+       /* adjust for an unexpected EOF */
+       if (quit && status == FAILED) {
+               if (j == 0)
+                       break;
+               else
+                       j--;
+       }
+       last = j;
+
+       /* write out the address and clear the rest of the buffer */
+       sprintf(buff, "%06lx", ulj);
+       for (k = strlen(buff) ; k < BUFF_MAX ; k++)
+               buff[k] = ' ';
+
+       /* build the hex and ascii data representations */
+       newflg = TRUE;
+       found = FALSE;
+       for (j = 0 ; j < last ; j++ ) {
+
+               /* find a local symbol, one per address */
+               for (np = locsym[DATA] ; !found && np != (struct locname *)NULL ;
+                                                                       np = np->l_next) {
+                       if (ulj == np->l_value) {
+                               /* write out any outstanding data */
+                               if (j != 0) {
+                                       buff[75] = '\0';
+                                       fprintf(stdout, "%s\n", buff);
+                                       for (k = 8 ; k < 75 ; k++)
+                                               buff[k] = ' ';
+                               }
+                               /* write out the symbol name */
+                               for (k = 0 ; k < 8 ; k++)
+                                       label[k] = np->l_name[k];
+                               label[k] = '\0';
+                               fprintf(stdout, "%s\n", label);
+                               found = TRUE;
+                       }
+               }
+
+               /* find any global symbols, several per address */
+               while (!found && (index = find_asym(ulj, N_DATA)) != -1) {
+                       /* for the first symbol, write out any outstanding data */
+                       if (newflg && j != 0) {
+                               buff[75] = '\0';
+                               fprintf(stdout, "%s\n", buff);
+                               for (k = 8 ; k < 75 ; k++)
+                                       buff[k] = ' ';
+                               newflg = FALSE;
+                       }
+                       /* write out the symbol name */
+                       for (k = 0 ; k < 8 ; k++)
+                               label[k] = a_symtab[index].n_name[k];
+                       label[k] = '\0';
+                       /* for some reason, some table entries are empty */
+                       if (label[0] != '\0') fprintf(stdout, "%s\n", label);
+               }
+
+               /* set up for the next pass */
+               newflg = TRUE;
+               found = FALSE;
+               ulj++;
+               /* hex digits */
+               buff[8 + (3 * j) + (j < 8 ? 0 : 2)] = hex[(data[j] >> 4) & 0x0f];
+               buff[9 + (3 * j) + (j < 8 ? 0 : 2)] = hex[data[j] & 0x0f];
+               /* ascii conversion */
+               if (data[j] < 32 || data[j] > 127)
+                       buff[59 + j] = '.';
+               else
+                       buff[59 + j] = data[j];
+               if (j == 8)
+                       buff[32] = '-';
+       }
+       buff[75] = '\0';
+
+       /* write out the result */
+       fprintf(stdout, "%s\n", buff);
+
+       if (quit) break;
+  }
+
+  return(status);
+}
+
+
+/*
+ * d u m p _ a s y m
+ *
+ * Dump an a.out file symbol table.
+ *
+ * Returns:    OK      Success
+ *             FAILED  Invalid arguments
+ *
+ * The a_hdrbuf structure is read to determine section addresses.
+ */
+int dump_asym(struct nlist *np, int start, int count)
+{
+  char buff[BUFF_LEN], data[S_BUFF_LEN];
+  unsigned char uc;
+  int j, k;
+
+  if (start < 0 || (start + count) > (a_hdrbuf.a_syms / sizeof(struct nlist)))
+       return(FAILED);
+
+  for (j = start ; j < (start + count) ; j++) {
+       sprintf(buff, "%-4d ", j);
+       for (k = 0 ; k < SYMLEN ; k++)
+               data[k] = (np[j].n_name[k] == '\0') ? ' ' : np[j].n_name[k];
+       data[k] = '\0';
+       strcat(buff, data);
+       sprintf(data, " Val: 0x%08x", np[j].n_value);
+       strcat(buff, data);
+       sprintf(data, " Sto: 0x%02x", np[j].n_sclass);
+       strcat(buff, data);
+       uc = np[j].n_sclass;
+       if ((uc & N_SECT) == N_UNDF) strcat(buff, " N_UNDF");
+       else if ((uc & N_SECT) == N_ABS) strcat(buff, " N_ABS ");
+       else if ((uc & N_SECT) == N_TEXT) strcat(buff, " N_TEXT");
+       else if ((uc & N_SECT) == N_DATA) strcat(buff, " N_DATA");
+       else if ((uc & N_SECT) == N_BSS) strcat(buff, " N_BSS ");
+       else if ((uc & N_SECT) == N_COMM) strcat(buff, " N_COMM");
+       else strcat(buff, " UNKNOWN");
+       if ((uc & N_CLASS) == 0) strcat(buff, " C_NULL");
+       else if ((uc & N_CLASS) == C_EXT) strcat(buff, " C_EXT ");
+       else if ((uc & N_CLASS) == C_STAT) strcat(buff, " C_STAT");
+       else strcat(buff, " UNKNOWN");
+       sprintf(data, " Aux: 0x%02x", np[j].n_numaux);
+       strcat(buff, data);
+       sprintf(data, " Typ: 0x%04x", np[j].n_type);
+       strcat(buff, data);
+       fprintf(stdout, "%s\n", buff);
+  }
+
+  return(OK);
+}
+
+
+/*
+ * d u m p _ h e x
+ *
+ * Dump bytes in hex and ascii.
+ *
+ * Returns:    OK      Success
+ *             FAILED  File read failure, invalid arguments
+ */
+int dump_hex(FILE *fp, int start, int count)
+{
+  char c, buff[S_BUFF_LEN];
+  int j, k, status, quit, last;
+  unsigned long int ulj;
+
+  if (start < 0)
+       return(FAILED);
+
+  ulj = 0;
+  quit = FALSE;
+  status = OK;
+  while (TRUE) {
+       /* get 16 bytes of data */
+       for (j = 0 ; j < 16 ; j++) {
+               if ((k = fgetc(fp)) == EOF) {
+                       quit = TRUE;
+                       break;
+               }
+               else
+                       buff[j] = (char)k;
+       }
+
+       /* set up to dump any remaining data */
+       if (quit) {
+               status = FAILED;
+               if (j == 0)
+                       break;
+               else
+                       j--;
+       }
+       last = j;
+
+       /* print the address */
+       fprintf(stdout, "%06lx ", start + ulj);
+       ulj += 16;
+       if (ulj >= count) {
+               quit = TRUE;
+               if (last == 16)
+                       last = (count - 1) % 16;
+       }
+
+       /* print a line of hex data */
+       for (j = 0 ; j < 16 ; j++ ) {
+               if (j <= last)
+                       fprintf(stdout, " %02x", buff[j] & 0xff);
+               else
+                       fprintf(stdout, "   ");
+               if (j == 7)
+                       fprintf(stdout, " -");
+       }
+
+       /* print a trailer of ascii data */
+       fprintf(stdout, "  ");
+       for (j = 0 ; j < 16 ; j++ ) {
+               if (j <= last)
+                       c = buff[j];
+               else
+                       c = ' ';
+               if (c < 32 || c > 127)
+                       c = '.';
+               (void) fputc(c, stdout);
+       }
+
+       fprintf(stdout, "\n");
+       if (quit)
+               break;
+  }
+
+  return(status);
+}
+
+
+/*
+ * f i n d _ a s y m
+ *
+ * Find an a.out symbol index in a sorted list.
+ * There may be several symbols with the same value:
+ * return the first in the sequence.
+ *
+ * Returns:    index           Success
+ *             -1              Failure
+ *
+ * The a_sectab structure is read to determine section indices.
+ * The a_symtab structure is read to determine symbol names.
+ */
+int find_asym(long value, int sec)
+{
+  static int index = 0;
+  static long oldval = 0;
+  static int oldsec = 0;
+  int j;
+
+  /* check for a repeated search */
+  if (value != oldval || sec != oldsec) {
+       oldval = value;
+       oldsec = sec;
+       index = a_sectab[sec].first;
+  }
+  /* never happen */
+  else if (index == -1)
+       return(FAILED);
+
+  /* do a linear search for a symbol, since repeated searches may be needed */
+  for (j = index ; j < a_sectab[sec].last ; j++) {
+       if (value == a_symtab[j].n_value)
+               break;
+  }
+
+  /* set up the index for the next pass */
+  if (j == a_sectab[sec].last) {
+       index = a_sectab[sec].first;
+       return(-1);
+  }
+  else {
+       index = j + 1;
+       return(j);
+  }
+  /* NOTREACHED */
+}
+
+
+/*
+ * g e n _ l o c s y m
+ *
+ * Generate local symbols.
+ *
+ * Returns:    OK      Success
+ *             FAILED  Invalid arguments, malloc failure
+ *
+ * This works only for data and bss segments.  Text symbols need
+ * a disassembly of the text section, and intelligent guesses as
+ * to whether a local address refers to text or data.  In fact,
+ * this routine is hardwired to the data area, and the bss area
+ * is ignored.
+ */
+int gen_locsym(FILE *fp, int sec)
+{
+  char data[20];
+  int j, txtflg, hdrflg;
+  long int addrcount;
+  struct locname *np, *current;
+
+  /* check that all offsets are valid - this routine won't work for text */
+  if (sec < ROM || sec > BSS) {
+       fprintf(stderr, "Invalid section %s\n", a_sectab[sec & 7].name);
+       return(FAILED);
+  }
+
+  /* initialise the label string */
+  strncpy(data, ".DAT", 4);
+  data[4] = '\0';
+
+  /* initialise the in-memory local name table pointers */
+  current = (struct locname *)(NULL);
+
+  /* read the data area and load the symbols */
+  (void) fseek(aoutfp, A_DATAPOS(a_hdrbuf), SEEK_SET);
+  addrcount = 0;
+  txtflg = hdrflg = FALSE;
+  while (addrcount < a_hdrbuf.a_data) {
+       j = fgetc(fp);
+       if (j < 040 || j > 0177) {
+               txtflg = FALSE;
+               hdrflg = FALSE;
+       }
+       else
+               txtflg = TRUE;
+
+       /* ensure that the start of each apparent string has a related symbol */
+       if (txtflg && !hdrflg) {
+               if (find_asym(addrcount, sec) == -1) {
+                       /* if malloc fails, just collapse */
+                       if ((np = (struct locname *)malloc(sizeof(struct locname)))
+                                       == (struct locname *)NULL) {
+                               fprintf(stderr, "%s: malloc failed\n", progname);
+                               return(FAILED);
+                       }
+                       /* update the current record */
+                       sprintf(np->l_name, "%s%04x", data,
+                                       (a_hdrbuf.a_text + addrcount) & 0xffff);
+                       /* nb. must follow l_name update */
+                       if (sec == TEXT) np->l_sclass = S_TEXT & 0xff;
+                       else if (sec == ROM) np->l_sclass = S_DATA & 0xff;
+                       else if (sec == DATA) np->l_sclass = S_DATA & 0xff;
+                       else if (sec == BSS) np->l_sclass = S_BSS & 0xff;
+                       else sec = 0;
+                       np->l_value = a_hdrbuf.a_text + addrcount;
+                       np->l_next = (struct locname *)NULL;
+                       /* and add it to the list */
+                       if (current == (struct locname *)NULL)
+                               locsym[sec] = np;
+                       else
+                               current->l_next = np;
+                       current = np;
+               }
+               hdrflg = TRUE;
+       }
+       addrcount++;
+  }
+
+  return(OK);
+}
+
+
+/*
+ * i n i t _ a o u t
+ *
+ * Initialise the a.out file tables.
+ *
+ * Returns:    OK      Success
+ *             FAILED  File read failure
+ *
+ * The a_hdrbuf and a_symtab and a_sectab structures are
+ * all initialised here.  Also, the ability to read the
+ * entire file is checked; no read checking is done
+ * later in the program.
+ */
+int init_aout(FILE *fp)
+{
+  char *cp;
+  int j, k, maxsym;
+  struct nlist *np;
+  struct nlist ntmp;
+
+  /* load the header into memory for fast access.
+   * the header length is the fifth byte of the header.
+   */
+  cp = (char *)&a_hdrbuf;
+  if (fread(cp, sizeof(char), 5, aoutfp) != 5) {
+       fprintf(stderr, "Cannot read executable header.\n");
+       return(FAILED);
+  }
+  j = cp[4] - 5;
+  cp += 5;
+  if (fread(cp, sizeof(char), j, aoutfp) != j) {
+       fprintf(stderr, "Cannot read executable header.\n");
+       return(FAILED);
+  }
+  if(BADMAG(a_hdrbuf)) {
+       fprintf(stderr, "%s: bad magic number.\n", progname);
+       return(FAILED);
+  }
+
+  /* check that the whole file can be read */
+  if (fseek(aoutfp, A_SYMPOS(a_hdrbuf) + a_hdrbuf.a_syms, SEEK_SET) != 0) {
+       fprintf(stderr, "%s: cannot seek to end of file.\n", progname);
+       return(FAILED);
+  }
+
+  /* load the symbol table into memory for fast access */
+  a_symtab = (struct nlist *)NULL;
+  if (a_hdrbuf.a_syms != 0) {
+       /* get space for the nlist data */
+       if ((cp = (char *)malloc(a_hdrbuf.a_syms)) == (char *)NULL) {
+               fprintf(stderr, "%s: malloc failed\n", progname);
+               return(FAILED);
+       }
+       if (fseek(aoutfp, -a_hdrbuf.a_syms, SEEK_CUR) != 0) {
+               fprintf(stderr, "%s: cannot seek to symbol area.\n", progname);
+               return(FAILED);
+       }
+       /* load the symbols into a sorted list */
+       np = (struct nlist *)cp;
+       maxsym = 0;
+       for (j = 0 ; j < a_hdrbuf.a_syms / sizeof(struct nlist) ; j++) {
+               if (fread(&ntmp, sizeof(struct nlist), 1, aoutfp) != 1) {
+                       fprintf(stderr, "%s: cannot read symbol area.\n", progname);
+                       return(FAILED);
+               }
+               /* insertion sort, by class and value */
+               for (k = maxsym ; k > 0 ; k--) {
+                       if ((ntmp.n_sclass & N_SECT) < (np[k-1].n_sclass & N_SECT))
+                               np[k] = np[k - 1];
+                       else if ((ntmp.n_sclass & N_SECT) == (np[k-1].n_sclass & N_SECT) &&
+                                       ntmp.n_value < np[k-1].n_value)
+                               np[k] = np[k - 1];
+                       else
+                               break;
+               }
+               np[k] = ntmp;
+               maxsym++;
+       }
+       /* finally, we have a valid symbol table */
+       a_symtab = (struct nlist *)cp;
+
+       /* update the symbol section index list */
+       a_sectab[a_symtab[0].n_sclass & N_SECT].first = 0;
+       for (j = 1 ; j < (a_hdrbuf.a_syms / sizeof(struct nlist)) ; j++) {
+               if ((a_symtab[j].n_sclass & N_SECT) != (a_symtab[j-1].n_sclass & N_SECT)) {
+                       a_sectab[a_symtab[j-1].n_sclass & N_SECT].last = j - 1;
+                       a_sectab[a_symtab[j-1].n_sclass & N_SECT].total =
+                               j - a_sectab[a_symtab[j-1].n_sclass & N_SECT].first;
+                       a_sectab[a_symtab[j].n_sclass & N_SECT].first = j;
+               }
+       }
+       a_sectab[a_symtab[j-1].n_sclass & N_SECT].last = j - 1;
+
+       /* build the local symbol tables */
+       for (j = 0 ; j < MAXSECT ; j++)
+               locsym[j] = (struct locname *)NULL;
+
+       /* build the local .text symbol table */
+       /* ### full disassembly ? */
+
+       /* build the local data symbol table */
+       if (gen_locsym(fp, DATA) == FAILED)
+               return(FAILED);
+  }
+
+  return(OK);
+}
+
+
+/*
+ * m a i n
+ *
+ * Main routine of dis_a386.
+ */
+int main(int argc, char *argv[])
+{
+  char *cp, binfile[BUFF_LEN], symbfile[BUFF_LEN];
+  int j, errors;
+  unsigned long int addrfirst, addrlast, addrcount;
+  struct stat statbuff;
+
+  /* initial set up */
+  if ((cp = strrchr(argv[0], PSEP)) == (char *)NULL)
+       cp = argv[0];
+  else
+       cp++;
+  strncpy(progname, cp, BUFF_MAX);
+  strncpy(binfile, AOUT, BUFF_MAX);
+  addrfirst = addrlast = addrcount = 0;
+
+  /* check for an MSDOS-style option */
+  if (argc == 2 && argv[1][0] == '/') {
+       usage();
+       exit(0);
+  }
+
+  /* parse arguments */
+  errors = opterr = 0;
+  while ((j = getopt(argc, argv, "E:abdf:hl:stx:")) != EOF) {
+       switch (j & 0177) {
+#if 0
+       case 'C':                       /* core file name */
+               opt_C = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(binfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+#endif
+       case 'E':                       /* executable file name */
+               opt_E = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(binfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+#if 0
+       case 'O':                       /* object file name */
+               opt_O = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(binfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+       case 'S':                       /* symbol table name */
+               opt_S = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(symbfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+#endif
+       case 'a':                       /* dump tables and disassemble segments */
+               opt_a = TRUE;
+               break;
+       case 'b':                       /* dump straight binary */
+               opt_b = TRUE;
+               break;
+       case 'd':                       /* dump the data segment */
+               opt_d = TRUE;
+               break;
+       case 'f':                       /* first address of dump */
+               opt_f = TRUE;
+               if (optarg != (char *)NULL)
+                       addrfirst = atoaddr(optarg);
+               else
+                       errors++;
+               break;
+       case 'h':                       /* dump the header */
+               opt_h = TRUE;
+               break;
+       case 'l':                       /* last address of dump */
+               opt_l = TRUE;
+               if (optarg != (char *)NULL)
+                       addrlast = atoaddr(optarg);
+               else
+                       errors++;
+               break;
+#if 0
+       case 'm':                       /* dump the rom segment */
+               opt_m = TRUE;
+               break;
+       case 'n':                       /* dump the symbol names */
+               opt_n = TRUE;
+               break;
+       case 'r':                       /* dump the relocation structures */
+               opt_r = TRUE;
+               break;
+#endif
+       case 's':                       /* dump the symbol table */
+               opt_s = TRUE;
+               break;
+       case 't':                       /* dump the text segment */
+               opt_t = TRUE;
+               break;
+#if 0
+       case 'u':                       /* dump the bss segment */
+               opt_u = TRUE;
+               break;
+#endif
+       case 'x':                       /* debugging flag */
+               opt_x = TRUE;
+               if (optarg != (char *)NULL)
+                       dbglvl = atoi(optarg);
+               break;
+       case '?':
+       default:
+               usage();
+               exit(1);
+               break;
+       }
+  }
+
+  /* check the flags */
+  if (errors > 0) {
+       usage();
+       exit(1);
+  }
+  if (opt_a && (opt_d || opt_h || opt_s || opt_t)) {
+       usage();
+       exit(1);
+  }
+  if ((opt_f || opt_l) && (addrlast != 0 && addrfirst > addrlast)) {
+       usage();
+       exit(1);
+  }
+
+  /* check for a specific input file */
+  if (optind < argc)
+       strncpy(binfile, argv[optind], BUFF_MAX);
+
+  /* we must have a binary file of some sort */
+  if ((aoutfp = fopen(binfile, "rb")) == (FILE *)NULL ||
+               stat(binfile, &statbuff) == -1) {
+       perror(binfile);
+       exit(1);
+  }
+
+  /* initialise the a.out data structures */
+  if (init_aout(aoutfp) == FAILED) {
+       perror(binfile);
+       exit(1);
+  }
+
+  /* show the output file name and date */
+  fprintf(stdout, "File name: %s\nFile date: %s",
+               binfile, ctime(&statbuff.st_ctime));
+
+  /* show the header section - default behaviour */
+  if (opt_a || opt_h || (!opt_d && !opt_s && !opt_t)) {
+       fprintf(stdout, "\nHeader data:\n");
+       (void) dump_ahdr(&a_hdrbuf);
+  }
+
+  /* dump the data section */
+  if (opt_d && opt_b) {
+       /* check that all offsets are valid */
+       if (addrfirst > a_hdrbuf.a_data || addrlast > a_hdrbuf.a_data) {
+               fprintf(stderr, "Invalid data address range 0x%08.8lu to 0x%08.8lu\n",
+                                                               addrfirst, addrlast);
+       }
+       else {
+               addrcount = (addrlast == 0) ? a_hdrbuf.a_data : addrlast;
+               addrcount -= addrfirst;
+               (void) fseek(aoutfp, A_DATAPOS(a_hdrbuf) + addrfirst, SEEK_SET);
+               fprintf(stdout, "\nData:\n");
+               (void) dump_hex(aoutfp, A_DATAPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen + addrfirst,
+                                                               addrcount);
+       }
+  }
+
+  /* disassemble the data section */
+  if (opt_a || (opt_d && !opt_b)) {
+       /* check that all offsets are valid */
+       if (addrfirst > a_hdrbuf.a_data || addrlast > a_hdrbuf.a_data) {
+               fprintf(stderr, "Invalid data address range 0x%08.8lu to 0x%08.8lu\n",
+                                                               addrfirst, addrlast);
+       }
+       else {
+               addrcount = (addrlast == 0) ? a_hdrbuf.a_data : addrlast;
+               addrcount -= addrfirst;
+               (void) fseek(aoutfp, A_DATAPOS(a_hdrbuf) + addrfirst, SEEK_SET);
+               fprintf(stdout, "\nDisassembled data:\n");
+               (void) dump_adata(aoutfp, A_DATAPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen
+                                                       + addrfirst, addrcount);
+       }
+  }
+
+  /* dump the text section */
+  if (opt_t && opt_b) {
+       /* check that all offsets are valid */
+       if (addrfirst > a_hdrbuf.a_text || addrlast > a_hdrbuf.a_text) {
+               fprintf(stderr, "Invalid text address range 0x%08.8lu to 0x%08.8lu\n",
+                                                               addrfirst, addrlast);
+       }
+       else {
+               addrcount = (addrlast == 0) ? a_hdrbuf.a_text : addrlast;
+               addrcount -= addrfirst;
+               (void) fseek(aoutfp, A_TEXTPOS(a_hdrbuf) + addrfirst, SEEK_SET);
+               fprintf(stdout, "\nText:\n");
+               (void) dump_hex(aoutfp, A_TEXTPOS(a_hdrbuf) - a_hdrbuf.a_hdrlen
+                                                       + addrfirst, addrcount);
+       }
+  }
+
+  /* disassemble the text section */
+  if (opt_a || (opt_t && !opt_b)) {
+       /* check that all offsets are valid */
+       if (addrfirst > a_hdrbuf.a_text || addrlast > a_hdrbuf.a_text) {
+               fprintf(stderr, "Invalid text address range 0x%08.8lu to 0x%08.8lu\n",
+                                                               addrfirst, addrlast);
+       }
+       else {
+               addrcount = (addrlast == 0) ? a_hdrbuf.a_text : addrlast;
+               addrcount -= addrfirst;
+               disfp = aoutfp;                 /* file to be disassembled */
+               objfp = (FILE *)NULL;           /* without relocation information */
+               (void) fseek(disfp, A_TEXTPOS(a_hdrbuf) + addrfirst, SEEK_SET);
+               fprintf(stdout, "\nDisassembled text:\n");
+               (void) dasm(addrfirst, addrcount);
+       }
+  }
+
+  /* show the symbol data */
+  if (opt_a || opt_s) {
+       fprintf(stdout, "\nSymbol data:\n");
+       if (a_hdrbuf.a_syms == 0)
+               fprintf(stdout, "No symbol table available.\n");
+       else
+               (void) dump_asym(a_symtab, 0, a_hdrbuf.a_syms / sizeof(struct nlist));
+  }
+
+  /* wrap up */
+  (void) fclose(aoutfp);
+
+  exit(0);
+  /* NOTREACHED */
+}
+
+
+/*
+ * u s a g e
+ *
+ * Usage message.
+ *
+ * Returns:    Nothing         Always
+ */
+void usage()
+{
+  fprintf(stderr, "Usage: %s [-a|-dhst] [-b] [-f #] [-l #] [-E executable]\n",
+               progname);
+}
+
+/*
+ * EOF
+ */
+
diff --git a/commands/dis386/diso.c b/commands/dis386/diso.c
new file mode 100644 (file)
index 0000000..79a70cf
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/stat.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <a.out.h>
+#include <ansi.h>
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#undef S_ABS           /* used in a.out.h */
+#include "out.h"       /* ACK compiler output header */
+#undef EXTERN
+#define EXTERN
+#include "dis386.h"    /* dis386 header */
+#endif
+
+#ifdef OS2
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include </local/minix/minix/config.h>
+#include </local/minix/minix/const.h>
+#include </local/minix/a.out.h>
+#include </local/minix/ansi.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#undef S_ABS           /* used in a.out.h */
+#include "out.h"       /* ACK compiler output header */
+#undef EXTERN
+#define EXTERN
+#include "dis386.h"    /* dis386 header */
+#endif
+
+/* Standard defines */
+#define FALSE          0
+#undef TRUE
+#define TRUE           !FALSE
+#define FAILED         -1
+#define MAYBE          0
+#define OK             1
+#define SAME           0
+
+/* Local defines */
+#define L_BUFF_LEN     1024
+#define BUFF_LEN       256
+#define S_BUFF_LEN     20
+#define L_BUFF_MAX     (L_BUFF_LEN-1)
+#define BUFF_MAX       (BUFF_LEN-1)
+#define S_BUFF_MAX     (S_BUFF_LEN-1)
+#define PSEP           '\\'
+
+#define AOUT           "a.out" /* useful default file names */
+#define CORE           "core"
+#define OBJF           "test.o"
+#define STAB           "symbol.tab"
+#define LINE_LEN       16
+#define SYMLEN         8
+
+#define TEXT           0       /* section indices for locsym[] */
+#define ROM            1
+#define DATA           2
+#define BSS            3
+
+#ifndef lint
+static char *Version = "@(#) dis_o386.c $Revision: 1.1 $ $Date: 1997/10/20 12:00:00 $";
+#endif
+
+/* Global variables */
+int opt_C = FALSE;             /* core file name */
+int opt_E = FALSE;             /* executable file name */
+int opt_O = FALSE;             /* object file name */
+int opt_S = FALSE;             /* symbol table name */
+int opt_a = FALSE;             /* dump tables and disassemble segments */
+int opt_b = FALSE;             /* dump straight binary */
+int opt_d = FALSE;             /* dump the data segment */
+int opt_f = FALSE;             /* first address of dump */
+int opt_h = FALSE;             /* dump the header structure */
+int opt_l = FALSE;             /* last address of dump */
+int opt_m = FALSE;             /* dump the rom segment */
+int opt_n = FALSE;             /* dump the symbol names */
+int opt_r = FALSE;             /* dump the relocation structures */
+int opt_s = FALSE;             /* dump the symbol table */
+int opt_t = FALSE;             /* dump the text segment */
+int opt_u = FALSE;             /* dump the bss segment */
+int opt_x = FALSE;             /* debugging flag */
+
+char progname[BUFF_LEN];       /* program name */
+int dbglvl = 0;                        /* debugging level */
+
+/* Forward declarations */
+/* _PROTOTYPE(void usage, (void)); */
+unsigned long int atoaddr(char *sp);                   /* Convert ascii hex/dec to ulong */
+int dump_hex(FILE *fp, long s, long n);                        /* Dump bytes in hex and ascii */
+int dump_odata(FILE *fp, long s, long n, int sec);     /* Dump object file data section */
+int dump_ohdr(struct outhead *ph);                     /* Dump object file header */
+int dump_orel(FILE *fp, long s, long n);               /* Dump object file relocation section */
+int dump_osec(long b, long e, int sec, int flg);       /* Dump object file section */
+int dump_oshdr(FILE *fp, long s, long n);              /* Dump object file section headers */
+int dump_ostr(FILE *fp, long s, long n);               /* Dump object file string data */
+int dump_osym(FILE *fp, long s, long n);               /* Dump object file symbol table data */
+int find_osym(long val, int sec);                      /* Find object file symbol index */
+int gen_locsym(FILE *fp, int sec);                     /* Generate local symbols */
+int getstruct(FILE *fp, char *bp, char *s);            /* Get values from the input file */
+int init_objf(FILE *fp);                               /* Initialise object file tables */
+void usage(void);                                      /* Usage message */
+
+
+/*
+ * a t o a d d r
+ *
+ * Convert ascii hex/dec to unsigned long.
+ *
+ * Returns:    Conversion result       Always
+ */
+unsigned long int atoaddr(char *sp)
+{
+  char c, *cp, buff[S_BUFF_LEN];
+  int j;
+  unsigned long int result = 0;
+
+  /* flip to upper */
+  for (j = 0 ; j < S_BUFF_MAX && *(sp + j) != '\0' ; j++)
+       buff[j] = toupper(*(sp + j));
+  buff[j] = '\0';
+
+  /* lose leading whitespace */
+  cp = buff;
+  while isspace(*cp)
+       cp++;
+
+  /* check for hexadecimal entry */
+  if (*cp == '0' && *(cp + 1) == 'X') {
+       cp += 2;
+       while (isxdigit(*cp)) {
+               c = *cp++;
+               j = (c < 'A') ? c - '0' : c - 'A' + 10;
+               result = (result << 4) + (c < 'A' ? c - '0' : c - 'A' + 10);
+       }
+  }
+  else
+       result = atol(buff);
+
+  return result;
+}
+
+
+/*
+ * d u m p _ h e x
+ *
+ * Dump bytes in hex and ascii.
+ *
+ * Returns:    OK      Success
+ *             FAILED  File read failure, invalid arguments
+ */
+int dump_hex(FILE *fp, long start, long count)
+{
+  char c, buff[S_BUFF_LEN];
+  int j, k, status, quit, last;
+  unsigned long int ulj;
+
+  if (start < 0)
+       return(FAILED);
+
+  ulj = 0;
+  quit = FALSE;
+  status = OK;
+  while (TRUE) {
+       /* get 16 bytes of data */
+       for (j = 0 ; j < 16 ; j++) {
+               if ((k = fgetc(fp)) == EOF) {
+                       quit = TRUE;
+                       break;
+               }
+               else
+                       buff[j] = (char)k;
+       }
+
+       /* set up to dump any remaining data */
+       if (quit) {
+               status = FAILED;
+               if (j == 0)
+                       break;
+               else
+                       j--;
+       }
+       last = j;
+
+       /* print the address */
+       fprintf(stdout, "%06lx ", start + ulj);
+       ulj += 16;
+       if (ulj >= count) {
+               quit = TRUE;
+               if (last == 16)
+                       last = (count - 1) % 16;
+       }
+
+       /* print a line of hex data */
+       for (j = 0 ; j < 16 ; j++ ) {
+               if (j <= last)
+                       fprintf(stdout, " %02x", buff[j] & 0xff);
+               else
+                       fprintf(stdout, "   ");
+               if (j == 7)
+                       fprintf(stdout, " -");
+       }
+
+       /* print a trailer of ascii data */
+       fprintf(stdout, "  ");
+       for (j = 0 ; j < 16 ; j++ ) {
+               if (j <= last)
+                       c = buff[j];
+               else
+                       c = ' ';
+               if (c < 32 || c > 127)
+                       c = '.';
+               fputc(c, stdout);
+       }
+
+       fprintf(stdout, "\n");
+       if (quit)
+               break;
+  }
+
+  return(status);
+}
+
+
+/*
+ * d u m p _ o d a t a
+ *
+ * Dump object file data section.
+ *
+ * Returns:    OK      Success
+ *             FAILED  File read failure, invalid arguments
+ *
+ * The o_hdrbuf and o_sectab structures are read to determine section addresses.
+ * The o_symtab and o_strtab structures are read to determine symbol names.
+ */
+int dump_odata(FILE *fp, long start, long count, int sec)
+{
+  char label[S_BUFF_LEN], data[S_BUFF_LEN], buff[BUFF_LEN];
+  char *hex = "0123456789ABCDEF";
+  int j, k, newflg, index, last, status, found, quit;
+  long int lj, addr;
+  unsigned long int ulj;
+  struct locname *np;
+
+  if (start < 0 || (start + count) > o_sectab[sec].os_flen)
+       return(FAILED);
+
+  ulj = start;
+  quit = FALSE;
+  status = OK;
+  for (addr = start ; addr < (start + count) ; addr += 16) {
+       /* get a line's worth of data */
+       for (j = 0 ; j < 16 ; j++) {
+               if (j == (start + count - addr)) {
+                       quit = TRUE;
+                       break;
+               }
+               if ((k = fgetc(fp)) == EOF) {
+                       status = FAILED;
+                       quit = TRUE;
+                       break;
+               }
+               data[j] = (char)k;
+       }
+
+       /* adjust for an unexpected EOF */
+       if (quit && status == FAILED) {
+               if (j == 0)
+                       break;
+               else
+                       j--;
+       }
+       last = j;
+
+       /* write out the address and clear the rest of the buffer */
+       sprintf(buff, "%06lx", ulj);
+       for (k = strlen(buff) ; k < BUFF_MAX ; k++)
+               buff[k] = ' ';
+
+       /* build the hex and ascii data representations */
+       newflg = TRUE;
+       found = FALSE;
+       for (j = 0 ; j < last ; j++ ) {
+
+               /* find a local symbol, one per address */
+               for (np = locsym[sec] ; !found && np != (struct locname *)NULL ;
+                                                                       np = np->l_next) {
+                       if (ulj == np->l_value) {
+                               /* write out any outstanding data */
+                               if (j != 0) {
+                                       buff[75] = '\0';
+                                       fprintf(stdout, "%s\n", buff);
+                                       for (k = 8 ; k < 75 ; k++)
+                                               buff[k] = ' ';
+                               }
+                               /* write out the symbol name */
+                               for (k = 0 ; k < 8 ; k++)
+                                       label[k] = np->l_name[k];
+                               label[k] = '\0';
+                               fprintf(stdout, "%s\n", label);
+                               found = TRUE;
+                       }
+               }
+
+               /* find any global symbols, several per address */
+               while (!found && (index = find_osym(ulj, sec)) != -1) {
+                       /* for the first symbol, write out any outstanding data */
+                       if (newflg && j != 0) {
+                               buff[75] = '\0';
+                               fprintf(stdout, "%s\n", buff);
+                               for (k = 8 ; k < 75 ; k++)
+                                       buff[k] = ' ';
+                               newflg = FALSE;
+                       }
+                       /* write out the symbol name */
+                       lj = o_symtab[index].on_foff - (long)OFF_CHAR(o_hdrbuf);
+                       for (k = 0 ; k < 8 ; k++)
+                               label[k] = *(o_strtab + lj + k);
+                       label[k] = '\0';
+                       fprintf(stdout, "%s\n", label);
+               }
+
+               /* set up for the next pass */
+               newflg = TRUE;
+               found = FALSE;
+               ulj++;
+               /* hex digits */
+               buff[8 + (3 * j) + (j < 8 ? 0 : 2)] = hex[(data[j] >> 4) & 0x0f];
+               buff[9 + (3 * j) + (j < 8 ? 0 : 2)] = hex[data[j] & 0x0f];
+               /* ascii conversion */
+               if (data[j] < 32 || data[j] > 127)
+                       buff[59 + j] = '.';
+               else
+                       buff[59 + j] = data[j];
+               if (j == 8)
+                       buff[32] = '-';
+       }
+       buff[75] = '\0';
+
+       /* write out the result */
+       fprintf(stdout, "%s\n", buff);
+
+       if (quit) break;
+  }
+
+  return(status);
+}
+
+
+/*
+ * d u m p _ o h d r
+ *
+ * Dump object file header data.
+ *
+ * Returns:    OK      Always
+ */
+int dump_ohdr(struct outhead *ph)
+{
+  char buff[BUFF_LEN];
+
+  sprintf(buff, "Magic number:          0x%04.4x", ph->oh_magic);
+  if (ph->oh_magic == O_MAGIC) strcat(buff, " O_MAGIC");
+  else strcat(buff, " UNKNOWN");
+  fprintf(stdout, "%s\n", buff);
+
+  fprintf(stdout, "Version stamp:         0x%04.4x\n", ph->oh_stamp);
+
+  sprintf(buff, "Format flags:          0x%04.4x", ph->oh_flags);
+  if (ph->oh_flags & HF_LINK) strcat(buff, " HF_LINK");
+  if (ph->oh_flags & HF_8086) strcat(buff, " HF_8086");
+  if (ph->oh_flags & ~(HF_LINK | HF_8086)) strcat(buff, " UNKNOWN");
+  fprintf(stdout, "%s\n", buff);
+
+  fprintf(stdout, "Number of sections:    0x%04.4x\n", ph->oh_nsect);
+  fprintf(stdout, "Number of relocations: 0x%04.4x\n", ph->oh_nrelo);
+  fprintf(stdout, "Number of symbols:     0x%04.4x\n", ph->oh_nname);
+  fprintf(stdout, "Sum of section sizes:  0x%08.8x\n", ph->oh_nemit);
+  fprintf(stdout, "Size of string area:   0x%08.8x\n", ph->oh_nchar);
+
+  return(OK);
+}
+
+
+/*
+ * d u m p _ o r e l
+ *
+ * Dump object file relocation data.
+ *
+ * Returns:    OK      Success
+ *             FAILED  Invalid arguments
+ *
+ * The o_hdrbuf and o_sectab structures are read to determine section addresses.
+ * The o_symtab and o_strtab structures are read to determine symbol values.
+ */
+int dump_orel(FILE *fp, long start, long count)
+{
+  char buff[BUFF_LEN], data[S_BUFF_LEN];
+  int j;
+  unsigned int uj;
+  long int lj;
+  struct outrelo relbuf;
+
+  if (start < 0 || (start + count) > o_hdrbuf.oh_nrelo)
+       return(FAILED);
+
+  for (j = 0 ; j < count ; j++) {
+       (void) getstruct(fp, (char *)&relbuf, SF_RELO);
+       sprintf(buff, "%04d Type:", j + start);
+       if (relbuf.or_type & RELO1) strcat(buff, " RELO1");
+       if (relbuf.or_type & RELO2) strcat(buff, " RELO2");
+       if (relbuf.or_type & RELO4) strcat(buff, " RELO4");
+       if (relbuf.or_type & RELPC) strcat(buff, " RELPC");
+       else strcat(buff, "      ");
+       if (relbuf.or_type & RELBR) strcat(buff, " RELBR");
+       if (relbuf.or_type & RELWR) strcat(buff, " RELWR");
+       if (relbuf.or_type & ~(RELO1 | RELO2 | RELO4 | RELPC | RELBR | RELWR))
+               strcat(buff, "UNKNOWN");
+
+       strcat(buff, " Sect:");
+       uj = relbuf.or_sect & S_TYP;
+       if (uj >= S_MIN && uj <= S_MAX) {
+#if 1
+               /* use arbitrary names for Minix 386 */
+               sprintf(data, " %-5s", o_secnam[uj - S_MIN]);
+#else
+               sprintf(data, "  0x%02.2x", uj - S_MIN);
+#endif
+               strcat(buff, data);
+       }
+       /* S_UND is the empty S_TYP field */
+       if ((relbuf.or_sect & S_TYP) == S_UND) strcat(buff, " S_UND");
+       if ((relbuf.or_sect & S_TYP) == S_ABS) strcat(buff, " S_ABS");
+       if ((relbuf.or_sect & S_TYP) == S_CRS) strcat(buff, " S_CRS");
+
+       if ((relbuf.or_sect & S_EXT) == S_EXT) strcat(buff, " S_EXT");
+       else strcat(buff, "      ");
+
+       if (relbuf.or_sect & ~(S_TYP | S_EXT))
+               strcat(buff, " UNKNOWN");
+
+       strcat(buff, " Symb:");
+       if (relbuf.or_nami < o_hdrbuf.oh_nname) {
+               lj = o_symtab[relbuf.or_nami].on_foff - (long)OFF_CHAR(o_hdrbuf);
+               /* check that addressing isn't messed up */
+               assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
+               /* name size is defined by SZ_NAME */
+               sprintf(data, "%-13s", o_strtab + lj);
+       }
+       else
+               sprintf(data, " 0x%04.4x", relbuf.or_nami);
+       strcat(buff, data);
+       strcat(buff, " Addr:");
+       sprintf(data, " 0x%08.8x", relbuf.or_addr);
+       strcat(buff, data);
+       fprintf(stdout, "%s\n", buff);
+
+#if 0
+       printf("Type Section Symbol Address\n");
+       printf("0x%02.2x 0x%02.2x 0x%04.4x 0x%08.8x\n",
+               relbuf.or_type, relbuf.or_sect,
+               relbuf.or_nami, relbuf.or_addr);
+#endif
+  }
+
+  return(OK);
+}
+
+
+/*
+ * d u m p _ o s e c
+ *
+ * Dump object file section.
+ *
+ * Returns:    OK      Success
+ *             FAILED  Invalid arguments
+ */
+int dump_osec(long addrfirst, long addrlast, int sec, int full)
+{
+  long int addrcount;
+
+  /* check that all offsets are valid */
+  addrcount = o_sectab[sec].os_flen;
+  if (addrfirst > o_sectab[sec].os_flen || addrlast > o_sectab[sec].os_flen) {
+       fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
+                                       o_secnam[sec], addrfirst, addrlast);
+       return(FAILED);
+  }
+  else {
+       if (opt_l)
+               addrcount = addrlast + 1;
+       addrcount = addrcount - addrfirst;
+       (void) fseek(objfp, o_sectab[sec].os_foff, SEEK_SET);
+       fprintf(stdout, "\n%s%s:\n", full ? "Disassembled " : "", o_secnam[sec]);
+       if (full)
+               (void) dump_odata(objfp, addrfirst, addrcount, sec);
+       else
+               (void) dump_hex(objfp, addrfirst, addrcount);
+       return(OK);
+  }
+  /* NOTREACHED */
+}
+
+
+/*
+ * d u m p _ o s h d r
+ *
+ * Dump object file section headers.
+ *
+ * Returns:    OK      Always
+ *
+ * The o_secnam structure is read to determine section names.
+ */
+int dump_oshdr(FILE *fp, long start, long count)
+{
+  int j;
+  struct outsect secbuf;
+
+  fprintf(stdout,
+       "Name          Index Core start Core size  File start File size  Alignment\n");
+  for (j = 0 ; j < count ; j++) {
+       (void) getstruct(fp, (char *)&secbuf, SF_SECT);
+       if (j >= start)
+               fprintf(stdout, "%-13s %4.4d  0x%08.8x 0x%08.8x 0x%08.8x 0x%08.8x 0x%08.8x\n",
+                       o_secnam[j], j, secbuf.os_base, secbuf.os_size, secbuf.os_foff,
+                       secbuf.os_flen, secbuf.os_lign);
+  }
+
+  return(OK);
+}
+
+
+/*
+ * d u m p _ o s t r
+ *
+ * Dump object file string data.
+ *
+ * Returns:    OK      Success
+ *             FAILED  File read failure, invalid arguments
+ *
+ * The o_hdrbuf structure is read to determine section addresses.
+ */
+int dump_ostr(FILE *fp, long start, long count)
+{
+  int j, k;
+
+  if (start < 0 || count > o_hdrbuf.oh_nname)
+       return(FAILED);
+
+  /* we cannot precalculate the offset of a name record */
+  for (j = 0 ; j < count ; j++) {
+       fprintf(stdout, "%04d ", j + start);
+       do {
+               switch (k = fgetc(fp)) {
+               case EOF:
+                       return(FAILED);
+                       break;
+               case 0:
+                       fprintf(stdout, "\n");
+                       break;
+               default:
+                       fprintf(stdout, "%c", k);
+                       break;
+               }
+       } while (k);
+  }
+
+  return(OK);
+}
+
+
+/*
+ * d u m p _ o s y m
+ *
+ * Dump object file symbol table data.
+ *
+ * Returns:    OK      Success
+ *             FAILED  Invalid arguments
+ *
+ * The o_hdrbuf structure is read to determine section addresses.
+ * The o_strtab and o_secnam structures are read to determine symbol values.
+ */
+int dump_osym(FILE *fp, long start, long count)
+{
+  char buff[BUFF_LEN], data[S_BUFF_LEN];
+  int j;
+  unsigned int uj;
+  long lj;
+  struct outname nambuf;
+
+  if (start < 0 || (start + count) > o_hdrbuf.oh_nname)
+       return(FAILED);
+
+  for (j = 0 ; j < count ; j++) {
+       (void) getstruct(fp, (char *)&nambuf, SF_NAME);
+       sprintf(buff, "%4.4d", j + start);
+#if 1
+       lj = nambuf.on_foff - (long)OFF_CHAR(o_hdrbuf);
+       /* check that addressing isn't messed up */
+       assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
+       /* name size is defined by SZ_NAME */
+       sprintf(data, " %-13s", o_strtab + lj);
+       strcat(buff, data);
+#else
+       sprintf(data, " 0x%08.8x", nambuf.on_foff);
+       strcat(buff, data);
+#endif
+       strcat(buff, " Type:");
+       uj = nambuf.on_type & S_TYP;
+       if (uj >= S_MIN && uj <= S_MAX) {
+#if 1
+               /* use arbitrary names for Minix 386 */
+               sprintf(data, " %-5s", o_secnam[uj - S_MIN]);
+#else
+               sprintf(data, "  0x%02.2x", uj - S_MIN);
+#endif
+               strcat(buff, data);
+       }
+       /* S_UND is the empty S_TYP field */
+       if ((nambuf.on_type & S_TYP) == S_UND) strcat(buff, " S_UND");
+       if ((nambuf.on_type & S_TYP) == S_ABS) strcat(buff, " S_ABS");
+       if ((nambuf.on_type & S_TYP) == S_CRS) strcat(buff, " S_CRS");
+
+       if ((nambuf.on_type & S_EXT) == S_EXT) strcat(buff, " S_EXT");
+       else strcat(buff, "      ");
+
+       if ((nambuf.on_type & S_ETC) == S_SCT) strcat(buff, " S_SCT");
+       if ((nambuf.on_type & S_ETC) == S_LIN) strcat(buff, " S_LIN");
+       if ((nambuf.on_type & S_ETC) == S_FIL) strcat(buff, " S_FIL");
+       if ((nambuf.on_type & S_ETC) == S_MOD) strcat(buff, " S_MOD");
+       if ((nambuf.on_type & S_ETC) == S_COM) strcat(buff, " S_COM");
+       if ((nambuf.on_type & S_ETC) == 0) strcat(buff, "      ");
+
+       if (nambuf.on_type &
+               ~(S_TYP | S_EXT | S_SCT | S_LIN | S_FIL | S_MOD | S_COM))
+               strcat(buff, " UNKNOWN");
+
+#if 1
+       /* Desc is not used, so save space */
+       strcat(buff, " Desc: 0x00");
+#else
+       strcat(buff, " Desc:");
+       sprintf(data, " 0x%04.4x", nambuf.on_desc);
+       strcat(buff, data);
+#endif
+       strcat(buff, " Valu:");
+       sprintf(data, " 0x%08.8x", nambuf.on_valu);
+       strcat(buff, data);
+       fprintf(stdout, "%s\n", buff);
+  }
+#if 0
+  fprintf(stdout, "Name Type Debug Value\n");
+  fprintf(stdout, "0x%08.8x 0x%04.4x 0x%04.4x 0x%08.8x\n",
+               nambuf.on_u.on_off, nambuf.on_type,
+               nambuf.on_desc, nambuf.on_valu);
+#endif
+
+  return(OK);
+}
+
+
+/*
+ * f i n d _ o s y m
+ *
+ * Find an object file symbol name in a unsorted list.
+ *
+ * Returns:    index   Found
+ *             -1      Not found
+ *
+ * There may be several symbols with the same value:
+ * return each of them on successive calls.
+ *
+ */
+int find_osym(long value, int sec)
+{
+  static int index = 0;
+  static long oldval = 0;
+  static int oldsec = 0;
+  int j;
+
+  /* check for a repeated search */
+  if (value != oldval || sec != oldsec) {
+       oldval = value;
+       oldsec = sec;
+       index = 0;
+  }
+  /* never happen */
+  else if (index == -1)
+       return(FAILED);
+
+  /* do a linear search for a symbol, as the symbol table is unsorted */
+  for (j = index ; j < o_hdrbuf.oh_nname ; j++) {
+       if (value == o_symtab[j].on_valu &&
+                       sec == ((o_symtab[j].on_type & S_TYP) - S_MIN))
+               break;
+  }
+
+  /* set up the index for the next pass */
+  if (j == o_hdrbuf.oh_nname)
+       index = 0;
+  else
+       index = j + 1;
+
+ return(index - 1);
+}
+
+
+/*
+ * g e n _ l o c s y m
+ *
+ * Generate local symbols.
+ *
+ * Returns:    OK      Success
+ *             FAILED  Invalid arguments, malloc failure
+ *
+ * This works only for .data, .rom and .bss.  Text symbols need
+ * a disassembly of the text section, and intelligent guesses as
+ * to whether a local address refers to text or data.  In fact,
+ * this routine can be usefully applied only to the .rom area.
+ */
+int gen_locsym(FILE *fp, int sec)
+{
+  char data[20];
+  int j, txtflg, hdrflg;
+  long int addrcount;
+  struct locname *np, *current;
+
+  /* check that all offsets are valid - this routine won't work for text */
+  if (sec < ROM || sec > BSS) {
+       fprintf(stderr, "Invalid section %s\n", o_secnam[sec]);
+       return(FAILED);
+  }
+
+  /* initialise the label string */
+  strncpy(data, o_secnam[sec], 4);
+  data[4] = '\0';
+
+  /* initialise the in-memory local name table pointers */
+  current = (struct locname *)(NULL);
+
+  /* read the data area and load the symbols */
+  (void) fseek(fp, o_sectab[sec].os_foff, SEEK_SET);
+  addrcount = 0;
+  txtflg = hdrflg = FALSE;
+  while (addrcount < o_sectab[sec].os_flen) {
+       j = fgetc(fp);
+       if (j < 040 || j > 0177) {
+               txtflg = FALSE;
+               hdrflg = FALSE;
+       }
+       else
+               txtflg = TRUE;
+
+       /* ensure that the start of each apparent string has a related symbol */
+       if (txtflg && !hdrflg) {
+               if (find_osym(addrcount, sec) == -1) {
+                       /* if malloc fails, just collapse */
+                       if ((np = (struct locname *)malloc(sizeof(struct locname)))
+                                       == (struct locname *)NULL) {
+                               fprintf(stderr, "%s: malloc failed\n", progname);
+                               return(FAILED);
+                       }
+                       /* update the current record */
+                       sprintf(np->l_name, "%s%04x", data, addrcount & 0xffff);
+                       /* nb. must follow l_name update */
+                       if (sec == TEXT) np->l_sclass = S_TEXT & 0xff;
+                       else if (sec == ROM) np->l_sclass = S_DATA & 0xff;
+                       else if (sec == DATA) np->l_sclass = S_DATA & 0xff;
+                       else if (sec == BSS) np->l_sclass = S_BSS & 0xff;
+                       else sec = 0;
+                       np->l_value = addrcount;
+                       np->l_next = (struct locname *)NULL;
+                       /* and add it to the list */
+                       if (current == (struct locname *)NULL)
+                               locsym[sec] = np;
+                       else
+                               current->l_next = np;
+                       current = np;
+               }
+               hdrflg = TRUE;
+       }
+       addrcount++;
+  }
+
+  return(OK);
+}
+
+
+
+/*
+ * g e t s t r u c t
+ *
+ * Returns:    0       Always
+ *
+ * Get 1, 2 and 4 byte values from the input file.
+ *
+ * Note that the bytes must be reordered and the
+ * read pointer incremented correctly for each value;
+ * hence the need for a structure format string.
+ *
+ * Called with:
+ * a file destcriptor
+ * a pointer to the output buffer
+ * a structure format string
+ */
+int getstruct(FILE *fp, char *bp, char *s)
+{
+  int j;
+  long lj;
+
+  while (TRUE) {
+       switch (*s++) {
+#if 0
+       /* not used */
+       case '0':
+               bp++;
+               continue;
+#endif
+       case '1':
+               *bp++ = (char) getc(fp);
+               continue;
+       case '2':
+               j = getc(fp);
+               j |= (getc(fp) << 8);
+               *((short *)bp) = (short) j;
+               bp += 2;
+               continue;
+       case '4':
+               lj = (long)getc(fp);
+               lj |= ((long)getc(fp) << 8);
+               lj |= ((long)getc(fp) << 16);
+               lj |= ((long)getc(fp) << 24);
+               *((long *)bp) = lj;
+               bp += 4;
+               continue;
+       default:
+               break;
+       }
+       break;
+  }
+
+  return(0);
+}
+
+
+/*
+ * i n i t _ o b j f
+ *
+ * Initialise object file tables.
+ *
+ * Returns:    OK      Success
+ *             FAILED  Otherwise
+ */
+int init_objf(FILE *fp)
+{
+  char *cp;
+  int j;
+  unsigned int uj;
+  long int lj;
+
+  /* load the header into memory for fast access */
+  (void) getstruct(fp, (char *)&o_hdrbuf, SF_HEAD);
+  if (BADMAGIC(o_hdrbuf)) {
+       fprintf(stderr, "%s: bad magic number.\n", progname);
+       return(FAILED);
+  }
+  if (o_hdrbuf.oh_nsect == 0) {
+       fprintf(stderr, "%s: no sections present.\n", progname);
+       return(FAILED);
+  }
+
+  /* check that the whole file can be read */
+  if (fseek(fp, OFF_CHAR(o_hdrbuf) + o_hdrbuf.oh_nchar, SEEK_SET) != 0) {
+       fprintf(stderr, "%s: cannot seek to end of file.\n", progname);
+       return(FAILED);
+  }
+
+  /* load the section data into memory for fast access */
+  uj = o_hdrbuf.oh_nsect * sizeof(struct outsect);
+  if (fseek(fp, OFF_SECT(o_hdrbuf), SEEK_SET) != 0) {
+       fprintf(stderr, "%s: cannot seek to section area.\n", progname);
+       return(FAILED);
+  }
+  if (fread(o_sectab, sizeof(char), uj, fp) != uj) {
+       fprintf(stderr, "%s: cannot read section area.\n", progname);
+       return(FAILED);
+  }
+
+  /* load the relocation data into memory for fast access */
+  /* ### Should this be left on disk and only the indices loaded ? */
+  uj = o_hdrbuf.oh_nrelo * sizeof(struct outrelo);
+  if (fseek(fp, OFF_RELO(o_hdrbuf), SEEK_SET) != 0) {
+       fprintf(stderr, "%s: cannot seek to relocation area.\n", progname);
+       return(FAILED);
+  }
+  if ((cp = (char *)malloc(uj)) == (char *)NULL) {
+       fprintf(stderr, "%s: malloc failed\n", progname);
+       return(FAILED);
+  }
+  if (fread(cp, sizeof(char), uj, fp) != uj) {
+       fprintf(stderr, "%s: cannot read relocation area.\n", progname);
+       return(FAILED);
+  }
+  /* initialise the in-memory relocation table array pointers */
+  o_reltab = (struct outrelo *)cp;
+
+  /* ### needs to be optional for files without symbol tables */
+  /* load the symbol table into memory for fast access */
+  uj = o_hdrbuf.oh_nname * sizeof(struct outname);
+  if ((cp = (char *)malloc(uj)) == (char *)NULL) {
+       fprintf(stderr, "%s: malloc failed\n", progname);
+       return(FAILED);
+  }
+  if (fseek(fp, OFF_NAME(o_hdrbuf), SEEK_SET) != 0) {
+       fprintf(stderr, "%s: cannot seek to symbol area.\n", progname);
+       return(FAILED);
+  }
+  if (fread(cp, sizeof(char), uj, fp) != uj) {
+       fprintf(stderr, "%s: cannot read symbol area.\n", progname);
+       return(FAILED);
+  }
+  /* initialise the in-memory symbol table array pointers */
+  o_symtab = (struct outname *)cp;
+
+  /* load the string area into memory for fast access */
+  uj = (unsigned int)o_hdrbuf.oh_nchar;
+  if ((o_strtab = (char *)malloc(uj)) == (char *)NULL) {
+       fprintf(stderr, "%s: malloc failed\n", progname);
+       return(FAILED);
+  }
+  if (fseek(fp, OFF_CHAR(o_hdrbuf), SEEK_SET) != 0) {
+       fprintf(stderr, "%s: cannot seek to string area.\n", progname);
+       return(FAILED);
+  }
+  if (fread(o_strtab, sizeof(char), uj, fp) != uj) {
+       fprintf(stderr, "%s: cannot read string area.\n", progname);
+       return(FAILED);
+  }
+
+  /* build the section name table */
+  for (j = 0 ; j < o_hdrbuf.oh_nname ; j++) {
+       if ((o_symtab[j].on_type & S_ETC) == S_SCT) {
+               lj = o_symtab[j].on_foff - (long)OFF_CHAR(o_hdrbuf);
+               /* check that addressing isn't messed up */
+               assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
+               strncpy(o_secnam[(o_symtab[j].on_type & S_TYP) - S_MIN],
+                               o_strtab + lj, SZ_NAME + 1);
+       }
+  }
+
+  /* build the local symbol tables */
+  for (j = 0 ; j < MAXSECT ; j++)
+       locsym[j] = (struct locname *)NULL;
+
+  /* build the local .text symbol table */
+  /* ### full disassembly ? */
+
+  /* build the local .rom symbol table */
+  if (gen_locsym(fp, ROM) == FAILED)
+       return(FAILED);
+
+  /* there's no point in building the .data and .bss tables */
+
+  return(OK);
+}
+
+
+/*
+ * m a i n
+ *
+ * Main routine of dis_o386.
+ */
+int main(int argc, char *argv[])
+{
+  char *cp, objfile[BUFF_LEN], symbfile[BUFF_LEN];
+  char table[MAXSECT*(SZ_NAME+2)];
+  int j, errors;
+  unsigned long int addrfirst, addrlast, addrcount;
+  struct stat statbuff;
+
+  /* initial set up */
+  if ((cp = strrchr(argv[0], PSEP)) == (char *)NULL)
+       cp = argv[0];
+  else
+       cp++;
+  strncpy(progname, cp, BUFF_MAX);
+  strncpy(objfile, OBJF, BUFF_MAX);
+  addrfirst = addrlast = addrcount = 0;
+
+  /* clear the in-core name tables */
+  o_strtab = (char *)NULL;
+  for (j = 0 ; j < MAXSECT ; j++)
+       o_secnam[j] = table + j * (SZ_NAME + 2);        /* nb. leading '_' */
+  for (j = 0 ; j < sizeof(table) ; j++) table[j] = '\0';
+
+  /* check for an MSDOS-style option */
+  if (argc == 2 && argv[1][0] == '/') {
+       usage();
+       exit(0);
+  }
+
+  /* parse arguments */
+  errors = opterr = 0;
+  while ((j = getopt(argc, argv, "O:S:abdf:hl:mnrstx:")) != EOF) {
+       switch (j & 0177) {
+#if 0
+       case 'C':                       /* core file name */
+               opt_C = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(binfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+       case 'E':                       /* executable file name */
+               opt_E = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(binfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+#endif
+       case 'O':                       /* object file name */
+               opt_O = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(objfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+       case 'S':                       /* symbol table name */
+               opt_S = TRUE;
+               if (optarg != (char *)NULL)
+                       strncpy(symbfile, optarg, BUFF_MAX);
+               else
+                       errors++;
+               break;
+       case 'a':                       /* dump tables and disassemble segments */
+               opt_a = TRUE;
+               break;
+       case 'b':                       /* dump straight binary */
+               opt_b = TRUE;
+               break;
+       case 'd':                       /* dump the data segment */
+               opt_d = TRUE;
+               break;
+       case 'f':                       /* first address of dump */
+               opt_f = TRUE;
+               if (optarg != (char *)NULL) {
+                       addrfirst = atoaddr(optarg);
+               }
+               else
+                       errors++;
+               break;
+       case 'h':                       /* dump the header */
+               opt_h = TRUE;
+               break;
+       case 'l':                       /* last address of dump */
+               opt_l = TRUE;
+               if (optarg != (char *)NULL) {
+                       addrlast = atoaddr(optarg);
+               }
+               else
+                       errors++;
+               break;
+       case 'm':                       /* dump the rom segment */
+               opt_m = TRUE;
+               break;
+       case 'n':                       /* dump the symbol names */
+               opt_n = TRUE;
+               break;
+       case 'r':                       /* dump the relocation structures */
+               opt_r = TRUE;
+               break;
+       case 's':                       /* dump the symbol table */
+               opt_s = TRUE;
+               break;
+       case 't':                       /* dump the text segment */
+               opt_t = TRUE;
+               break;
+#if 0
+       case 'u':                       /* dump the bss segment */
+               opt_u = TRUE;
+               break;
+#endif
+       case 'x':                       /* debugging flag */
+               opt_x = TRUE;
+               if (optarg != (char *)NULL)
+                       dbglvl = atoi(optarg);
+               break;
+       case '?':
+       default:
+               usage();
+               exit(1);
+               break;
+       }
+  }
+
+  /* check the flags */
+  if (errors > 0) {
+       usage();
+       exit(1);
+  }
+  if (opt_a && (opt_d || opt_h || opt_m || opt_n ||
+               opt_r || opt_s || opt_t)) {
+       usage();
+       exit(1);
+  }
+  if ((opt_f || opt_l) && (addrlast > 0  && addrfirst > addrlast)) {
+       usage();
+       exit(1);
+  }
+
+  /* check for a specific input file */
+  if (optind < argc)
+       strncpy(objfile, argv[optind], BUFF_MAX);
+
+  /* we must have a binary file of some sort */
+  if ((objfp = fopen(objfile, "rb")) == (FILE *)NULL ||
+               stat(objfile, &statbuff) == -1) {
+       perror(objfile);
+       exit(1);
+  }
+
+  /* initialise the object file data structures */
+  if (init_objf(objfp) == FAILED) {
+       perror(objfile);
+       exit(1);
+  }
+
+  /* show the output file name and date */
+  fprintf(stdout, "File name: %s\nFile date: %s",
+               objfile, ctime(&statbuff.st_ctime));
+
+  /* show the header and section data - default behaviour */
+  if (opt_a || opt_h || (!opt_d && !opt_m && !opt_n &&
+               !opt_r && !opt_s && !opt_t)) {
+       fprintf(stdout, "\nHeader data:\n");
+       (void) dump_ohdr(&o_hdrbuf);
+       fprintf(stdout, "\nSection data:\n");
+       (void) fseek(objfp, OFF_SECT(hdrbuf), SEEK_SET);
+       (void) dump_oshdr(objfp, 0, o_hdrbuf.oh_nsect);
+  }
+
+  /* The core start address is zero for every section.  What allowances
+   * should be made for the differences between file and core images?
+   */
+
+  /* dump or disassemble the rom section */
+  if (opt_a || opt_m) {
+       if (opt_b)
+               (void) dump_osec(addrfirst, addrlast, ROM, FALSE);
+       else
+               (void) dump_osec(addrfirst, addrlast, ROM, TRUE);
+  }
+
+  /* dump or disassemble the data section */
+  if (opt_a || opt_d) {
+       if (opt_b)
+               (void) dump_osec(addrfirst, addrlast, DATA, FALSE);
+       else
+               (void) dump_osec(addrfirst, addrlast, DATA, TRUE);
+  }
+
+  /* dump or disassemble the text section */
+  if (opt_a || opt_t) {
+       /* check that all offsets are valid */
+       if (addrfirst > o_sectab[TEXT].os_flen || addrlast > o_sectab[TEXT].os_flen) {
+               fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
+                                               "text", addrfirst, addrlast);
+       }
+       else {
+               if (opt_b)
+                       (void) dump_osec(addrfirst, addrlast, TEXT, FALSE);
+               else {
+                       addrcount = (addrlast == 0) ? o_sectab[TEXT].os_flen : addrlast;
+                       addrcount -= addrfirst;
+                       disfp = objfp;                  /* file to be disassembled */
+                       (void) fseek(disfp, o_sectab[TEXT].os_foff + addrfirst, SEEK_SET);
+                       fprintf(stdout, "\nDisassembled text:\n");
+                       (void) dasm(addrfirst, addrcount);
+               }
+       }
+  }
+
+  /* show the relocation data */
+  if (opt_a || opt_r) {
+       if (opt_b)
+               addrcount = o_hdrbuf.oh_nrelo * sizeof(struct outrelo);
+       else
+               addrcount = o_hdrbuf.oh_nrelo;
+       /* check that all offsets are valid */
+       if (addrfirst >= addrcount || addrlast >= addrcount) {
+               fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
+                               "relocation", addrfirst, addrlast);
+       }
+       else {
+               if (opt_l)
+                       addrcount = addrlast + 1;
+               addrcount = addrcount - addrfirst;
+               if (opt_b) {
+                       fprintf(stdout, "\nRelocation data dump:\n");
+                       (void) fseek(objfp, OFF_RELO(o_hdrbuf) + addrfirst, SEEK_SET);
+                       (void) dump_hex(objfp, addrfirst, addrcount);
+               }
+               else {
+                       fprintf(stdout, "\nRelocation data:\n");
+                       (void) fseek(objfp, OFF_RELO(o_hdrbuf) + addrfirst *
+                                       sizeof(struct outrelo), SEEK_SET);
+                       (void) dump_orel(objfp, addrfirst, addrcount);
+               }
+       }
+  }
+
+  /* show the symbol data */
+  if (opt_a || opt_s) {
+       if (opt_b)
+               addrcount = o_hdrbuf.oh_nname * sizeof(struct outname);
+       else
+               addrcount = o_hdrbuf.oh_nname;
+       /* check that all offsets are valid */
+       if (addrfirst >= addrcount || addrlast >= addrcount) {
+               fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
+                               "symbol", addrfirst, addrlast);
+       }
+       else {
+               if (opt_l)
+                       addrcount = addrlast + 1;
+               addrcount = addrcount - addrfirst;
+               if (opt_b) {
+                       fprintf(stdout, "\nSymbol data dump:\n");
+                       (void) fseek(objfp, OFF_NAME(o_hdrbuf) + addrfirst, SEEK_SET);
+                       (void) dump_hex(objfp, addrfirst, addrcount);
+               }
+               else {
+                       fprintf(stdout, "\nSymbol data:\n");
+                       (void) fseek(objfp, OFF_NAME(o_hdrbuf) + addrfirst *
+                                       sizeof(struct outname), SEEK_SET);
+                       (void) dump_osym(objfp, addrfirst, addrcount);
+               }
+       }
+  }
+
+  /* show the string data */
+  if (opt_a || opt_n) {
+       if (opt_b)
+               addrcount = o_hdrbuf.oh_nchar;
+       else
+               addrcount = o_hdrbuf.oh_nname;  /* assumes one name per symbol */
+       /* check that all offsets are valid */
+       if (addrfirst >= addrcount || addrlast >= addrcount) {
+               fprintf(stderr, "Invalid %s address range 0x%08.8lu to 0x%08.8lu\n",
+                               "symbol", addrfirst, addrlast);
+       }
+       else {
+               if (opt_l)
+                       addrcount = addrlast + 1;
+               addrcount = addrcount - addrfirst;
+               if (opt_b) {
+                       fprintf(stdout, "\nName data dump:\n");
+                       (void) fseek(objfp, OFF_CHAR(o_hdrbuf) + addrfirst, SEEK_SET);
+                       (void) dump_hex(objfp, addrfirst, addrcount);
+               }
+               else {
+                       fprintf(stdout, "\nName data:\n");
+                       (void) fseek(objfp, o_symtab[addrfirst].on_foff, SEEK_SET);
+                       (void) dump_ostr(objfp, addrfirst, addrcount);
+               }
+       }
+  }
+
+  /* wrap up */
+  fclose(objfp);
+
+  exit(0);
+}
+
+
+/*
+ * u s a g e
+ *
+ * Usage message.
+ *
+ * Returns:    Nothing         Always
+ */
+void usage()
+{
+  fprintf(stderr, "Usage: %s [-a|-dhmnrst] [-b] [-f #] [-l #] [-O objfile]\n",
+               progname);
+}
+
+
+/*
+ * EOF
+ */
+
diff --git a/commands/dis386/misc.c b/commands/dis386/misc.c
new file mode 100644 (file)
index 0000000..760d1cc
--- /dev/null
@@ -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 <sys/types.h>
+#ifdef MINIX
+#include <minix/config.h>
+#include <minix/const.h>
+#include <a.out.h>
+#endif
+#ifdef OS2
+typedef unsigned char u8_t;
+typedef unsigned int u16_t;
+typedef unsigned long u32_t;
+#include </local/minix/minix/config.h>
+#include </local/minix/minix/const.h>
+#include </local/minix/a.out.h>
+#endif
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 (file)
index 0000000..d68938a
--- /dev/null
@@ -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 (file)
index 0000000..f11b5e2
--- /dev/null
@@ -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 (file)
index 0000000..6297621
--- /dev/null
@@ -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 <sys/types.h>
+#include <a.out.h>
+#endif
+#ifdef OS2
+typedef unsigned char u8_t;
+typedef unsigned int u16_t;
+typedef unsigned long u32_t;
+#include </local/minix/a.out.h>
+#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 (file)
index 0000000..ea48439
--- /dev/null
@@ -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;
+