n0ano@wldrdg.UUCP (05/26/87)
I've written a version of `adb' for MINIX that might be of some utility. It's major advantage is that it can read a MINIX symbol table listing and can dis-assemble 8086 object code. It consists of 5 files, `adb.doc' (very rudimentary documentation), `makefile', `adb.h', `adb.c' and `optab.c'. The files are in this article with each file preceeded by a line of the form: --- cut here for : file --- where `file' is one of the 5 files. (I didn't use `shar' because the shell can't extrace the resulting file.) Don't get your hopes up too far. This version of `adb' doesn't support process control (no breakpoints) or core dumps. Word of warning. As released the files `/dev/mem' and `/dev/kmem' are block special files. This means that accesses to them go through the buffer cache and therefore only the first access really goes to memory, all other accesses are satisfied from the cache. I got around this problem by redefining these two files as character special files, now read and write requests go directly to the driver. Don Dugger Wildridge Consulting ...nbires!wldrdg!n0ano "Censeo Toto nos in Kansa esse desisse" --- cut here for : adb.doc --- NAME adb - absolute debugger SYNOPSIS adb [ -w ] [ -b ] [ -m map ] a.out [ core ] DESCRIPTION This is a rewritten version of adb for MINIX. It can be used to examine and/or write binary files, especially a.out images and core dumps. The command line parameters (those inclosed in brackets are optional) are: -w Normally, files cannot be written. This flag enables the writing capabilities of `adb'. -b Files are read and written 1 to 4 bytes at a time. Since this is rather slow the `b' flag causes the file data to be buffered 1024 bytes at a time. This will normally speed things up but if you are examining time sensitive data, such as the contents of `/dev/kmem', you should not use this flag. -m Indicates that `map' is a load map associated with file `a.out'. a.out The a.out image that is to be examined. core An optional core dump associated with `a.out'. (Currently `adb' does not recognize core dumps so this parameter just allows 2 different files to be examined at the same time.) The commands to `adb' normally consist of the fields: [address][,count][file][format] Each field is optional and except for `count' keeps its prior value if omitted. `count' takes the value 1 if it is omitted. An address can be: nnn An absolute number in the default base. The default base starts out at 16. 0xn A hexadecimal number. 0on An octal number. That is zero followed by the letter o. 0tn A decimal number. symbol A symbol from the load map. Only external symbols are recognized and all `C' language symbols have a leading `_' that must be specified, e.g. `_main' is the symbol for the main routine. . The period (dot) represents the current address to `adb'. Addresses and counts can be formed from arithmetic expressions made from address quantities. The following operators have equal precedence but can be grouped with parenthesis: + Addition - Subtraction * Multiplication % Division The `file' field identifies which file from which to read the data. ? Data from/to a.out / Data from/to core. = Don't use a file, instead the address field specifies the data rather than the address of the data. $ Special commands to `adb' unrelated to the files. : Process control commands. (Currently unimplemented.) `format' specifies how the data in the specified file will be printed. It consists of a string of format characters. If more than one format character is given then successive data from the file will be printed. The current format characters are: x 2-byte hexadecimal integer X 4-byte hexadecimal integer o 2-byte octal integer O 4-byte octal integer d 2-byte decimal integer D 4-byte decimal integer b 1-byte octal integer i print as an 8086 instruction p print the current address. If a map was specified it will be printed as a positive offset from the closest symbol. a same as `a' only a `:\t' will follow the address. c one character s string of characters terminated by a 0 byte. S string of characters terminated by a 0 byte. Unprintable ASCII characters show as a period. "ss" print the enclosed string. There are no escapes, you can't print a ". The special commands, indicated by a file field of `$', are: q quit d set the default base to 10. o set the default base to 8. x set the default base to 16. s set the `symbol offset' match to the current address. Under the `a' and `p' format characters I lied. Addresses are only printed as symbol plus offset if the address if closer than `symbol offset' from the nearest external symbol. This command allows you to change that `symbol offset', which defaults to 256, to a different value. m print the current address maps. Address maps are described later. M same as `m'. A new-line alone is a special command. This command means increment the current address by the size of the current format and then print data from the current file with the current format. In order to write 2 bytes to a file use the command: [address][,count][file]w value where `value' is an arithmetic expression. To write 4 bytes use a `W' rather than a `w'. This command can only be used if the `-w' flag was given on the command line. `adb' maintains 2 address maps for both the a.out and core files. These maps are needed because program virtual addresses are not one-to-one with file addresses for either an a.out image or a core dump. To deal with this `adb' maintains two 3-tuples for both files. The 3-tuples are: b1,b2 first program virtual address e1,e2 ending program virtual address f1,f2 file offset To map between program virtual addresses and file addresses, `adb' applies the following 3 rules: 1: if b1 <= address < e1 then file address = address - b1 + f1 2: if b2 <= address < e2 then file address = address - b2 + f2 3: otherwise file address = address To change the mapping numbers for `a.out' use the commands ?m b1 e1 f1 ?*m b2 e2 f2 where `b1', `e1', `f1', `b2', `e2', and `f2' are the new values for the associated map numbers. Likewise, to change the mapping numbers for `core' use the commands /m b1 e1 f1 /*m b2 e2 f2 EXAMPLES 100,3/X starting at location 100 print 3 4-byte integers in hex. 100/XXX same thing as prior command _main?aiiii starting at `main' print the current address and then decode 4 instructions 0t100$s set the `symbol offset' to 100 decimal 100/X print the 4-byte integer at 100 in hex ./W 0x123 write 0x123 to the 4 bytes starting at 100 1+2*3=D print the expression (1+2)*3 in decimal 1+(2*3)=x print the expression 1+(2*3) in hex. 1000=p print nearest symbol to 1000. CAVEATS The instruction decode is my interpretation of INTEL's encoding scheme. It has not been tested for all valid instructions so I'm sure there are some glitches in it. --- cut here for : makefile --- OBJ=adb.s optab.s CFLAGS=-c -T. .c.s: cc $(CFLAGS) $*.c adb: $(OBJ) rm /lib/cpp /lib/cem cc -T. $(OBJ) --- cut here for : adb.h --- #define NUMERIC 3 #define HEX 7 #define ALPHA 5 #define SPEC 8 #define ALPHANUM 1 #define HEXDIG 2 #define ALPHAONLY 4 #define BSIZE 512 #define LOGBS 9 #define SYMSZ 10 struct symbol { struct symbol * next; unsigned int value; char name[SYMSZ]; }; struct file { int fid; char * name; struct symbol *symptr; long cblock; long tmap[3]; long dmap[3]; char buf[BSIZE + BSIZE]; }; #define b1 tmap[0] #define e1 tmap[1] #define f1 tmap[2] #define b2 dmap[0] #define e2 dmap[1] #define f2 dmap[2] struct fheader { long magic; long flag; long tsize; long dsize; long bsize; long entry; long size; long fill; }; #define MAGIC 0x04100301L #define IDMAGIC 0x04200301L --- cut here for : adb.c --- #include <stdio.h> #include "adb.h" struct file binary; struct file core; long dot; int dotoff; int maxoff = 256; int ibase = 16; int lastc = 0; char lbuf[128]; char *bufp = lbuf; char sign = 0; int mode = 0; int buffer = 0; main(argc, argv) int argc; char *argv[]; { char *cp; binary.symptr = 0; core.symptr = 0; while (argc > 1 && argv[1][0] == '-') { for (cp = &argv[1][1]; *cp; ) switch (*cp++) { case 'b': buffer++; break; case 'w': mode = 2; break; case 'm': setsym(argv[2]); argc--; argv++; break; default: printf("%c:unknown flag\n", cp[-1]); break; } argc--; argv++; } if (argc > 1) { binary.name = argv[1]; core.name = argv[1]; } if (argc > 2) core.name = argv[2]; if ((binary.fid = open(binary.name, mode)) < 0) { printf("%s:cannot open\n", binary.name); exit(1); } if ((core.fid = open(core.name, mode)) < 0) { printf("%s:cannot open\n", core.name); exit(2); } setobj(&binary); setcor(&core); adb(); } setobj(fp) struct file *fp; { struct fheader hdr; fp->b1 = 0; fp->e1 = -1; fp->f1 = 0; fp->b2 = 0; fp->e2 = -1; fp->f2 = 0; fp->cblock = -1; lseek(fp->fid, (long)0, 0); if (read(fp->fid, &hdr, sizeof(hdr)) != sizeof(hdr)) return; if (hdr.magic != MAGIC && hdr.magic != IDMAGIC) return; fp->b1 = 0; fp->e1 = hdr.tsize; fp->f1 = sizeof(hdr); fp->b2 = hdr.tsize; fp->e2 = hdr.tsize + hdr.dsize; fp->f2 = hdr.tsize + hdr.tsize; return; } setcor(fp) struct file *fp; { fp->b1 = 0; fp->e1 = -1; fp->f1 = 0; fp->b2 = 0; fp->e2 = 0; fp->f2 = 0; fp->cblock = -1; return; } adb() { int cmddol(), cmdcol(), cmdprt(), cmdwrt(), null(); long getn(), getdot(); long expr(); register int c, lc, count; int (*f)(); long (*g)(); char fmt[128]; f = cmdprt; g = getdot; lc = '='; dot = 0; dotoff = 0; for (;;) { if ((c = peekc()) == '(' || c == '.' || (type(c) & ALPHANUM)) { dot = expr(); dotoff = 0; } if (peekc() == ',') { nb(); count = expr(); } else count = 1; switch (c = nb()) { case EOF: return; case '$': f = cmddol; break; case ':': f = cmdcol; break; case '?': case '/': g = getn; switch (peekc()) { case 'w': case 'W': f = cmdwrt; break; default: f = cmdprt; getfmt(fmt); case '\n': break; } break; case '=': f = cmdprt; g = getdot; getfmt(fmt); break; case '\r': case '\n': c = lc; dot += dotoff; break; default: f = null; count = 1; break; } dotoff = 0; while (count--) (*f)(c, fmt, g); lc = c; while (getchr() != '\n') ; } } getchr() { register int c; if (lastc) { c = lastc; lastc = 0; } else c = getchar(); return(c); } pushc(c) int c; { lastc = c; return(c); } peekc() { return(pushc(nb())); } nb() { register int c; while ((c = getchr()) == ' ' || c == '\t') ; if (c == '\n') pushc(c); return(c); } type(c) char c; { if (c >= '0' && c <= '9') return(NUMERIC); if (c >= 'a' && c <= 'f') return(HEX); if (c >= 'A' && c <= 'F') return(HEX); if (c >= 'g' && c <= 'z') return(ALPHA); if (c >= 'G' && c <= 'Z') return(ALPHA); if (c == '_') return(ALPHA); return(SPEC); } long expr() { long term(); long r; int c; r = term(); for (;;) switch (c = nb()) { case '+': r += term(); break; case '-': r -= term(); break; case '*': r *= term(); break; case '%': r /= term(); break; case ')': default: pushc(c); return(r); } } long term() { long n; register int c, base; char *cp, buf[80]; struct symbol *sp, *findnam(); if ((c = nb()) == '(') { n = expr(); if (nb() != ')') putchr('?'); return(n); } else if (c == '\'') { n = 0; while ((c = getchr()) != '\'') if (c == '\n') { pushc(c); break; } else n = (n << 8) | c; return(n); } else if (c == '.' || (type(c) & ALPHAONLY)) { cp = buf; *cp++ = c; if (c == '.') if (type(pushc(getchr())) == SPEC) return(dot); while (type(c = getchr()) & ALPHANUM) *cp++ = c; *cp = '\0'; pushc(c); if (sp = findnam(buf, binary.symptr)) return(sp->value); else if (sp = findnam(buf, core.symptr)) return(sp->value); pushc('@'); return(0); } n = 0; base = ibase; if (c == '0') { base = 8; switch (pushc(getchr())) { case 'x': base += 6; case 't': base += 2; case 'o': getchr(); c = getchr(); break; default: base = ibase; break; } } while (type(c) & HEXDIG) { if (c >= 'a' && c <= 'f') c -= 'a' - '9' - 1; if (c >= 'A' && c <= 'F') c -= 'A' - '9' - 1; n = (n * base) + (c - '0'); c = getchr(); } pushc(c); return(n); } null(c, fmt, get) int c; char *fmt; long (*get)(); { printf("?\n"); return(0); } cmdcol(c, fmt, get) int c; char *fmt; long (*get)(); { printf("?\n"); return(0); } cmddol(c, fmt, get) int c; char *fmt; long (*get)(); { switch (c = nb()) { case 'm': case 'M': prtmap('?', &binary); prtmap('/', &core); break; case 'q': exit(0); case 'd': ibase = 10; break; case 'o': ibase = 8; break; case 'x': ibase = 16; break; case 's': maxoff = dot; break; default: pushc(c); putchr('?'); putchr('\n'); break; } return(0); } prtmap(c, fp) char c; struct file *fp; { printf("%c\t%s\n", c, fp->name); putx(fp->b1, 10); putx(fp->e1, 10); putx(fp->f1, 10); putchr('\n'); putx(fp->b2, 10); putx(fp->e2, 10); putx(fp->f2, 10); putchr('\n'); return; } cmdwrt(c, fmt, get) char c; char *fmt; long (*get)(); { long l; struct file *fp; if (mode != 2) { prt("not is write mode\n"); return; } fp = (c == '?') ? &binary : &core; c = nb(); l = expr(); putn(l, dot + dotoff, c == 'w' ? 2 : 4, fp); return; } cmdprt(c, fmt, get) int c; char *fmt; long (*get)(); { register int c1; long *ip; struct file *fp; struct symbol *sp, *findsym(); fp = (c == '?') ? &binary : &core; while (c = *fmt++) switch (c) { case 'a': case 'p': if ((sp = findsym((int)(dot + dotoff), binary.symptr)) || (sp = findsym((int)(dot + dotoff), core.symptr))) prtsym((int)(dot + dotoff), sp); else putx(dot + dotoff, 8); if (c == 'p') break; putchr(':'); putchr('\t'); break; case 'i': if (get == getdot) { putchr('?'); break; } puti(fp); if (*fmt) putchr('\n'); break; case 'm': case 'M': if (get == getdot) { putchr('?'); break; } ip = c == 'm' ? fp->tmap : fp->dmap; for (c1 = 0; c1 < 3; c1++) { if (peekc() == '\n') break; *ip++ = expr(); } return; case 'o': puto((*get)(dot + dotoff, 2, fp) & 0xffff, 6); break; case 'O': puto((*get)(dot + dotoff, 4, fp), 12); break; case 'd': putd((*get)(dot + dotoff, 2, fp), 6); break; case 'D': putd((*get)(dot + dotoff, 4, fp), 11); break; case 'x': putx((*get)(dot + dotoff, 2, fp) & 0xffff, 4); break; case 'X': putx((*get)(dot + dotoff, 4, fp), 8); break; case 'b': puto((*get)(dot + dotoff, 1, fp) & 0xff, 4); break; case 'c': putchr((char)(*get)(dot + dotoff, 1, fp)); break; case 'S': case 's': while (c1 = (char)(*get)(dot + dotoff, 1, fp)) { if ((c1 < ' ' || c1 > 127) && (c == 'S')) c1 = '.'; putchr(c1); } break; case '"': while ((c = *fmt++) != '"' && c) putchr(c); if (c != '"') fmt--; break; default: putchr(c); break; } putchr('\n'); return; } getfmt(fmt) char *fmt; { char c; if ((c = peekc()) == 'm' || c == 'M' || c == '*') { nb(); if (c == '*') if ((c = nb()) != 'm' && c != 'M') { pushc(c); c = '?'; } else c = 'M'; else c = 'm'; *fmt++ = c; *fmt++ = '\0'; return; } while ((*fmt = getchr()) != '\n') fmt++; *fmt = '\0'; pushc('\n'); return; } long getdot(d, n, fp) long d; int n; struct file *fp; { long l; l = dot; if (n == 2) l &= 0xffff; else if (n == 1) l &= 0xff; return(l); } unsigned char getb(fp) struct file *fp; { return(getn(dot + dotoff, 1, fp)); } unsigned int getw(fp) struct file *fp; { return(getn(dot + dotoff, 2, fp)); } putn(v, d, n, fp) long v, d; int n; struct file *fp; { long b, no; register int o; char *p; if (d >= fp->b1 && d < fp->e1) d += fp->f1 - fp->b1; else if (d >= fp->b2 && d < fp->e2) d += fp->f2 - fp->b2; b = d >> LOGBS; o = d & (BSIZE - 1); if (buffer) { if (fp->cblock != b) { fp->cblock = b; lseek(fp->fid, b << LOGBS, 0); read(fp->fid, fp->buf, sizeof(fp->buf)); } } else { lseek(fp->fid, d, 0); read(fp->fid, &fp->buf[o], n); } p = &fp->buf[o]; dotoff += n; switch (n) { case 2: putx(((long)*(int *)p) & 0xffff, 4); prt(" ="); putx(v & 0xffff, 4); putchr('\n'); *(int *)p = v; break; case 4: putx(*(long *)p, 8); prt(" ="); putx(v, 8); putchr('\n'); *(long *)p = v; break; } if (buffer) { lseek(fp->fid, b << LOGBS, 0); write(fp->fid, fp->buf, sizeof(fp->buf)); } else { lseek(fp->fid, d, 0); write(fp->fid, &fp->buf[o], n); } return; } long getn(d, n, fp) long d; int n; struct file *fp; { long b, no; register int o; char *p; if (d >= fp->b1 && d < fp->e1) d += fp->f1 - fp->b1; else if (d >= fp->b2 && d < fp->e2) d += fp->f2 - fp->b2; b = d >> LOGBS; o = d & (BSIZE - 1); if (buffer) { if (fp->cblock != b) { fp->cblock = b; lseek(fp->fid, b << LOGBS, 0); read(fp->fid, fp->buf, sizeof(fp->buf)); } } else { lseek(fp->fid, d, 0); read(fp->fid, &fp->buf[o], n); } p = &fp->buf[o]; dotoff += n; switch (n) { case 1: no = *p; break; case 2: no = *(int *)p; break; case 4: no = *(long *)p; break; } return(no); } puto(n, s) unsigned long n; int s; { if (n > 0) puto((n >> 3) & 0x1fffffff, --s); else while (s-- > 0) putchr(' '); putchr((char)((n & 7) + '0')); return; } putd(n, s) long n; int s; { if (n < 0) { s--; n = -n; if (n < 0) { while (s-- > 0) putchr(' '); putchr('?'); return; } else sign = '-'; } if (n > 9) putd(n / 10, --s); else while (s-- > 0) putchr(' '); if (sign) { putchr(sign); sign = 0; } putchr((char)((n % 10) + '0')); return; } putx(n, s) unsigned long n; int s; { if (n > 0xf) putx((n >> 4) & 0xfffffff, --s); else while (s-- > 0) putchr(' '); putchr("0123456789abcdef"[n & 0xf]); return; } prt(s) char *s; { while (*s) putchr(*s++); return; } putchr(c) char c; { *bufp++ = c; if (c == '\n' || bufp > &lbuf[70]) { write(1, lbuf, bufp - lbuf); bufp = lbuf; } return(c); } setsym(mn) char *mn; { FILE *fd; char buf[80]; if ((fd = fopen(mn, "r")) == NULL) { printf("%s:cannot open\n", mn); return; } while (fgets(buf, sizeof(buf), fd)) switch(buf[0]) { case 'T': addsym(&binary.symptr, buf); break; case 'A': case 'D': case 'B': addsym(&core.symptr, buf); break; } return; } addsym(sp, cp) struct symbol *sp; char *cp; { unsigned int v; char *cptr; struct symbol *p; v = htoi(cp + 2); while (sp->next) if (sp->next->value > v) break; else sp = sp->next; p = (struct symbol *)malloc(sizeof(*p)); p->next = sp->next; sp->next = p; p->value = v; cp += 7; cptr = p->name; while ((type(*cp) & ALPHANUM) || *cp == '.') *cptr++ = *cp++; *cptr = '\0'; return; } struct symbol * findnam(cp, sp) char *cp; struct symbol *sp; { while (sp) if (strcmp(cp, sp->name) == 0) return(sp); else sp = sp->next; return(0); } struct symbol * findsym(v, sp) unsigned int v; struct symbol *sp; { struct symbol *lp; lp = sp; while (sp) if (sp->value > v) break; else { lp = sp; sp = sp->next; } if (lp && v >= lp->value && v < lp->value + maxoff) return(lp); return(0); } htoi(cp) char *cp; { int n; char c; n = 0; while (type(c = *cp++) & HEXDIG) { if (c >= 'a' && c <= 'f') c -= 'a' - '9' - 1; else if (c >= 'A' && c <= 'F') c -= 'A' - '9' - 1; n = (n << 4) + (c - '0'); } return(n); } prtsym(v, sp) unsigned int v; struct symbol *sp; { prt(sp->name); if (v != sp->value) { putchr('+'); putx((long)(v - sp->value), 0); } return; } --- cut here for : optab.c --- #include "adb.h" int i_normal(), i_incdec(), i_ill(), i_jmp(), i_immed(); int i_mov(), i_movi(), i_movs(); int i_misc1(), i_misc2(), i_misc3(); int i_string(), i_xchg(), i_shift(), i_esc(); int i_ioi(), i_ior(), i_monad(), i_misc4(); extern long dot; extern int dotoff; extern struct file binary; extern struct file core; struct symbol *findsym(); long getn(); unsigned char getb(); unsigned int getw(); char *mon0[] = { "add", "push\tes", "pop\tes" }; char *mon1[] = { "or", "push\tcs", "???" }; char *mon2[] = { "adc", "push\tss", "pop\tss" }; char *mon3[] = { "sbb", "push\tds", "pop\tds" }; char *mon4[] = { "and", "es:", "daa" }; char *mon5[] = { "sub", "cs:", "das" }; char *mon6[] = { "xor", "ss:", "aaa" }; char *mon7[] = { "cmp", "ds:", "aas" }; char *mon8[] = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }; char *mon9[] = { "jo", "jno", "jb", "jnb", "je", "jne", "jna", "ja" }; char *mon10[] = { "js", "jns", "jp", "jnp", "jl", "jnl", "jng", "jg" }; char *mon11[] = { "cbw", "cwd", "call", "wait", "pushf", "popf", "sahf", "lahf" }; char *mon12[] = { "mov", "mov", "mov", "mov", "movs", "movs", "cmps", "cmps" }; char *mon13[] = { "test\tal", "test\tax", "stosb", "stosw", "lodsb", "lodsw", "scasb", "scasw" }; char *mon14[] = { "rol", "ror", "rcl", "rcr", "shl", "shr", "???", "sar" }; char *mon15[] = { "loopne\t", "loope\t", "loop\t", "jcxz\t", "in\tal", "in\tax", "out\tal", "out\tax" }; char *mon16[] = { "lock", "???", "repne", "rep", "hlt", "cmd" }; char *mon17[] = { "clc", "stc", "cli", "sti", "cld", "std" }; char *mon18[] = { "test", "???", "not", "neg", "mul", "imul", "div", "idiv" }; char *mon19[] = { "incw", "decw", "call", "call", "jmp", "jmpf", "push" }; char *reg8[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; char *reg16[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; char *regsg[] = { "es", "cs", "ss", "ds" }; char *regi[] = { "[bx+si]", "[bx+di]", "[bp+si]", "[bp+di]", "[si]", "[di]", "[bp]", "[bx]" }; struct optable { char **numon; int (*proc)(); } optable[] = { mon0, i_normal, /* 00000xxx */ mon1, i_normal, /* 00001xxx */ mon2, i_normal, /* 00010xxx */ mon3, i_normal, /* 00011xxx */ mon4, i_normal, /* 00100xxx */ mon5, i_normal, /* 00101xxx */ mon6, i_normal, /* 00110xxx */ mon7, i_normal, /* 00111xxx */ (char **)"inc", i_incdec, /* 01000xxx */ (char **)"dec", i_incdec, /* 01001xxx */ (char **)"push", i_incdec, /* 01010xxx */ (char **)"pop", i_incdec, /* 01011xxx */ 0, i_ill, /* 01100xxx */ 0, i_ill, /* 01101xxx */ mon9, i_jmp, /* 01110xxx */ mon10, i_jmp, /* 01111xxx */ 0, i_immed, /* 10000xxx */ 0, i_mov, /* 10001xxx */ 0, i_xchg, /* 10010xxx */ mon11, i_misc1, /* 10011xxx */ mon12, i_movs, /* 10100xxx */ mon13, i_string, /* 10101xxx */ reg8, i_movi, /* 10110xxx */ reg16, i_movi, /* 10111xxx */ 0, i_misc2, /* 11000xxx */ 0, i_misc3, /* 11001xxx */ 0, i_shift, /* 11010xxx */ 0, i_esc, /* 11011xxx */ 0, i_ioi, /* 11100xxx */ 0, i_ior, /* 11101xxx */ 0, i_monad, /* 11110xxx */ 0, i_misc4 /* 11111xxx */ }; puti(fp) struct file *fp; { int opcode; struct optable *op; opcode = (int)getb(fp) & 0xff; op = &optable[opcode >> 3]; (*(op->proc))(opcode, op->numon, fp); return; } i_ill(opc, mon, fp) int opc; char *mon[]; struct file *fp; { putchr('?'); putchr('?'); putchr('?'); return; } i_incdec(opc, mon, fp) int opc; char *mon; struct file *fp; { prt(mon); putchr('\t'); prt(reg16[opc & 7]); return; } i_normal(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod; switch (opc & 7) { case 0: case 1: case 2: case 3: mod = getb(fp); prt(mon[0]); putchr('\t'); putad(opc, mod, fp); break; case 4: prt(mon[0]); prt("\tal,"); putx((long)getb(fp) & 0xff, 0); break; case 5: prt(mon[0]); prt("\tax,"); putx((long)getw(fp), 0); break; case 6: case 7: prt(mon[(opc & 7) - 5]); break; } return; } putad(opc, mod, fp) int opc, mod; struct file *fp; { switch (opc & 3) { case 0: putea(mod, reg8, fp); putchr(','); prt(reg8[(mod >> 3) & 7]); break; case 1: putea(mod, reg16, fp); putchr(','); prt(reg16[(mod >> 3) & 7]); break; case 2: prt(reg8[(mod >> 3) & 7]); putchr(','); putea(mod, reg8, fp); break; case 3: prt(reg16[(mod >> 3) & 7]); putchr(','); putea(mod, reg16, fp); break; } return; } putea(mod, rp, fp) int mod; char *rp[]; struct file *fp; { int type, reg; long l; struct symbol *sp; type = mod & 0xc0; reg = mod & 7; if (type == 0xc0) { prt(rp[reg]); return; } if (type == 0x00 && reg == 6) { l = getw(fp); l &= 0xffff; if (sp = findsym((int)l, core.symptr)) prtsym((int)l, sp); else { putchr('['); putx(l, 0); putchr(']'); } return; } if (type == 0x40) putx((long)getb(fp) & 0xff, 0); else if (type == 0x80) putx((long)getw(fp), 0); prt(regi[reg]); return; } i_immed(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod, reg; mod = getb(fp); reg = (mod >> 3) & 7; mon = opc & 1 ? reg16 : reg8; if (opc & 4) { prt(opc & 2 ? "xchg\t" : "test\t"); putad(opc, mod, fp); return; } prt(mon8[reg]); putchr('\t'); putea(mod, mon, fp); putchr(','); if ((opc & 3) == 1) putx((long)getw(fp), 0); else putx((long)getb(fp) & 0xff, 0); return; } i_jmp(opc, mon, fp) int opc; char *mon[]; struct file *fp; { unsigned int pc; struct symbol *sp; pc = getb(fp); pc += dot + dotoff; prt(mon[opc & 7]); putchr('\t'); if (sp = findsym(pc, binary.symptr)) prtsym(pc, sp); else putx((long)(pc), 0); return; } i_mov(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod; mod = getb(fp); mon = opc & 1 ? reg16 : reg8; switch (opc & 7) { case 0: case 1: case 2: case 3: prt("mov\t"); putad(opc, mod, fp); break; case 4: if (mod & 0x20) { prt("???"); break; } prt("mov\t"); putea(mod, reg16, fp); putchr(','); prt(regsg[(mod >> 3) & 3]); break; case 5: prt("lea\t"); putad(opc, mod, fp); break; case 6: if (mod & 0x20) { prt("???"); break; } prt("mov\t"); prt(regsg[(mod >> 3) & 3]); putchr(','); putea(mod, reg16, fp); break; case 7: if (mod & 0x38) { prt("???"); break; } prt("pop\t"); putea(mod, reg16, fp); break; } return; } i_xchg(opc, mon, fp) int opc; char *mon[]; struct file *fp; { if ((opc & 7) == 0) prt("nop"); else { prt("xchg\tax,"); prt(reg16[opc & 7]); } return; } i_misc1(opc, mon, fp) int opc; char *mon[]; struct file *fp; { long pc; struct symbol *sp; prt(mon[opc & 7]); if ((opc & 7) == 2) { putchr('\t'); pc = getw(fp); putx((long)getw(fp), 0); putchr(':'); if (sp = findsym((int)pc, binary.symptr)) prtsym((int)pc, sp); else putx(pc, 0); } return; } i_misc2(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod, reg; if ((opc & 7) >= 4) { mod = getb(fp); reg = (mod >> 3) & 7; } switch (opc & 7) { case 2: prt("ret\t"); putx((long)getw(fp), 0); break; case 3: prt("ret"); break; case 4: prt("lea\t"); prt(reg16[reg]); putchr(','); putea(mod, reg16, fp); break; case 5: prt("lds\t"); prt(reg16[reg]); putchr(','); putea(mod, reg16, fp); break; case 6: prt("movb\t"); putea(mod, reg8, fp); putchr(','); putx((long)getb(fp) & 0xff, 0); break; case 7: prt("movw\t"); putea(mod, reg16, fp); putchr(','); putx((long)getw(fp), 0); break; default: prt("???"); break; } return; } i_misc3(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int sub; long l; sub = opc & 7; if (sub == 2) l = getw(fp); else if (sub == 5) l = (long)getb(fp) & 0xff; switch (sub) { case 2: prt("ret\t"); putx(l, 0); break; case 3: prt("ret"); break; case 4: prt("int\t3"); break; case 5: prt("int\t"); putx(l, 0); break; case 6: prt("into"); break; case 7: prt("iret"); break; default: prt("???"); break; } return; } i_movs(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int sub; long l; sub = opc & 7; prt(mon[sub]); putchr('\t'); if (sub < 5) l = getw(fp); switch (sub) { case 0: prt("al,"); putx(l, 0); break; case 1: prt("ax,"); putx(l, 0); break; case 2: putx(l, 0); prt(",al"); break; case 3: putx(l, 0); prt(",ax"); break; case 4: case 5: case 6: case 7: break; } return; } i_string(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int sub; sub = opc & 7; prt(mon[sub]); if (sub == 0) putx((long)getb(fp) & 0xff, 0); else putx((long)getw(fp), 0); return; } i_movi(opc, mon, fp) int opc; char *mon[]; struct file *fp; { long l; if (opc & 8) l = getw(fp); else l = getb(fp) & 0xff; prt("mov\t"); prt(mon[opc & 7]); putchr(','); putx(l, 0); return; } i_shift(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod, reg; char *count; switch (opc & 7) { case 4: mod = getb(fp); prt(mod == 0x0a ? "aam" : "???"); return; case 5: mod = getb(fp); prt(mod == 0x0a ? "aad" : "???"); return; case 6: prt("???"); return; case 7: prt("xlat"); return; } mod = getb(fp); reg = (mod >> 3) & 7; mon = opc & 1 ? reg16 : reg8; count = opc & 2 ? ",cl" : ",1"; if (reg == 6) { prt("???"); return; } prt(mon14[reg]); putchr('\t'); putea(mod, mon, fp); prt(count); return; } i_esc(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod, code; mod = getb(fp); code = ((opc & 7) << 3) | ((mod >> 3) & 7); prt("esc\t"); putx((long)code, 0); putchr(','); putea(mod, reg8, fp); return; } i_ioi(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int sub; long pc; struct symbol *sp; pc = getb(fp); sub = opc & 7; prt(mon15[sub]); putchr(','); if (sub < 4) pc += dot + dotoff; else pc &= 0xff; if (sp = findsym((int)pc, binary.symptr)) prtsym((int)pc, sp); else putx(pc, 0); return; } i_ior(opc, mon, fp) int opc; char *mon[]; struct file *fp; { long pc; struct symbol *sp; switch (opc & 7) { case 0: prt("call\t"); pc = getn(dot + dotoff, 2, fp); pc += dot + dotoff; break; case 1: prt("jmp\t"); pc = getn(dot + dotoff, 2, fp); pc += dot + dotoff; break; case 2: prt("jmp\t"); pc = getw(fp); putx((long)getw(fp), 0); putchr(':'); break; case 3: prt("jmp\t"); pc = getn(dot + dotoff, 1, fp); pc += dot + dotoff; break; case 4: case 5: case 6: case 7: prt(mon15[opc & 7]); prt(",dx"); return; } if (sp = findsym((int)pc, binary.symptr)) prtsym((int)pc, sp); else putx(pc, 0); return; } i_monad(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod, sub; sub = opc & 7; switch (sub) { case 0: case 1: case 2: case 3: case 4: case 5: prt(mon16[sub]); break; case 6: case 7: mon = sub == 7 ? reg16 : reg8; mod = getb(fp); sub = (mod >> 3) & 7; if (sub == 1) { prt("???"); break; } prt(mon18[sub]); putchr('\t'); putea(mod, mon, fp); if (sub == 0) { putchr(','); if (opc & 1) putx((long)getw(fp), 0); else putx((long)getb(fp) & 0xff, 0); } break; } return; } i_misc4(opc, mon, fp) int opc; char *mon[]; struct file *fp; { int mod, sub; sub = opc & 7; switch (sub) { case 0: case 1: case 2: case 3: case 4: case 5: prt(mon17[sub]); break; case 6: mod = getb(fp); sub = (mod >> 3) & 7; if (sub == 0) { prt("incb\t"); putea(mod, reg8, fp); } else if (sub == 1) { prt("decb\t"); putea(mod, reg8, fp); } else prt("???"); break; case 7: mod = getb(fp); sub = (mod >> 3) & 7; if (sub == 7) prt("???"); else { prt(mon19[sub]); putchr('\t'); putea(mod, reg16, fp); } break; } return; }