[comp.os.minix] adb for MINIX

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;
}