xref: /csrg-svn/old/dbx/tahoe.c (revision 42687)
126326Ssam /*
238105Sbostic  * Copyright (c) 1985 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42687Sbostic  * %sccs.include.redist.c%
626326Ssam  */
726326Ssam 
826326Ssam #ifndef lint
9*42687Sbostic static char sccsid[] = "@(#)tahoe.c	5.8 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
1126326Ssam 
1226326Ssam /*
1326326Ssam  * Target machine dependent stuff.
1426326Ssam  */
1526326Ssam 
1626326Ssam #include "defs.h"
1726326Ssam #include "machine.h"
1826326Ssam #include "process.h"
1926326Ssam #include "runtime.h"
2026326Ssam #include "events.h"
2126326Ssam #include "main.h"
2226326Ssam #include "symbols.h"
2326326Ssam #include "source.h"
2426326Ssam #include "mappings.h"
2526326Ssam #include "object.h"
2626326Ssam #include "keywords.h"
2726326Ssam #include "ops.h"
2833338Sdonn #include "eval.h"
2926326Ssam #include <signal.h>
3026326Ssam 
3126326Ssam #ifndef public
3226326Ssam typedef unsigned int Address;
3326326Ssam typedef unsigned char Byte;
3426326Ssam typedef unsigned int Word;
3526326Ssam 
3626326Ssam #define NREG 16
3726326Ssam 
3826326Ssam #define FRP 13
3926326Ssam #define STKP 14
4026326Ssam #define PROGCTR 15
4126326Ssam 
4233338Sdonn #define CODESTART 0
4333338Sdonn #define FUNCOFFSET 2
4433338Sdonn 
4526326Ssam #define BITSPERBYTE 8
4626326Ssam #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
4726326Ssam 
4826337Ssam /*
4933338Sdonn  * This magic macro enables us to look at the process' registers
5033338Sdonn  * in its user structure.
5126337Ssam  */
5226326Ssam 
5333338Sdonn #define regloc(reg)	(ctob(UPAGES) + (sizeof(Word) * (reg)))
5433338Sdonn 
5533338Sdonn #define nargspassed(frame) (((argn(-1, frame)&0xffff)-4)/4)
5633338Sdonn 
5726337Ssam #define	SYSBASE	0xc0000000		/* base of system address space */
5826337Ssam #define	physaddr(a)	((a) &~ 0xc0000000)
5926337Ssam 
6026326Ssam #include "source.h"
6126326Ssam #include "symbols.h"
6226337Ssam #include <sys/param.h>
6326337Ssam #include <machine/psl.h>
6426337Ssam #include <sys/user.h>
6533338Sdonn #undef DELETE /* XXX */
6626337Ssam #include <sys/vm.h>
6726337Ssam #include <machine/reg.h>
6826337Ssam #include <machine/pte.h>
6926326Ssam 
7026326Ssam Address pc;
7126326Ssam Address prtaddr;
7226326Ssam 
7326326Ssam #endif
7426326Ssam 
7526337Ssam /*
7626337Ssam  * Indices into u. for use in collecting registers values.
7726337Ssam  */
7826337Ssam public int rloc[] =
7926337Ssam     { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, FP, SP, PC };
8026337Ssam 
8126326Ssam private Address printop();
8226326Ssam 
8326326Ssam Optab	*ioptab[256];	/* index by opcode to optab */
8426326Ssam /*
8526326Ssam  * Initialize the opcode lookup table.
8626326Ssam  */
optab_init()8726326Ssam public optab_init()
8826326Ssam {
8926326Ssam 	register Optab *p;
9026326Ssam 
9126326Ssam 	for (p = optab; p->iname; p++)
9226326Ssam 		ioptab[p->val & 0xff] = p;
9326326Ssam }
9426326Ssam 
9526326Ssam /*
9626326Ssam  * Decode and print the instructions within the given address range.
9726326Ssam  */
printinst(lowaddr,highaddr)9826326Ssam public printinst(lowaddr, highaddr)
9926326Ssam 	Address lowaddr, highaddr;
10026326Ssam {
10126326Ssam 	register Address addr;
10226326Ssam 
10326326Ssam 	for (addr = lowaddr; addr <= highaddr; )
10426326Ssam 		addr = printop(addr);
10526326Ssam 	prtaddr = addr;
10626326Ssam }
10726326Ssam 
10826326Ssam /*
10926326Ssam  * Another approach:  print n instructions starting at the given address.
11026326Ssam  */
printninst(count,addr)11126326Ssam public printninst(count, addr)
11226326Ssam 	int count;
11326326Ssam 	Address addr;
11426326Ssam {
11526326Ssam 	register Integer i;
11626326Ssam 	register Address newaddr;
11726326Ssam 
11826326Ssam 	if (count <= 0)
11926326Ssam 		error("non-positive repetition count");
12026326Ssam 	for (newaddr = addr, i = 0; i < count; i++)
12126326Ssam 		newaddr = printop(newaddr);
12226326Ssam 	prtaddr = newaddr;
12326326Ssam }
12426326Ssam 
12526326Ssam /*
12626326Ssam  * Hacked version of adb's instruction decoder.
12726326Ssam  */
printop(addr)12826326Ssam private Address printop(addr)
12926326Ssam 	Address addr;
13026326Ssam {
13126326Ssam 	register Optab *op;
13226326Ssam 	Opcode ins;
13326326Ssam 	unsigned char mode;
13426326Ssam 	int argtype, amode, argno, argval, r;
13526326Ssam 	String reg;
13626326Ssam 	Boolean indexf;
13726326Ssam 	short offset;
13826326Ssam 
13926326Ssam 	argval = 0;
14026326Ssam 	indexf = false;
14126326Ssam 	printf("%08x  ", addr);
14226326Ssam 	iread(&ins, addr, sizeof(ins));
14326326Ssam 	addr += 1;
14426326Ssam 	op = ioptab[ins];
14526326Ssam 	printf("%s", op->iname);
14626326Ssam 	for (argno = 0; argno < op->numargs; argno++) {
14726326Ssam 		if (indexf == true)
14826326Ssam 			indexf = false;
14926326Ssam 		else
15026326Ssam 			printf(argno == 0 ? "\t" : ",");
15126326Ssam 		argtype = op->argtype[argno];
15226326Ssam 		if (is_branch_disp(argtype))
15326326Ssam 			mode = 0xAF + (typelen(argtype) << 5);
15426326Ssam 		else
15526326Ssam 			iread(&mode, addr, sizeof(mode)), addr += 1;
15626326Ssam 		reg = regname[regnm(mode)];
15726326Ssam 		amode = addrmode(mode);
15826326Ssam 		switch (amode) {
15926326Ssam 
16026326Ssam 		case LITSHORT: case LITUPTO31:
16126326Ssam 		case LITUPTO47: case LITUPTO63:
16226326Ssam 			if (ins == O_KCALL && mode >= 0 && mode < SYSSIZE &&
16326326Ssam 			   systab[mode])
16426326Ssam 				printf("$%s", systab[mode]);
16526326Ssam 			else
16626326Ssam 				printf("$%x", mode);
16726326Ssam 			argval = mode;
16826326Ssam 			break;
16926326Ssam 
17026326Ssam 		case INDEX:
17126326Ssam 			printf("[%s]", reg);
17226326Ssam 			indexf = true;
17326326Ssam 			argno--;
17426326Ssam 			break;
17526326Ssam 
17626326Ssam 		case REG:
17726326Ssam 			printf("%s", reg);
17826326Ssam 			break;
17926326Ssam 
18026326Ssam 		case REGDEF:
18126326Ssam 			printf("(%s)", reg);
18226326Ssam 			break;
18326326Ssam 
18426326Ssam 		case AUTODEC:
18526326Ssam 			printf("-(%s)", reg);
18626326Ssam 			break;
18726326Ssam 
18826326Ssam 		case AUTOINC:
18926326Ssam 			r = mode & 0xf;
19026326Ssam 			if (r == 0xf || r == 8 || r == 9) {
19126326Ssam 				int size = (mode&03) + 1;
19226326Ssam 
19326326Ssam 				/* immediate mode */
19426326Ssam 				printf("$");
19526326Ssam 				argval = printdisp(addr, size,
19626326Ssam 				    regname[PROGCTR], amode);
19726326Ssam 				addr += size;
19826326Ssam 			} else
19926326Ssam 				printf("(%s)+", reg);
20026326Ssam 			break;
20126326Ssam 
20226326Ssam 		case AUTOINCDEF:
20326326Ssam 			if ((mode&0xf) == 0xf) {
20426326Ssam 				printf("*$");
20526326Ssam 				argval = printdisp(addr, 4, reg, amode);
20626326Ssam 				addr += 4;
20726326Ssam 			} else
20826326Ssam 				printf("*(%s)+", reg);
20926326Ssam 			break;
21026326Ssam 
21126326Ssam 		case BYTEDISP:
21226326Ssam 			argval = printdisp(addr, 1, reg, amode);
21326326Ssam 			addr += 1;
21426326Ssam 			break;
21526326Ssam 
21626326Ssam 		case BYTEDISPDEF:
21726326Ssam 			printf("*");
21826326Ssam 			argval = printdisp(addr, 1, reg, amode);
21926326Ssam 			addr += 1;
22026326Ssam 			break;
22126326Ssam 
22226326Ssam 		case WORDDISP:
22326326Ssam 			argval = printdisp(addr, 2, reg, amode);
22426326Ssam 			addr += 2;
22526326Ssam 			break;
22626326Ssam 
22726326Ssam 		case WORDDISPDEF:
22826326Ssam 			printf("*");
22926326Ssam 			argval = printdisp(addr, 2, reg, amode);
23026326Ssam 			addr += 2;
23126326Ssam 			break;
23226326Ssam 
23326326Ssam 		case LONGDISP:
23426326Ssam 			argval = printdisp(addr, 4, reg, amode);
23526326Ssam 			addr += 4;
23626326Ssam 			break;
23726326Ssam 
23826326Ssam 		case LONGDISPDEF:
23926326Ssam 			printf("*");
24026326Ssam 			argval = printdisp(addr, 4, reg, amode);
24126326Ssam 			addr += 4;
24226326Ssam 			break;
24326326Ssam 		}
24426326Ssam 	}
24526326Ssam 	if (ins == O_CASEL)
24626326Ssam 		for (argno = 0; argno <= argval; argno++) {
24726326Ssam 			iread(&offset, addr, sizeof(offset));
24826326Ssam 			printf("\n\t\t%d", offset);
24926326Ssam 			addr += 2;
25026326Ssam 		}
25126326Ssam 	printf("\n");
25226326Ssam 	return (addr);
25326326Ssam }
25426326Ssam 
25526326Ssam /*
25626326Ssam  * Print the displacement of an instruction that uses displacement
25726326Ssam  * addressing.
25826326Ssam  */
printdisp(addr,nbytes,reg,mode)25926326Ssam private int printdisp(addr, nbytes, reg, mode)
26026326Ssam 	Address addr;
26126326Ssam 	int nbytes;
26226326Ssam 	char *reg;
26326326Ssam 	int mode;
26426326Ssam {
26526326Ssam 	char byte;
26626326Ssam 	short hword;
26726326Ssam 	int argval;
26826326Ssam 	Symbol f;
26926326Ssam 
27026326Ssam 	switch (nbytes) {
27126326Ssam 
27226326Ssam 	case 1:
27326326Ssam 		iread(&byte, addr, sizeof(byte));
27426326Ssam 		argval = byte;
27526326Ssam 		break;
27626326Ssam 
27726326Ssam 	case 2:
27826326Ssam 		iread(&hword, addr, sizeof(hword));
27926326Ssam 		argval = hword;
28026326Ssam 		break;
28126326Ssam 
28226326Ssam 	case 4:
28326326Ssam 		iread(&argval, addr, sizeof(argval));
28426326Ssam 		break;
28526326Ssam 	}
28626326Ssam 	if (reg == regname[PROGCTR] && mode >= BYTEDISP)
28726326Ssam 		argval += addr + nbytes;
28826326Ssam 	if (reg == regname[PROGCTR]) {
28926326Ssam 		f = whatblock((Address) argval + 2);
29026326Ssam 		if (codeloc(f) == argval + 2)
29126326Ssam 			printf("%s", symname(f));
29226326Ssam 		else
29326326Ssam 			printf("%x", argval);
29426326Ssam 	} else {
29526326Ssam 		if (varIsSet("$hexoffsets")) {
29626326Ssam 			if (argval < 0)
29726326Ssam 				printf("-%x(%s)", -(argval), reg);
29826326Ssam 			else
29926326Ssam 				printf("%x(%s)", argval, reg);
30026326Ssam 		} else
30126326Ssam 			printf("%d(%s)", argval, reg);
30226326Ssam 	}
30326326Ssam 	return (argval);
30426326Ssam }
30526326Ssam 
30626326Ssam /*
30726326Ssam  * Print the contents of the addresses within the given range
30826326Ssam  * according to the given format.
30926326Ssam  */
31026326Ssam typedef struct {
31126326Ssam 	String	name;
31226326Ssam 	String	printfstring;
31326326Ssam 	int	length;
31426326Ssam } Format;
31526326Ssam 
31626326Ssam private Format fmt[] = {
31726326Ssam 	{ "d", " %d", sizeof(short) },
31826326Ssam 	{ "D", " %ld", sizeof(long) },
31926326Ssam 	{ "o", " %o", sizeof(short) },
32026326Ssam 	{ "O", " %lo", sizeof(long) },
32126326Ssam 	{ "x", " %04x", sizeof(short) },
32226326Ssam 	{ "X", " %08x", sizeof(long) },
32326326Ssam 	{ "b", " \\%o", sizeof(char) },
32426326Ssam 	{ "c", " '%c'", sizeof(char) },
32526326Ssam 	{ "s", "%c", sizeof(char) },
32626326Ssam 	{ "f", " %f", sizeof(float) },
32726326Ssam 	{ "g", " %g", sizeof(double) },
32826326Ssam 	{ nil, nil, 0 }
32926326Ssam };
33026326Ssam 
findformat(s)33126326Ssam private Format *findformat(s)
33226326Ssam 	String s;
33326326Ssam {
33426326Ssam 	register Format *f;
33526326Ssam 
33626326Ssam 	for (f = &fmt[0]; f->name != nil && !streq(f->name, s); f++)
33726326Ssam 		;
33826326Ssam 	if (f->name == nil)
33926326Ssam 		error("bad print format \"%s\"", s);
34026326Ssam 	return (f);
34126326Ssam }
34226326Ssam 
printdata(lowaddr,highaddr,format)34326326Ssam public Address printdata(lowaddr, highaddr, format)
34426326Ssam 	Address lowaddr;
34526326Ssam 	Address highaddr;
34626326Ssam 	String format;
34726326Ssam {
34826326Ssam 	register int n;
34926326Ssam 	register Address addr;
35026326Ssam 	register Format *f;
35126326Ssam 	int value;
35226326Ssam 
35326326Ssam 	if (lowaddr > highaddr)
35426326Ssam 		error("first address larger than second");
35526326Ssam 	f = findformat(format);
35626326Ssam 	n = 0;
35726326Ssam 	value = 0;
35826326Ssam 	for (addr = lowaddr; addr <= highaddr; addr += f->length) {
35926326Ssam 		if (n == 0)
36026326Ssam 			printf("%08x: ", addr);
36126326Ssam 		dread(&value, addr, f->length);
36226326Ssam 		printf(f->printfstring, value);
36326326Ssam 		++n;
36426326Ssam 		if (n >= (16 div f->length)) {
36526326Ssam 			putchar('\n');
36626326Ssam 			n = 0;
36726326Ssam 		}
36826326Ssam 	}
36926326Ssam 	if (n != 0)
37026326Ssam 		putchar('\n');
37126326Ssam 	prtaddr = addr;
37226326Ssam 	return (addr);
37326326Ssam }
37426326Ssam 
37526326Ssam /*
37626326Ssam  * The other approach is to print n items starting with a given address.
37726326Ssam  */
37826326Ssam 
printndata(count,startaddr,format)37926326Ssam public printndata(count, startaddr, format)
38026326Ssam int count;
38126326Ssam Address startaddr;
38226326Ssam String format;
38326326Ssam {
38426326Ssam 	register int i, n;
38526326Ssam 	register Address addr;
38626326Ssam 	register Format *f;
38726326Ssam 	register Boolean isstring;
38826326Ssam 	char c;
38926326Ssam 	union {
39026326Ssam 		char	charv;
39126326Ssam 		short	shortv;
39226326Ssam 		int	intv;
39326326Ssam 		float	floatv;
39426326Ssam 		double	doublev;
39526326Ssam 	} value;
39626326Ssam 
39726326Ssam 	if (count <= 0)
39826326Ssam 		error("non-positive repetition count");
39926326Ssam 	f = findformat(format);
40026326Ssam 	isstring = (Boolean) streq(f->name, "s");
40126326Ssam 	n = 0;
40226326Ssam 	addr = startaddr;
40326326Ssam 	value.intv = 0;
40426326Ssam 	for (i = 0; i < count; i++) {
40526326Ssam 		if (n == 0)
40626326Ssam 			printf("%08x: ", addr);
40726326Ssam 		if (isstring) {
40826326Ssam 			putchar('"');
40926326Ssam 			dread(&c, addr, sizeof(char));
41026326Ssam 			while (c != '\0') {
41126326Ssam 				printchar(c);
41226326Ssam 				++addr;
41326326Ssam 				dread(&c, addr, sizeof(char));
41426326Ssam 			}
41526326Ssam 			putchar('"');
41626326Ssam 			putchar('\n');
41726326Ssam 			n = 0;
41826326Ssam 			addr += sizeof(String);
41926326Ssam 			continue;
42026326Ssam 		}
42126326Ssam 		dread(&value, addr, f->length);
42226326Ssam 		printf(f->printfstring, value);
42326326Ssam 		++n;
42426326Ssam 		if (n >= (16 div f->length)) {
42526326Ssam 			putchar('\n');
42626326Ssam 			n = 0;
42726326Ssam 		}
42826326Ssam 		addr += f->length;
42926326Ssam 	}
43026326Ssam 	if (n != 0)
43126326Ssam 		putchar('\n');
43226326Ssam 	prtaddr = addr;
43326326Ssam }
43426326Ssam 
43526326Ssam /*
43626326Ssam  * Print out a value according to the given format.
43726326Ssam  */
printvalue(v,format)43826326Ssam public printvalue(v, format)
43926326Ssam 	long v;
44026326Ssam 	String format;
44126326Ssam {
44226326Ssam 	Format *f;
44326326Ssam 	char *p, *q;
44426326Ssam 
44526326Ssam 	f = findformat(format);
44626326Ssam 	if (streq(f->name, "s")) {
44726326Ssam 		putchar('"');
44826326Ssam 		for (p = (char *) &v, q = p + sizeof(v); p < q; ++p)
44926326Ssam 			printchar(*p);
45026326Ssam 		putchar('"');
45126326Ssam 	} else
45226326Ssam 		printf(f->printfstring, v);
45326326Ssam 	putchar('\n');
45426326Ssam }
45526326Ssam 
45626326Ssam /*
45726326Ssam  * Print out an execution time error.
45826326Ssam  * Assumes the source position of the error has been calculated.
45926326Ssam  *
46026326Ssam  * Have to check if the -r option was specified; if so then
46126326Ssam  * the object file information hasn't been read in yet.
46226326Ssam  */
printerror()46326326Ssam public printerror()
46426326Ssam {
46526326Ssam 	extern Integer sys_nsig;
46626326Ssam 	extern String sys_siglist[];
46726326Ssam 	integer err;
46826326Ssam 
46926326Ssam 	if (isfinished(process)) {
47026326Ssam 		err = exitcode(process);
47126326Ssam 		if (err) {
47226326Ssam 			printf("\"%s\" terminated abnormally (exit code %d)\n",
47326326Ssam 			    objname, err);
47426326Ssam 			erecover();
47526326Ssam 		} else
47626326Ssam 			printf("\"%s\" terminated normally\n", objname);
47726326Ssam 	}
47826326Ssam 	if (runfirst) {
47926326Ssam 		fprintf(stderr, "Entering debugger ...\n");
48026326Ssam 		init();
48126326Ssam 	}
48226326Ssam 	err = errnum(process);
48326326Ssam 	putchar('\n');
48426326Ssam 	printsig(err);
48526326Ssam 	putchar(' ');
48626326Ssam 	printloc();
48726326Ssam 	putchar('\n');
48826326Ssam 	if (curline > 0)
48926326Ssam 		printlines(curline, curline);
49026326Ssam 	else
49126326Ssam 		printinst(pc, pc);
49226326Ssam 	erecover();
49326326Ssam }
49426326Ssam 
49526326Ssam /*
49626326Ssam  * Print out a signal.
49726326Ssam  */
49826326Ssam private String illinames[] = {
49926326Ssam 	"reserved addressing fault",
50033338Sdonn 	"privileged instruction fault",
50126326Ssam 	"reserved operand fault"
50226326Ssam };
50326326Ssam #define	NILLINAMES	(sizeof (illinames) / sizeof (illinames[0]))
50426326Ssam 
50526326Ssam private String fpenames[] = {
50626326Ssam 	nil,
50726326Ssam 	"integer overflow trap",
50826326Ssam 	"integer divide by zero trap",
50926326Ssam 	"floating point divide by zero trap",
51026326Ssam 	"floating point overflow trap",
51126326Ssam 	"floating point underflow trap",
51226326Ssam };
51326326Ssam #define	NFPENAMES	(sizeof (fpenames) / sizeof (fpenames[0]))
51426326Ssam 
printsig(signo)51526326Ssam public printsig(signo)
51626326Ssam integer signo;
51726326Ssam {
51826326Ssam 	integer code;
51926326Ssam 
52026326Ssam 	if (signo < 0 or signo > sys_nsig)
52126326Ssam 		printf("[signal %d]", signo);
52226326Ssam 	else
52326326Ssam 		printf("%s", sys_siglist[signo]);
52426326Ssam 	code = errcode(process);
52526326Ssam 	if (signo == SIGILL)
52626326Ssam 		if (code >= 0 && code < NILLINAMES)
52726326Ssam 			printf(" (%s)", illinames[code]);
52826326Ssam 	if (signo == SIGFPE)
52926326Ssam 		if (code > 0 and code < NFPENAMES)
53026326Ssam 			printf(" (%s)", fpenames[code]);
53126326Ssam }
53226326Ssam 
53326326Ssam /*
53426326Ssam  * Note the termination of the program.  We do this so as to avoid
53526326Ssam  * having the process exit, which would make the values of variables
53626326Ssam  * inaccessible.  We do want to flush all output buffers here,
53726326Ssam  * otherwise it'll never get done.
53826326Ssam  */
endprogram()53926326Ssam public endprogram()
54026326Ssam {
54126326Ssam 	Integer exitcode;
54226326Ssam 
54326326Ssam 	stepto(nextaddr(pc, true));
54426326Ssam 	printnews();
54526326Ssam 	exitcode = argn(1, nil);
54626326Ssam 	if (exitcode != 0)
54726326Ssam 		printf("\nexecution completed (exit code %d)\n", exitcode);
54826326Ssam 	else
54926326Ssam 		printf("\nexecution completed\n");
55026326Ssam 	getsrcpos();
55126326Ssam 	erecover();
55226326Ssam }
55326326Ssam 
55426326Ssam private Address getcall();
55526326Ssam /*
55626326Ssam  * Single step the machine a source line (or instruction if "inst_tracing"
55726326Ssam  * is true).  If "isnext" is true, skip over procedure calls.
55826326Ssam  */
dostep(isnext)55926326Ssam public dostep(isnext)
56026326Ssam 	Boolean isnext;
56126326Ssam {
56226326Ssam 	register Address addr;
56326326Ssam 	register Lineno line;
56426326Ssam 	String filename;
56526326Ssam 	Address startaddr;
56626326Ssam 
56726326Ssam 	startaddr = pc;
56826326Ssam 	addr = nextaddr(pc, isnext);
56926326Ssam 	if (!inst_tracing && nlhdr.nlines != 0) {
57026326Ssam 		line = linelookup(addr);
57126326Ssam 		for (; line == 0; line = linelookup(addr))
57226326Ssam 			addr = nextaddr(addr, isnext);
57326326Ssam 		curline = line;
57426326Ssam 	} else
57526326Ssam 		curline = 0;
57626326Ssam 	stepto(addr);
57726326Ssam 	filename = srcfilename(addr);
57826326Ssam 	setsource(filename);
57926326Ssam }
58026326Ssam 
58126326Ssam private Address findnextaddr();
58226326Ssam /*
58326326Ssam  * Compute the next address that will be executed from the given one.
58426326Ssam  * If "isnext" is true then consider a procedure call as straight line code.
58526326Ssam  *
58626326Ssam  * We must unfortunately do much of the same work that is necessary
58726326Ssam  * to print instructions.  In addition we have to deal with branches.
58826326Ssam  * Unconditional branches we just follow, for conditional branches
58926326Ssam  * we continue execution to the current location and then single step
59026326Ssam  * the machine.  We assume that the last argument in an instruction
59126326Ssam  * that branches is the branch address (or relative offset).
59226326Ssam  */
nextaddr(startaddr,isnext)59326326Ssam public Address nextaddr(startaddr, isnext)
59426326Ssam 	Address startaddr;
59526326Ssam 	boolean isnext;
59626326Ssam {
59726326Ssam 	Address addr;
59826326Ssam 
59926326Ssam 	addr = usignal(process);
60026326Ssam 	if (addr == 0 or addr == 1)
60126326Ssam 		addr = findnextaddr(startaddr, isnext);
60226326Ssam 	return (addr);
60326326Ssam }
60426326Ssam 
60526326Ssam /*
60626326Ssam  * Determine if it's ok to skip function f entered by instruction ins.
60726326Ssam  * If so, we're going to compute the return address and step to it.
60826326Ssam  */
skipfunc(ins,f)60926326Ssam private boolean skipfunc(ins, f)
61026326Ssam 	Opcode ins;
61126326Ssam 	Symbol f;
61226326Ssam {
61326326Ssam 
61426326Ssam 	return ((boolean) (!inst_tracing && nlhdr.nlines != 0 &&
61526326Ssam 		nosource(curfunc) && canskip(curfunc)));
61626326Ssam }
61726326Ssam 
findnextaddr(startaddr,isnext)61826326Ssam private Address findnextaddr(startaddr, isnext)
61926326Ssam 	Address startaddr;
62026326Ssam 	Boolean isnext;
62126326Ssam {
62226326Ssam 	register Address addr;
62326326Ssam 	Optab *op;
62426326Ssam 	Opcode ins;
62526326Ssam 	unsigned char mode;
62626326Ssam 	int argtype, amode, argno, argval, nib;
62726326Ssam 	String r;
62826326Ssam 	Boolean indexf;
62926326Ssam 	enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
63026326Ssam 
63126326Ssam 	argval = 0;
63226326Ssam 	indexf = false;
63326326Ssam 	addr = startaddr;
63426326Ssam 	iread(&ins, addr, sizeof(ins));
63526326Ssam 	switch (ins) {
63626326Ssam 
63726326Ssam 	case O_CALLF:
63826326Ssam 	case O_CALLS:
63926326Ssam 		addrstatus = KNOWN;
64026326Ssam 		stepto(addr);
64126326Ssam 		pstep(process, DEFSIG);
64226326Ssam 		addr = reg(PROGCTR);
64326326Ssam 		pc = addr;
64426326Ssam 		setcurfunc(whatblock(pc));
64526326Ssam 		if (not isbperr()) {
64626326Ssam 			printstatus();
64726326Ssam 			/* NOTREACHED */
64826326Ssam 		}
64926326Ssam 		bpact();
65026326Ssam 		if (isnext or skipfunc(ins, curfunc)) {
65126326Ssam 			addrstatus = KNOWN;
65226326Ssam 			addr = return_addr();
65326326Ssam 			stepto(addr);
65426326Ssam 			bpact();
65526326Ssam 		} else
65626326Ssam 			callnews(/* iscall = */ true);
65726326Ssam 		break;
65826326Ssam 
65926326Ssam 	case O_RET:
66026326Ssam 		addrstatus = KNOWN;
66126326Ssam 		stepto(addr);
66226326Ssam 		callnews(/* iscall = */ false);
66326326Ssam 		pstep(process, DEFSIG);
66426326Ssam 		addr = reg(PROGCTR);
66526326Ssam 		pc = addr;
66626326Ssam 		if (not isbperr())
66726326Ssam 			printstatus();
66826326Ssam 		bpact();
66926326Ssam 		break;
67026326Ssam 
67126326Ssam 	case O_BRB:
67226326Ssam 	case O_BRW:
67326326Ssam 	case O_JMP:
67426326Ssam 	case O_BBSSI:
67526326Ssam 	case O_BCC:
67626326Ssam 	case O_BCS:
67726326Ssam 	case O_BEQL:
67826326Ssam 	case O_BGEQ:
67926326Ssam 	case O_BGTR:
68026326Ssam 	case O_BGTRU:
68126326Ssam 	case O_BLEQ:
68226326Ssam 	case O_BLEQU:
68326326Ssam 	case O_BLSS:
68426326Ssam 	case O_BNEQ:
68526326Ssam 	case O_BVC:
68626326Ssam 	case O_BVS:
68726326Ssam 	case O_CASEL:
68826326Ssam 	case O_AOBLSS:
68926326Ssam 	case O_AOBLEQ:
69026326Ssam 		addrstatus = KNOWN;
69126326Ssam 		stepto(addr);
69226326Ssam 		pstep(process, DEFSIG);
69326326Ssam 		addr = reg(PROGCTR);
69426326Ssam 		pc = addr;
69526326Ssam 		if (not isbperr())
69626326Ssam 			printstatus();
69726326Ssam 		break;
69826326Ssam 
69926326Ssam 	default:
70026326Ssam 		addrstatus = SEQUENTIAL;
70126326Ssam 		break;
70226326Ssam 	}
70326326Ssam 	if (addrstatus == KNOWN)
70426326Ssam 		return (addr);
70526326Ssam 	addr += 1;
70626326Ssam 	op = ioptab[ins];
70726326Ssam 	for (argno = 0; argno < op->numargs; argno++) {
70826326Ssam 		if (indexf == true)
70926326Ssam 			indexf = false;
71026326Ssam 		argtype = op->argtype[argno];
71126326Ssam 		if (is_branch_disp(argtype))
71226326Ssam 			mode = 0xAF + (typelen(argtype) << 5);
71326326Ssam 		else
71426326Ssam 			iread(&mode, addr, sizeof(mode)), addr += 1;
71526326Ssam 		r = regname[regnm(mode)];
71626326Ssam 		amode = addrmode(mode);
71726326Ssam 		switch (amode) {
71826326Ssam 
71926326Ssam 		case LITSHORT:
72026326Ssam 		case LITUPTO31:
72126326Ssam 		case LITUPTO47:
72226326Ssam 		case LITUPTO63:
72326326Ssam 			argval = mode;
72426326Ssam 			break;
72526326Ssam 
72626326Ssam 		case INDEX:
72726326Ssam 			indexf = true;
72826326Ssam 			--argno;
72926326Ssam 			break;
73026326Ssam 
73126326Ssam 		case REG:
73226326Ssam 		case REGDEF:
73326326Ssam 		case AUTODEC:
73426326Ssam 			break;
73526326Ssam 
73626326Ssam 		case AUTOINC:
73726326Ssam 			nib = mode & 0xf;
73826326Ssam 			if (nib == 0xf || nib == 8 || nib == 9) {
73926326Ssam 				int size = (mode&03)+1;
74026326Ssam 
74126326Ssam 				argval = getdisp(addr, size,
74226326Ssam 				    regname[PROGCTR], amode);
74326326Ssam 				addr += size;
74426326Ssam 			}
74526326Ssam 			break;
74626326Ssam 
74726326Ssam 		case AUTOINCDEF:
74826326Ssam 			if ((mode&0xf) != 0xf)
74926326Ssam 				break;
75026326Ssam 			argval = getdisp(addr, 4, r, amode);
75126326Ssam 			addr += 4;
75226326Ssam 			break;
75326326Ssam 
75426326Ssam 		case BYTEDISP:
75526326Ssam 		case BYTEDISPDEF:
75626326Ssam 			argval = getdisp(addr, 1, r, amode);
75726326Ssam 			addr += 1;
75826326Ssam 			break;
75926326Ssam 
76026326Ssam 		case WORDDISP:
76126326Ssam 		case WORDDISPDEF:
76226326Ssam 			argval = getdisp(addr, 2, r, amode);
76326326Ssam 			addr += 2;
76426326Ssam 			break;
76526326Ssam 
76626326Ssam 		case LONGDISP:
76726326Ssam 		case LONGDISPDEF:
76826326Ssam 			argval = getdisp(addr, 4, r, amode);
76926326Ssam 			addr += 4;
77026326Ssam 			break;
77126326Ssam 		}
77226326Ssam 	}
77326326Ssam 	if (ins == O_CALLF or ins == O_CALLS)
77426326Ssam 		argval += 2;
77526326Ssam 	if (addrstatus == BRANCH)
77626326Ssam 		addr = argval;
77726326Ssam 	return (addr);
77826326Ssam }
77926326Ssam 
78026326Ssam /*
78126326Ssam  * Get the displacement of an instruction that uses displacement addressing.
78226326Ssam  */
getdisp(addr,nbytes,reg,mode)78326326Ssam private int getdisp(addr, nbytes, reg, mode)
78426326Ssam 	Address addr;
78526326Ssam 	int nbytes;
78626326Ssam 	String reg;
78726326Ssam 	int mode;
78826326Ssam {
78926326Ssam 	char byte;
79026326Ssam 	short hword;
79126326Ssam 	int argval;
79226326Ssam 
79326326Ssam 	switch (nbytes) {
79426326Ssam 
79526326Ssam 	case 1:
79626326Ssam 		iread(&byte, addr, sizeof(byte));
79726326Ssam 		argval = byte;
79826326Ssam 		break;
79926326Ssam 
80026326Ssam 	case 2:
80126326Ssam 		iread(&hword, addr, sizeof(hword));
80226326Ssam 		argval = hword;
80326326Ssam 		break;
80426326Ssam 
80526326Ssam 	case 4:
80626326Ssam 		iread(&argval, addr, sizeof(argval));
80726326Ssam 		break;
80826326Ssam 	}
80926326Ssam 	if (reg == regname[PROGCTR] && mode >= BYTEDISP)
81026326Ssam 		argval += addr + nbytes;
81126326Ssam 	return (argval);
81226326Ssam }
81326326Ssam 
81426326Ssam #define BP_OP	   	O_BPT	   /* breakpoint trap */
81526326Ssam #define BP_ERRNO	SIGTRAP	 /* signal received at a breakpoint */
81626326Ssam 
81726326Ssam /*
81826326Ssam  * Setting a breakpoint at a location consists of saving
81926326Ssam  * the word at the location and poking a BP_OP there.
82026326Ssam  *
82126326Ssam  * We save the locations and words on a list for use in unsetting.
82226326Ssam  */
82326326Ssam typedef struct Savelist *Savelist;
82426326Ssam 
82526326Ssam struct Savelist {
82626326Ssam 	Address location;
82726326Ssam 	Byte save;
82826326Ssam 	Byte refcount;
82926326Ssam 	Savelist link;
83026326Ssam };
83126326Ssam 
83226326Ssam private Savelist savelist;
83326326Ssam 
83426326Ssam /*
83526326Ssam  * Set a breakpoint at the given address.  Only save the word there
83626326Ssam  * if it's not already a breakpoint.
83726326Ssam  */
setbp(addr)83826326Ssam public setbp(addr)
83926326Ssam 	Address addr;
84026326Ssam {
84126326Ssam 	Byte w, save;
84226326Ssam 	register Savelist newsave, s;
84326326Ssam 
84426326Ssam 	for (s = savelist; s != nil; s = s->link)
84526326Ssam 		if (s->location == addr) {
84626326Ssam 			s->refcount++;
84726326Ssam 			return;
84826326Ssam 		}
84926326Ssam 	iread(&save, addr, sizeof(save));
85026326Ssam 	newsave = new(Savelist);
85126326Ssam 	newsave->location = addr;
85226326Ssam 	newsave->save = save;
85326326Ssam 	newsave->refcount = 1;
85426326Ssam 	newsave->link = savelist;
85526326Ssam 	savelist = newsave;
85626326Ssam 	w = BP_OP;
85726326Ssam 	iwrite(&w, addr, sizeof(w));
85826326Ssam }
85926326Ssam 
86026326Ssam /*
86126326Ssam  * Unset a breakpoint; unfortunately we have to search the SAVELIST
86226326Ssam  * to find the saved value.  The assumption is that the SAVELIST will
86326326Ssam  * usually be quite small.
86426326Ssam  */
unsetbp(addr)86526326Ssam public unsetbp(addr)
86626326Ssam Address addr;
86726326Ssam {
86826326Ssam 	register Savelist s, prev;
86926326Ssam 
87026326Ssam 	prev = nil;
87126326Ssam 	for (s = savelist; s != nil; s = s->link) {
87226326Ssam 		if (s->location == addr) {
87326326Ssam 			iwrite(&s->save, addr, sizeof(s->save));
87426326Ssam 			s->refcount--;
87526326Ssam 			if (s->refcount == 0) {
87626326Ssam 				if (prev == nil)
87726326Ssam 					savelist = s->link;
87826326Ssam 				else
87926326Ssam 					prev->link = s->link;
88026326Ssam 				dispose(s);
88126326Ssam 			}
88226326Ssam 			return;
88326326Ssam 		}
88426326Ssam 		prev = s;
88526326Ssam 	}
88626326Ssam 	panic("unsetbp: couldn't find address %d", addr);
88726326Ssam }
88826326Ssam 
88926326Ssam /*
89026326Ssam  * Enter a procedure by creating and executing a call instruction.
89126326Ssam  */
89226326Ssam 
89326326Ssam #define CALLSIZE 7	/* size of call instruction */
89426326Ssam 
beginproc(p,argc)89526326Ssam public beginproc(p, argc)
89626326Ssam 	Symbol p;
89726326Ssam 	Integer argc;
89826326Ssam {
89926326Ssam 	char save[CALLSIZE];
90026326Ssam 	struct {
90126326Ssam 		Opcode op;
90226326Ssam 		unsigned char numargs;
90326326Ssam 		unsigned char mode;
90426326Ssam 		char addr[sizeof(long)];	/* unaligned long */
90526326Ssam 	} call;
90626326Ssam 	long dest;
90726326Ssam 
90826326Ssam 	if (4*argc+4 > 256)
90926326Ssam 		error("too many parameters (max %d)", 256/4 - 1);
91026326Ssam 	pc = 2;
91126326Ssam 	iread(save, pc, sizeof(save));
91226326Ssam 	call.op = O_CALLF;
91326326Ssam 	call.numargs = 4*argc+4;
91426326Ssam 	call.mode = 0xef;			/* longword relative */
91526326Ssam 	dest = codeloc(p) - 2 - (pc + CALLSIZE);
91626326Ssam 	mov(&dest, call.addr, sizeof(call.addr));
91726326Ssam 	iwrite(&call, pc, sizeof(call));
91826326Ssam 	setreg(PROGCTR, pc);
91926326Ssam 	pstep(process, DEFSIG);
92026326Ssam 	iwrite(save, pc, sizeof(save));
92126326Ssam 	pc = reg(PROGCTR);
92226326Ssam 	if (not isbperr())
92326326Ssam 		printstatus();
92426326Ssam }
92526337Ssam 
92626337Ssam /*
92726337Ssam  * Special variables for debugging the kernel.
92826337Ssam  */
92926337Ssam 
93026337Ssam public integer masterpcbb;
93126337Ssam public integer slr;
93226337Ssam public struct pte *sbr;
93333338Sdonn private struct pcb pcb;
93426337Ssam 
getpcb()93526337Ssam public getpcb ()
93626337Ssam {
93726337Ssam     fseek(corefile, masterpcbb & ~0xc0000000, 0);
93826337Ssam     get(corefile, pcb);
93926337Ssam     printf("p0br %lx p0lr %lx p2br %lx p2lr %lx\n",
94026337Ssam 	pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p2br, pcb.pcb_p2lr
94126337Ssam     );
94226337Ssam     setreg(0, pcb.pcb_r0);
94326337Ssam     setreg(1, pcb.pcb_r1);
94426337Ssam     setreg(2, pcb.pcb_r2);
94526337Ssam     setreg(3, pcb.pcb_r3);
94626337Ssam     setreg(4, pcb.pcb_r4);
94726337Ssam     setreg(5, pcb.pcb_r5);
94826337Ssam     setreg(6, pcb.pcb_r6);
94926337Ssam     setreg(7, pcb.pcb_r7);
95026337Ssam     setreg(8, pcb.pcb_r8);
95126337Ssam     setreg(9, pcb.pcb_r9);
95226337Ssam     setreg(10, pcb.pcb_r10);
95326337Ssam     setreg(11, pcb.pcb_r11);
95426337Ssam     setreg(12, pcb.pcb_r12);
95526337Ssam     setreg(FRP, pcb.pcb_fp);
95626337Ssam     setreg(STKP, pcb.pcb_ksp);
95726337Ssam     setreg(PROGCTR, pcb.pcb_pc);
95826337Ssam }
95926337Ssam 
copyregs(savreg,reg)96026337Ssam public copyregs (savreg, reg)
96126337Ssam Word savreg[], reg[];
96226337Ssam {
96326337Ssam     reg[0] = savreg[R0];
96426337Ssam     reg[1] = savreg[R1];
96526337Ssam     reg[2] = savreg[R2];
96626337Ssam     reg[3] = savreg[R3];
96726337Ssam     reg[4] = savreg[R4];
96826337Ssam     reg[5] = savreg[R5];
96926337Ssam     reg[6] = savreg[R6];
97026337Ssam     reg[7] = savreg[R7];
97126337Ssam     reg[8] = savreg[R8];
97226337Ssam     reg[9] = savreg[R9];
97326337Ssam     reg[10] = savreg[R10];
97426337Ssam     reg[11] = savreg[R11];
97526337Ssam     reg[12] = savreg[R12];
97626337Ssam     reg[FRP] = savreg[FP];
97726337Ssam     reg[STKP] = savreg[SP];
97826337Ssam     reg[PROGCTR] = savreg[PC];
97926337Ssam }
98026337Ssam 
98126337Ssam /*
98226337Ssam  * Map a virtual address to a physical address.
98326337Ssam  */
98426337Ssam 
vmap(addr)98526337Ssam public Address vmap (addr)
98626337Ssam Address addr;
98726337Ssam {
98826337Ssam 	int oldaddr = addr, v;
98926337Ssam 	struct pte pte;
99026337Ssam 
99126337Ssam 	addr &= ~0xc0000000;
99226337Ssam 	v = btop(addr);
99326337Ssam 	switch (oldaddr&0xc0000000) {
99426337Ssam 
99526337Ssam 	case 0xc0000000:
99626337Ssam 		/*
99726337Ssam 		 * In system space get system pte.  If
99826337Ssam 		 * valid or reclaimable then physical address
99926337Ssam 		 * is combination of its page number and the page
100026337Ssam 		 * offset of the original address.
100126337Ssam 		 */
100226337Ssam 		if (v >= slr)
100326337Ssam 			goto oor;
100426337Ssam 		addr = ((long)(sbr+v)) &~ 0xc0000000;
100526337Ssam 		goto simple;
100626337Ssam 
100726337Ssam 	case 0x80000000:
100826337Ssam 		/*
100926337Ssam 		 * In p2 spce must not be in shadow region.
101026337Ssam 		 */
101126337Ssam 		if (v < pcb.pcb_p2lr)
101226337Ssam 			goto oor;
101326337Ssam 		addr = (long)(pcb.pcb_p2br+v);
101426337Ssam 		break;
101526337Ssam 
101626337Ssam 	case 0x40000000:
101726337Ssam 		/*
101826337Ssam 		 * In p1 space everything is verboten (for now).
101926337Ssam 		 */
102026337Ssam 		goto oor;
102126337Ssam 
102226337Ssam 	case 0x00000000:
102326337Ssam 		/*
102426337Ssam 		 * In p0 space must not be off end of region.
102526337Ssam 		 */
102626337Ssam 		if (v >= pcb.pcb_p0lr)
102726337Ssam 			goto oor;
102826337Ssam 		addr = (long)(pcb.pcb_p0br+v);
102926337Ssam 		break;
103026337Ssam 	oor:
103126337Ssam 		error("address out of segment");
103226337Ssam 	}
103326337Ssam 	/*
103426337Ssam 	 * For p0/p1/p2 address, user-level page table should
103526337Ssam 	 * be in kernel vm.  Do second-level indirect by recursing.
103626337Ssam 	 */
103726337Ssam 	if ((addr & 0xc0000000) != 0xc0000000)
103826337Ssam 		error("bad p0br, p1br, or p2br in pcb");
103926337Ssam 	addr = vmap(addr);
104026337Ssam simple:
104126337Ssam 	/*
104226337Ssam 	 * Addr is now address of the pte of the page we
104326337Ssam 	 * are interested in; get the pte and paste up the
104426337Ssam 	 * physical address.
104526337Ssam 	 */
104626337Ssam 	fseek(corefile, addr, 0);
104726337Ssam 	if (fread(&pte, sizeof (pte), 1, corefile) != 1)
104826337Ssam 		error("page table botch");
104926337Ssam 	/* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */
105026337Ssam 	if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0))
105126337Ssam 		error("page not valid/reclaimable");
105226337Ssam 	return ((long)(ptob(pte.pg_pfnum) + (oldaddr & PGOFSET)));
105326337Ssam }
105433338Sdonn 
105533338Sdonn /*
105633338Sdonn  * Extract a bit field from an integer.
105733338Sdonn  */
105833338Sdonn 
extractField(s)105933338Sdonn public integer extractField (s)
106033338Sdonn Symbol s;
106133338Sdonn {
106233338Sdonn     integer nbytes, nbits, n, r, off, len;
106333338Sdonn 
106433338Sdonn     off = s->symvalue.field.offset;
106533338Sdonn     len = s->symvalue.field.length;
106633338Sdonn     nbytes = size(s);
106733338Sdonn     n = 0;
106833338Sdonn     if (nbytes > sizeof(n)) {
106933338Sdonn 	printf("[bad size in extractField -- word assumed]\n");
107033338Sdonn 	nbytes = sizeof(n);
107133338Sdonn     }
107233338Sdonn     popn(nbytes, ((char *) &n) + (sizeof(Word) - nbytes));
107333338Sdonn     nbits = nbytes * BITSPERBYTE;
107433338Sdonn     r = n >> (nbits - ((off mod nbits) + len));
107533338Sdonn     r &= ((1 << len) - 1);
107633338Sdonn     return r;
107733338Sdonn }
107833338Sdonn 
107933338Sdonn /*
108033338Sdonn  * Change the length of a value in memory according to a given difference
108133338Sdonn  * in the lengths of its new and old types.
108233338Sdonn  */
108333338Sdonn 
loophole(oldlen,newlen)108433338Sdonn public loophole (oldlen, newlen)
108533338Sdonn integer oldlen, newlen;
108633338Sdonn {
108733338Sdonn     integer i, n;
108833338Sdonn     Stack *oldsp;
108933338Sdonn 
109033338Sdonn     n = newlen - oldlen;
109133338Sdonn     oldsp = sp - oldlen;
109233338Sdonn     if (n > 0) {
109333338Sdonn 	for (i = oldlen - 1; i >= 0; i--) {
109433338Sdonn 	    oldsp[n + i] = oldsp[i];
109533338Sdonn 	}
109633338Sdonn 	for (i = 0; i < n; i++) {
109733338Sdonn 	    oldsp[i] = '\0';
109833338Sdonn 	}
109933338Sdonn     } else {
110033338Sdonn 	for (i = 0; i < newlen; i++) {
110133338Sdonn 	    oldsp[i] = oldsp[i - n];
110233338Sdonn 	}
110333338Sdonn     }
110433338Sdonn     sp += n;
110533338Sdonn }
1106