xref: /csrg-svn/old/dbx/tahoe.c (revision 26337)
126326Ssam /*
226326Ssam  * Copyright (c) 1985 Regents of the University of California.
326326Ssam  * All rights reserved.  The Berkeley software License Agreement
426326Ssam  * specifies the terms and conditions for redistribution.
526326Ssam  */
626326Ssam 
726326Ssam #ifndef lint
8*26337Ssam static char sccsid[] = "@(#)tahoe.c	5.2 (Berkeley) 02/23/86";
926326Ssam #endif not lint
1026326Ssam 
1126326Ssam /*
1226326Ssam  * Target machine dependent stuff.
1326326Ssam  */
1426326Ssam 
1526326Ssam #include "defs.h"
1626326Ssam #include "machine.h"
1726326Ssam #include "process.h"
1826326Ssam #include "runtime.h"
1926326Ssam #include "events.h"
2026326Ssam #include "main.h"
2126326Ssam #include "symbols.h"
2226326Ssam #include "source.h"
2326326Ssam #include "mappings.h"
2426326Ssam #include "object.h"
2526326Ssam #include "keywords.h"
2626326Ssam #include "ops.h"
2726326Ssam #include <signal.h>
2826326Ssam 
2926326Ssam #ifndef public
3026326Ssam typedef unsigned int Address;
3126326Ssam typedef unsigned char Byte;
3226326Ssam typedef unsigned int Word;
3326326Ssam 
3426326Ssam #define NREG 16
3526326Ssam 
3626326Ssam #define FRP 13
3726326Ssam #define STKP 14
3826326Ssam #define PROGCTR 15
3926326Ssam 
4026326Ssam #define BITSPERBYTE 8
4126326Ssam #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
4226326Ssam 
4326326Ssam #define nargspassed(frame) ((frame->removed-4)/4)
44*26337Ssam /*
45*26337Ssam  * Extract a field's value from the integer i.  The value
46*26337Ssam  * is placed in i in such as way as the first bit of the
47*26337Ssam  * field is contained in the first byte of the integer.
48*26337Ssam  */
49*26337Ssam #define	extractfield(i, s) \
50*26337Ssam 	((i >> BITSPERWORD - ((s)->symvalue.field.offset mod BITSPERBYTE + \
51*26337Ssam 		(s)->symvalue.field.length)) & \
52*26337Ssam 	 ((1 << (s)->symvalue.field.length) - 1))
53*26337Ssam /*
54*26337Ssam  * Rearrange the stack so that the top of stack has
55*26337Ssam  * something corresponding to newsize, whereas before it had
56*26337Ssam  * something corresponding to oldsize.  If we are expanding
57*26337Ssam  * then the stack is padded at the front of the data with nulls.
58*26337Ssam  * If we are contracting, the appropriate amount is shaved off the
59*26337Ssam  * front by copying up the stack.
60*26337Ssam  */
61*26337Ssam #define	typerename(oldsize, newsize) { \
62*26337Ssam 	int osize = oldsize; \
63*26337Ssam 	Stack *osp; \
64*26337Ssam \
65*26337Ssam 	len = newsize - osize; \
66*26337Ssam 	osp = sp - osize; \
67*26337Ssam 	if (len > 0) { \
68*26337Ssam 		mov(osp, osp+len, osize);	/* copy old up and pad */ \
69*26337Ssam 		bzero(osp, len); \
70*26337Ssam 	} else if (len < 0) \
71*26337Ssam 		mov(osp-len, osp, osize+len);	/* copy new size down */ \
72*26337Ssam 	sp += len; \
73*26337Ssam }
7426326Ssam 
75*26337Ssam #define	SYSBASE	0xc0000000		/* base of system address space */
76*26337Ssam #define	physaddr(a)	((a) &~ 0xc0000000)
77*26337Ssam 
7826326Ssam #include "source.h"
7926326Ssam #include "symbols.h"
80*26337Ssam #include <sys/param.h>
81*26337Ssam #include <sys/dir.h>
82*26337Ssam #include <machine/psl.h>
83*26337Ssam #include <sys/user.h>
84*26337Ssam #include <sys/vm.h>
85*26337Ssam #include <machine/reg.h>
86*26337Ssam #include <machine/pte.h>
8726326Ssam 
8826326Ssam Address pc;
8926326Ssam Address prtaddr;
9026326Ssam 
9126326Ssam #endif
9226326Ssam 
93*26337Ssam /*
94*26337Ssam  * Indices into u. for use in collecting registers values.
95*26337Ssam  */
96*26337Ssam public int rloc[] =
97*26337Ssam     { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, FP, SP, PC };
98*26337Ssam 
9926326Ssam private Address printop();
10026326Ssam 
10126326Ssam Optab	*ioptab[256];	/* index by opcode to optab */
10226326Ssam /*
10326326Ssam  * Initialize the opcode lookup table.
10426326Ssam  */
10526326Ssam public optab_init()
10626326Ssam {
10726326Ssam 	register Optab *p;
10826326Ssam 
10926326Ssam 	for (p = optab; p->iname; p++)
11026326Ssam 		ioptab[p->val & 0xff] = p;
11126326Ssam }
11226326Ssam 
11326326Ssam /*
11426326Ssam  * Decode and print the instructions within the given address range.
11526326Ssam  */
11626326Ssam public printinst(lowaddr, highaddr)
11726326Ssam 	Address lowaddr, highaddr;
11826326Ssam {
11926326Ssam 	register Address addr;
12026326Ssam 
12126326Ssam 	for (addr = lowaddr; addr <= highaddr; )
12226326Ssam 		addr = printop(addr);
12326326Ssam 	prtaddr = addr;
12426326Ssam }
12526326Ssam 
12626326Ssam /*
12726326Ssam  * Another approach:  print n instructions starting at the given address.
12826326Ssam  */
12926326Ssam public printninst(count, addr)
13026326Ssam 	int count;
13126326Ssam 	Address addr;
13226326Ssam {
13326326Ssam 	register Integer i;
13426326Ssam 	register Address newaddr;
13526326Ssam 
13626326Ssam 	if (count <= 0)
13726326Ssam 		error("non-positive repetition count");
13826326Ssam 	for (newaddr = addr, i = 0; i < count; i++)
13926326Ssam 		newaddr = printop(newaddr);
14026326Ssam 	prtaddr = newaddr;
14126326Ssam }
14226326Ssam 
14326326Ssam /*
14426326Ssam  * Hacked version of adb's instruction decoder.
14526326Ssam  */
14626326Ssam private Address printop(addr)
14726326Ssam 	Address addr;
14826326Ssam {
14926326Ssam 	register Optab *op;
15026326Ssam 	Opcode ins;
15126326Ssam 	unsigned char mode;
15226326Ssam 	int argtype, amode, argno, argval, r;
15326326Ssam 	String reg;
15426326Ssam 	Boolean indexf;
15526326Ssam 	short offset;
15626326Ssam 
15726326Ssam 	argval = 0;
15826326Ssam 	indexf = false;
15926326Ssam 	printf("%08x  ", addr);
16026326Ssam 	iread(&ins, addr, sizeof(ins));
16126326Ssam 	addr += 1;
16226326Ssam 	op = ioptab[ins];
16326326Ssam 	printf("%s", op->iname);
16426326Ssam 	for (argno = 0; argno < op->numargs; argno++) {
16526326Ssam 		if (indexf == true)
16626326Ssam 			indexf = false;
16726326Ssam 		else
16826326Ssam 			printf(argno == 0 ? "\t" : ",");
16926326Ssam 		argtype = op->argtype[argno];
17026326Ssam 		if (is_branch_disp(argtype))
17126326Ssam 			mode = 0xAF + (typelen(argtype) << 5);
17226326Ssam 		else
17326326Ssam 			iread(&mode, addr, sizeof(mode)), addr += 1;
17426326Ssam 		reg = regname[regnm(mode)];
17526326Ssam 		amode = addrmode(mode);
17626326Ssam 		switch (amode) {
17726326Ssam 
17826326Ssam 		case LITSHORT: case LITUPTO31:
17926326Ssam 		case LITUPTO47: case LITUPTO63:
18026326Ssam 			if (ins == O_KCALL && mode >= 0 && mode < SYSSIZE &&
18126326Ssam 			   systab[mode])
18226326Ssam 				printf("$%s", systab[mode]);
18326326Ssam 			else
18426326Ssam 				printf("$%x", mode);
18526326Ssam 			argval = mode;
18626326Ssam 			break;
18726326Ssam 
18826326Ssam 		case INDEX:
18926326Ssam 			printf("[%s]", reg);
19026326Ssam 			indexf = true;
19126326Ssam 			argno--;
19226326Ssam 			break;
19326326Ssam 
19426326Ssam 		case REG:
19526326Ssam 			printf("%s", reg);
19626326Ssam 			break;
19726326Ssam 
19826326Ssam 		case REGDEF:
19926326Ssam 			printf("(%s)", reg);
20026326Ssam 			break;
20126326Ssam 
20226326Ssam 		case AUTODEC:
20326326Ssam 			printf("-(%s)", reg);
20426326Ssam 			break;
20526326Ssam 
20626326Ssam 		case AUTOINC:
20726326Ssam 			r = mode & 0xf;
20826326Ssam 			if (r == 0xf || r == 8 || r == 9) {
20926326Ssam 				int size = (mode&03) + 1;
21026326Ssam 
21126326Ssam 				/* immediate mode */
21226326Ssam 				printf("$");
21326326Ssam 				argval = printdisp(addr, size,
21426326Ssam 				    regname[PROGCTR], amode);
21526326Ssam 				addr += size;
21626326Ssam 			} else
21726326Ssam 				printf("(%s)+", reg);
21826326Ssam 			break;
21926326Ssam 
22026326Ssam 		case AUTOINCDEF:
22126326Ssam 			if ((mode&0xf) == 0xf) {
22226326Ssam 				printf("*$");
22326326Ssam 				argval = printdisp(addr, 4, reg, amode);
22426326Ssam 				addr += 4;
22526326Ssam 			} else
22626326Ssam 				printf("*(%s)+", reg);
22726326Ssam 			break;
22826326Ssam 
22926326Ssam 		case BYTEDISP:
23026326Ssam 			argval = printdisp(addr, 1, reg, amode);
23126326Ssam 			addr += 1;
23226326Ssam 			break;
23326326Ssam 
23426326Ssam 		case BYTEDISPDEF:
23526326Ssam 			printf("*");
23626326Ssam 			argval = printdisp(addr, 1, reg, amode);
23726326Ssam 			addr += 1;
23826326Ssam 			break;
23926326Ssam 
24026326Ssam 		case WORDDISP:
24126326Ssam 			argval = printdisp(addr, 2, reg, amode);
24226326Ssam 			addr += 2;
24326326Ssam 			break;
24426326Ssam 
24526326Ssam 		case WORDDISPDEF:
24626326Ssam 			printf("*");
24726326Ssam 			argval = printdisp(addr, 2, reg, amode);
24826326Ssam 			addr += 2;
24926326Ssam 			break;
25026326Ssam 
25126326Ssam 		case LONGDISP:
25226326Ssam 			argval = printdisp(addr, 4, reg, amode);
25326326Ssam 			addr += 4;
25426326Ssam 			break;
25526326Ssam 
25626326Ssam 		case LONGDISPDEF:
25726326Ssam 			printf("*");
25826326Ssam 			argval = printdisp(addr, 4, reg, amode);
25926326Ssam 			addr += 4;
26026326Ssam 			break;
26126326Ssam 		}
26226326Ssam 	}
26326326Ssam 	if (ins == O_CASEL)
26426326Ssam 		for (argno = 0; argno <= argval; argno++) {
26526326Ssam 			iread(&offset, addr, sizeof(offset));
26626326Ssam 			printf("\n\t\t%d", offset);
26726326Ssam 			addr += 2;
26826326Ssam 		}
26926326Ssam 	printf("\n");
27026326Ssam 	return (addr);
27126326Ssam }
27226326Ssam 
27326326Ssam /*
27426326Ssam  * Print the displacement of an instruction that uses displacement
27526326Ssam  * addressing.
27626326Ssam  */
27726326Ssam private int printdisp(addr, nbytes, reg, mode)
27826326Ssam 	Address addr;
27926326Ssam 	int nbytes;
28026326Ssam 	char *reg;
28126326Ssam 	int mode;
28226326Ssam {
28326326Ssam 	char byte;
28426326Ssam 	short hword;
28526326Ssam 	int argval;
28626326Ssam 	Symbol f;
28726326Ssam 
28826326Ssam 	switch (nbytes) {
28926326Ssam 
29026326Ssam 	case 1:
29126326Ssam 		iread(&byte, addr, sizeof(byte));
29226326Ssam 		argval = byte;
29326326Ssam 		break;
29426326Ssam 
29526326Ssam 	case 2:
29626326Ssam 		iread(&hword, addr, sizeof(hword));
29726326Ssam 		argval = hword;
29826326Ssam 		break;
29926326Ssam 
30026326Ssam 	case 4:
30126326Ssam 		iread(&argval, addr, sizeof(argval));
30226326Ssam 		break;
30326326Ssam 	}
30426326Ssam 	if (reg == regname[PROGCTR] && mode >= BYTEDISP)
30526326Ssam 		argval += addr + nbytes;
30626326Ssam 	if (reg == regname[PROGCTR]) {
30726326Ssam 		f = whatblock((Address) argval + 2);
30826326Ssam 		if (codeloc(f) == argval + 2)
30926326Ssam 			printf("%s", symname(f));
31026326Ssam 		else
31126326Ssam 			printf("%x", argval);
31226326Ssam 	} else {
31326326Ssam 		if (varIsSet("$hexoffsets")) {
31426326Ssam 			if (argval < 0)
31526326Ssam 				printf("-%x(%s)", -(argval), reg);
31626326Ssam 			else
31726326Ssam 				printf("%x(%s)", argval, reg);
31826326Ssam 		} else
31926326Ssam 			printf("%d(%s)", argval, reg);
32026326Ssam 	}
32126326Ssam 	return (argval);
32226326Ssam }
32326326Ssam 
32426326Ssam /*
32526326Ssam  * Print the contents of the addresses within the given range
32626326Ssam  * according to the given format.
32726326Ssam  */
32826326Ssam typedef struct {
32926326Ssam 	String	name;
33026326Ssam 	String	printfstring;
33126326Ssam 	int	length;
33226326Ssam } Format;
33326326Ssam 
33426326Ssam private Format fmt[] = {
33526326Ssam 	{ "d", " %d", sizeof(short) },
33626326Ssam 	{ "D", " %ld", sizeof(long) },
33726326Ssam 	{ "o", " %o", sizeof(short) },
33826326Ssam 	{ "O", " %lo", sizeof(long) },
33926326Ssam 	{ "x", " %04x", sizeof(short) },
34026326Ssam 	{ "X", " %08x", sizeof(long) },
34126326Ssam 	{ "b", " \\%o", sizeof(char) },
34226326Ssam 	{ "c", " '%c'", sizeof(char) },
34326326Ssam 	{ "s", "%c", sizeof(char) },
34426326Ssam 	{ "f", " %f", sizeof(float) },
34526326Ssam 	{ "g", " %g", sizeof(double) },
34626326Ssam 	{ nil, nil, 0 }
34726326Ssam };
34826326Ssam 
34926326Ssam private Format *findformat(s)
35026326Ssam 	String s;
35126326Ssam {
35226326Ssam 	register Format *f;
35326326Ssam 
35426326Ssam 	for (f = &fmt[0]; f->name != nil && !streq(f->name, s); f++)
35526326Ssam 		;
35626326Ssam 	if (f->name == nil)
35726326Ssam 		error("bad print format \"%s\"", s);
35826326Ssam 	return (f);
35926326Ssam }
36026326Ssam 
36126326Ssam public Address printdata(lowaddr, highaddr, format)
36226326Ssam 	Address lowaddr;
36326326Ssam 	Address highaddr;
36426326Ssam 	String format;
36526326Ssam {
36626326Ssam 	register int n;
36726326Ssam 	register Address addr;
36826326Ssam 	register Format *f;
36926326Ssam 	int value;
37026326Ssam 
37126326Ssam 	if (lowaddr > highaddr)
37226326Ssam 		error("first address larger than second");
37326326Ssam 	f = findformat(format);
37426326Ssam 	n = 0;
37526326Ssam 	value = 0;
37626326Ssam 	for (addr = lowaddr; addr <= highaddr; addr += f->length) {
37726326Ssam 		if (n == 0)
37826326Ssam 			printf("%08x: ", addr);
37926326Ssam 		dread(&value, addr, f->length);
38026326Ssam 		printf(f->printfstring, value);
38126326Ssam 		++n;
38226326Ssam 		if (n >= (16 div f->length)) {
38326326Ssam 			putchar('\n');
38426326Ssam 			n = 0;
38526326Ssam 		}
38626326Ssam 	}
38726326Ssam 	if (n != 0)
38826326Ssam 		putchar('\n');
38926326Ssam 	prtaddr = addr;
39026326Ssam 	return (addr);
39126326Ssam }
39226326Ssam 
39326326Ssam /*
39426326Ssam  * The other approach is to print n items starting with a given address.
39526326Ssam  */
39626326Ssam 
39726326Ssam public printndata(count, startaddr, format)
39826326Ssam int count;
39926326Ssam Address startaddr;
40026326Ssam String format;
40126326Ssam {
40226326Ssam 	register int i, n;
40326326Ssam 	register Address addr;
40426326Ssam 	register Format *f;
40526326Ssam 	register Boolean isstring;
40626326Ssam 	char c;
40726326Ssam 	union {
40826326Ssam 		char	charv;
40926326Ssam 		short	shortv;
41026326Ssam 		int	intv;
41126326Ssam 		float	floatv;
41226326Ssam 		double	doublev;
41326326Ssam 	} value;
41426326Ssam 
41526326Ssam 	if (count <= 0)
41626326Ssam 		error("non-positive repetition count");
41726326Ssam 	f = findformat(format);
41826326Ssam 	isstring = (Boolean) streq(f->name, "s");
41926326Ssam 	n = 0;
42026326Ssam 	addr = startaddr;
42126326Ssam 	value.intv = 0;
42226326Ssam 	for (i = 0; i < count; i++) {
42326326Ssam 		if (n == 0)
42426326Ssam 			printf("%08x: ", addr);
42526326Ssam 		if (isstring) {
42626326Ssam 			putchar('"');
42726326Ssam 			dread(&c, addr, sizeof(char));
42826326Ssam 			while (c != '\0') {
42926326Ssam 				printchar(c);
43026326Ssam 				++addr;
43126326Ssam 				dread(&c, addr, sizeof(char));
43226326Ssam 			}
43326326Ssam 			putchar('"');
43426326Ssam 			putchar('\n');
43526326Ssam 			n = 0;
43626326Ssam 			addr += sizeof(String);
43726326Ssam 			continue;
43826326Ssam 		}
43926326Ssam 		dread(&value, addr, f->length);
44026326Ssam 		printf(f->printfstring, value);
44126326Ssam 		++n;
44226326Ssam 		if (n >= (16 div f->length)) {
44326326Ssam 			putchar('\n');
44426326Ssam 			n = 0;
44526326Ssam 		}
44626326Ssam 		addr += f->length;
44726326Ssam 	}
44826326Ssam 	if (n != 0)
44926326Ssam 		putchar('\n');
45026326Ssam 	prtaddr = addr;
45126326Ssam }
45226326Ssam 
45326326Ssam /*
45426326Ssam  * Print out a value according to the given format.
45526326Ssam  */
45626326Ssam public printvalue(v, format)
45726326Ssam 	long v;
45826326Ssam 	String format;
45926326Ssam {
46026326Ssam 	Format *f;
46126326Ssam 	char *p, *q;
46226326Ssam 
46326326Ssam 	f = findformat(format);
46426326Ssam 	if (streq(f->name, "s")) {
46526326Ssam 		putchar('"');
46626326Ssam 		for (p = (char *) &v, q = p + sizeof(v); p < q; ++p)
46726326Ssam 			printchar(*p);
46826326Ssam 		putchar('"');
46926326Ssam 	} else
47026326Ssam 		printf(f->printfstring, v);
47126326Ssam 	putchar('\n');
47226326Ssam }
47326326Ssam 
47426326Ssam /*
47526326Ssam  * Print out an execution time error.
47626326Ssam  * Assumes the source position of the error has been calculated.
47726326Ssam  *
47826326Ssam  * Have to check if the -r option was specified; if so then
47926326Ssam  * the object file information hasn't been read in yet.
48026326Ssam  */
48126326Ssam public printerror()
48226326Ssam {
48326326Ssam 	extern Integer sys_nsig;
48426326Ssam 	extern String sys_siglist[];
48526326Ssam 	integer err;
48626326Ssam 
48726326Ssam 	if (isfinished(process)) {
48826326Ssam 		err = exitcode(process);
48926326Ssam 		if (err) {
49026326Ssam 			printf("\"%s\" terminated abnormally (exit code %d)\n",
49126326Ssam 			    objname, err);
49226326Ssam 			erecover();
49326326Ssam 		} else
49426326Ssam 			printf("\"%s\" terminated normally\n", objname);
49526326Ssam 	}
49626326Ssam 	if (runfirst) {
49726326Ssam 		fprintf(stderr, "Entering debugger ...\n");
49826326Ssam 		init();
49926326Ssam 	}
50026326Ssam 	err = errnum(process);
50126326Ssam 	putchar('\n');
50226326Ssam 	printsig(err);
50326326Ssam 	putchar(' ');
50426326Ssam 	printloc();
50526326Ssam 	putchar('\n');
50626326Ssam 	if (curline > 0)
50726326Ssam 		printlines(curline, curline);
50826326Ssam 	else
50926326Ssam 		printinst(pc, pc);
51026326Ssam 	erecover();
51126326Ssam }
51226326Ssam 
51326326Ssam /*
51426326Ssam  * Print out a signal.
51526326Ssam  */
51626326Ssam private String illinames[] = {
51726326Ssam 	"reserved addressing fault",
51826326Ssam 	"priviliged instruction fault",
51926326Ssam 	"reserved operand fault"
52026326Ssam };
52126326Ssam #define	NILLINAMES	(sizeof (illinames) / sizeof (illinames[0]))
52226326Ssam 
52326326Ssam private String fpenames[] = {
52426326Ssam 	nil,
52526326Ssam 	"integer overflow trap",
52626326Ssam 	"integer divide by zero trap",
52726326Ssam 	"floating point divide by zero trap",
52826326Ssam 	"floating point overflow trap",
52926326Ssam 	"floating point underflow trap",
53026326Ssam };
53126326Ssam #define	NFPENAMES	(sizeof (fpenames) / sizeof (fpenames[0]))
53226326Ssam 
53326326Ssam public printsig(signo)
53426326Ssam integer signo;
53526326Ssam {
53626326Ssam 	integer code;
53726326Ssam 
53826326Ssam 	if (signo < 0 or signo > sys_nsig)
53926326Ssam 		printf("[signal %d]", signo);
54026326Ssam 	else
54126326Ssam 		printf("%s", sys_siglist[signo]);
54226326Ssam 	code = errcode(process);
54326326Ssam 	if (signo == SIGILL)
54426326Ssam 		if (code >= 0 && code < NILLINAMES)
54526326Ssam 			printf(" (%s)", illinames[code]);
54626326Ssam 	if (signo == SIGFPE)
54726326Ssam 		if (code > 0 and code < NFPENAMES)
54826326Ssam 			printf(" (%s)", fpenames[code]);
54926326Ssam }
55026326Ssam 
55126326Ssam /*
55226326Ssam  * Note the termination of the program.  We do this so as to avoid
55326326Ssam  * having the process exit, which would make the values of variables
55426326Ssam  * inaccessible.  We do want to flush all output buffers here,
55526326Ssam  * otherwise it'll never get done.
55626326Ssam  */
55726326Ssam public endprogram()
55826326Ssam {
55926326Ssam 	Integer exitcode;
56026326Ssam 
56126326Ssam 	stepto(nextaddr(pc, true));
56226326Ssam 	printnews();
56326326Ssam 	exitcode = argn(1, nil);
56426326Ssam 	if (exitcode != 0)
56526326Ssam 		printf("\nexecution completed (exit code %d)\n", exitcode);
56626326Ssam 	else
56726326Ssam 		printf("\nexecution completed\n");
56826326Ssam 	getsrcpos();
56926326Ssam 	erecover();
57026326Ssam }
57126326Ssam 
57226326Ssam private Address getcall();
57326326Ssam /*
57426326Ssam  * Single step the machine a source line (or instruction if "inst_tracing"
57526326Ssam  * is true).  If "isnext" is true, skip over procedure calls.
57626326Ssam  */
57726326Ssam public dostep(isnext)
57826326Ssam 	Boolean isnext;
57926326Ssam {
58026326Ssam 	register Address addr;
58126326Ssam 	register Lineno line;
58226326Ssam 	String filename;
58326326Ssam 	Address startaddr;
58426326Ssam 
58526326Ssam 	startaddr = pc;
58626326Ssam 	addr = nextaddr(pc, isnext);
58726326Ssam 	if (!inst_tracing && nlhdr.nlines != 0) {
58826326Ssam 		line = linelookup(addr);
58926326Ssam 		for (; line == 0; line = linelookup(addr))
59026326Ssam 			addr = nextaddr(addr, isnext);
59126326Ssam 		curline = line;
59226326Ssam 	} else
59326326Ssam 		curline = 0;
59426326Ssam 	stepto(addr);
59526326Ssam 	filename = srcfilename(addr);
59626326Ssam 	setsource(filename);
59726326Ssam }
59826326Ssam 
59926326Ssam private Address findnextaddr();
60026326Ssam /*
60126326Ssam  * Compute the next address that will be executed from the given one.
60226326Ssam  * If "isnext" is true then consider a procedure call as straight line code.
60326326Ssam  *
60426326Ssam  * We must unfortunately do much of the same work that is necessary
60526326Ssam  * to print instructions.  In addition we have to deal with branches.
60626326Ssam  * Unconditional branches we just follow, for conditional branches
60726326Ssam  * we continue execution to the current location and then single step
60826326Ssam  * the machine.  We assume that the last argument in an instruction
60926326Ssam  * that branches is the branch address (or relative offset).
61026326Ssam  */
61126326Ssam public Address nextaddr(startaddr, isnext)
61226326Ssam 	Address startaddr;
61326326Ssam 	boolean isnext;
61426326Ssam {
61526326Ssam 	Address addr;
61626326Ssam 
61726326Ssam 	addr = usignal(process);
61826326Ssam 	if (addr == 0 or addr == 1)
61926326Ssam 		addr = findnextaddr(startaddr, isnext);
62026326Ssam 	return (addr);
62126326Ssam }
62226326Ssam 
62326326Ssam /*
62426326Ssam  * Determine if it's ok to skip function f entered by instruction ins.
62526326Ssam  * If so, we're going to compute the return address and step to it.
62626326Ssam  */
62726326Ssam private boolean skipfunc(ins, f)
62826326Ssam 	Opcode ins;
62926326Ssam 	Symbol f;
63026326Ssam {
63126326Ssam 
63226326Ssam 	return ((boolean) (!inst_tracing && nlhdr.nlines != 0 &&
63326326Ssam 		nosource(curfunc) && canskip(curfunc)));
63426326Ssam }
63526326Ssam 
63626326Ssam private Address findnextaddr(startaddr, isnext)
63726326Ssam 	Address startaddr;
63826326Ssam 	Boolean isnext;
63926326Ssam {
64026326Ssam 	register Address addr;
64126326Ssam 	Optab *op;
64226326Ssam 	Opcode ins;
64326326Ssam 	unsigned char mode;
64426326Ssam 	int argtype, amode, argno, argval, nib;
64526326Ssam 	String r;
64626326Ssam 	Boolean indexf;
64726326Ssam 	enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
64826326Ssam 
64926326Ssam 	argval = 0;
65026326Ssam 	indexf = false;
65126326Ssam 	addr = startaddr;
65226326Ssam 	iread(&ins, addr, sizeof(ins));
65326326Ssam 	switch (ins) {
65426326Ssam 
65526326Ssam 	case O_CALLF:
65626326Ssam 	case O_CALLS:
65726326Ssam 		addrstatus = KNOWN;
65826326Ssam 		stepto(addr);
65926326Ssam 		pstep(process, DEFSIG);
66026326Ssam 		addr = reg(PROGCTR);
66126326Ssam 		pc = addr;
66226326Ssam 		setcurfunc(whatblock(pc));
66326326Ssam 		if (not isbperr()) {
66426326Ssam 			printstatus();
66526326Ssam 			/* NOTREACHED */
66626326Ssam 		}
66726326Ssam 		bpact();
66826326Ssam 		if (isnext or skipfunc(ins, curfunc)) {
66926326Ssam 			addrstatus = KNOWN;
67026326Ssam 			addr = return_addr();
67126326Ssam 			stepto(addr);
67226326Ssam 			bpact();
67326326Ssam 		} else
67426326Ssam 			callnews(/* iscall = */ true);
67526326Ssam 		break;
67626326Ssam 
67726326Ssam 	case O_RET:
67826326Ssam 		addrstatus = KNOWN;
67926326Ssam 		stepto(addr);
68026326Ssam 		callnews(/* iscall = */ false);
68126326Ssam 		pstep(process, DEFSIG);
68226326Ssam 		addr = reg(PROGCTR);
68326326Ssam 		pc = addr;
68426326Ssam 		if (not isbperr())
68526326Ssam 			printstatus();
68626326Ssam 		bpact();
68726326Ssam 		break;
68826326Ssam 
68926326Ssam 	case O_BRB:
69026326Ssam 	case O_BRW:
69126326Ssam 	case O_JMP:
69226326Ssam 	case O_BBSSI:
69326326Ssam 	case O_BCC:
69426326Ssam 	case O_BCS:
69526326Ssam 	case O_BEQL:
69626326Ssam 	case O_BGEQ:
69726326Ssam 	case O_BGTR:
69826326Ssam 	case O_BGTRU:
69926326Ssam 	case O_BLEQ:
70026326Ssam 	case O_BLEQU:
70126326Ssam 	case O_BLSS:
70226326Ssam 	case O_BNEQ:
70326326Ssam 	case O_BVC:
70426326Ssam 	case O_BVS:
70526326Ssam 	case O_CASEL:
70626326Ssam 	case O_AOBLSS:
70726326Ssam 	case O_AOBLEQ:
70826326Ssam 		addrstatus = KNOWN;
70926326Ssam 		stepto(addr);
71026326Ssam 		pstep(process, DEFSIG);
71126326Ssam 		addr = reg(PROGCTR);
71226326Ssam 		pc = addr;
71326326Ssam 		if (not isbperr())
71426326Ssam 			printstatus();
71526326Ssam 		break;
71626326Ssam 
71726326Ssam 	default:
71826326Ssam 		addrstatus = SEQUENTIAL;
71926326Ssam 		break;
72026326Ssam 	}
72126326Ssam 	if (addrstatus == KNOWN)
72226326Ssam 		return (addr);
72326326Ssam 	addr += 1;
72426326Ssam 	op = ioptab[ins];
72526326Ssam 	for (argno = 0; argno < op->numargs; argno++) {
72626326Ssam 		if (indexf == true)
72726326Ssam 			indexf = false;
72826326Ssam 		argtype = op->argtype[argno];
72926326Ssam 		if (is_branch_disp(argtype))
73026326Ssam 			mode = 0xAF + (typelen(argtype) << 5);
73126326Ssam 		else
73226326Ssam 			iread(&mode, addr, sizeof(mode)), addr += 1;
73326326Ssam 		r = regname[regnm(mode)];
73426326Ssam 		amode = addrmode(mode);
73526326Ssam 		switch (amode) {
73626326Ssam 
73726326Ssam 		case LITSHORT:
73826326Ssam 		case LITUPTO31:
73926326Ssam 		case LITUPTO47:
74026326Ssam 		case LITUPTO63:
74126326Ssam 			argval = mode;
74226326Ssam 			break;
74326326Ssam 
74426326Ssam 		case INDEX:
74526326Ssam 			indexf = true;
74626326Ssam 			--argno;
74726326Ssam 			break;
74826326Ssam 
74926326Ssam 		case REG:
75026326Ssam 		case REGDEF:
75126326Ssam 		case AUTODEC:
75226326Ssam 			break;
75326326Ssam 
75426326Ssam 		case AUTOINC:
75526326Ssam 			nib = mode & 0xf;
75626326Ssam 			if (nib == 0xf || nib == 8 || nib == 9) {
75726326Ssam 				int size = (mode&03)+1;
75826326Ssam 
75926326Ssam 				argval = getdisp(addr, size,
76026326Ssam 				    regname[PROGCTR], amode);
76126326Ssam 				addr += size;
76226326Ssam 			}
76326326Ssam 			break;
76426326Ssam 
76526326Ssam 		case AUTOINCDEF:
76626326Ssam 			if ((mode&0xf) != 0xf)
76726326Ssam 				break;
76826326Ssam 			argval = getdisp(addr, 4, r, amode);
76926326Ssam 			addr += 4;
77026326Ssam 			break;
77126326Ssam 
77226326Ssam 		case BYTEDISP:
77326326Ssam 		case BYTEDISPDEF:
77426326Ssam 			argval = getdisp(addr, 1, r, amode);
77526326Ssam 			addr += 1;
77626326Ssam 			break;
77726326Ssam 
77826326Ssam 		case WORDDISP:
77926326Ssam 		case WORDDISPDEF:
78026326Ssam 			argval = getdisp(addr, 2, r, amode);
78126326Ssam 			addr += 2;
78226326Ssam 			break;
78326326Ssam 
78426326Ssam 		case LONGDISP:
78526326Ssam 		case LONGDISPDEF:
78626326Ssam 			argval = getdisp(addr, 4, r, amode);
78726326Ssam 			addr += 4;
78826326Ssam 			break;
78926326Ssam 		}
79026326Ssam 	}
79126326Ssam 	if (ins == O_CALLF or ins == O_CALLS)
79226326Ssam 		argval += 2;
79326326Ssam 	if (addrstatus == BRANCH)
79426326Ssam 		addr = argval;
79526326Ssam 	return (addr);
79626326Ssam }
79726326Ssam 
79826326Ssam /*
79926326Ssam  * Get the displacement of an instruction that uses displacement addressing.
80026326Ssam  */
80126326Ssam private int getdisp(addr, nbytes, reg, mode)
80226326Ssam 	Address addr;
80326326Ssam 	int nbytes;
80426326Ssam 	String reg;
80526326Ssam 	int mode;
80626326Ssam {
80726326Ssam 	char byte;
80826326Ssam 	short hword;
80926326Ssam 	int argval;
81026326Ssam 
81126326Ssam 	switch (nbytes) {
81226326Ssam 
81326326Ssam 	case 1:
81426326Ssam 		iread(&byte, addr, sizeof(byte));
81526326Ssam 		argval = byte;
81626326Ssam 		break;
81726326Ssam 
81826326Ssam 	case 2:
81926326Ssam 		iread(&hword, addr, sizeof(hword));
82026326Ssam 		argval = hword;
82126326Ssam 		break;
82226326Ssam 
82326326Ssam 	case 4:
82426326Ssam 		iread(&argval, addr, sizeof(argval));
82526326Ssam 		break;
82626326Ssam 	}
82726326Ssam 	if (reg == regname[PROGCTR] && mode >= BYTEDISP)
82826326Ssam 		argval += addr + nbytes;
82926326Ssam 	return (argval);
83026326Ssam }
83126326Ssam 
83226326Ssam #define BP_OP	   	O_BPT	   /* breakpoint trap */
83326326Ssam #define BP_ERRNO	SIGTRAP	 /* signal received at a breakpoint */
83426326Ssam 
83526326Ssam /*
83626326Ssam  * Setting a breakpoint at a location consists of saving
83726326Ssam  * the word at the location and poking a BP_OP there.
83826326Ssam  *
83926326Ssam  * We save the locations and words on a list for use in unsetting.
84026326Ssam  */
84126326Ssam typedef struct Savelist *Savelist;
84226326Ssam 
84326326Ssam struct Savelist {
84426326Ssam 	Address location;
84526326Ssam 	Byte save;
84626326Ssam 	Byte refcount;
84726326Ssam 	Savelist link;
84826326Ssam };
84926326Ssam 
85026326Ssam private Savelist savelist;
85126326Ssam 
85226326Ssam /*
85326326Ssam  * Set a breakpoint at the given address.  Only save the word there
85426326Ssam  * if it's not already a breakpoint.
85526326Ssam  */
85626326Ssam public setbp(addr)
85726326Ssam 	Address addr;
85826326Ssam {
85926326Ssam 	Byte w, save;
86026326Ssam 	register Savelist newsave, s;
86126326Ssam 
86226326Ssam 	for (s = savelist; s != nil; s = s->link)
86326326Ssam 		if (s->location == addr) {
86426326Ssam 			s->refcount++;
86526326Ssam 			return;
86626326Ssam 		}
86726326Ssam 	iread(&save, addr, sizeof(save));
86826326Ssam 	newsave = new(Savelist);
86926326Ssam 	newsave->location = addr;
87026326Ssam 	newsave->save = save;
87126326Ssam 	newsave->refcount = 1;
87226326Ssam 	newsave->link = savelist;
87326326Ssam 	savelist = newsave;
87426326Ssam 	w = BP_OP;
87526326Ssam 	iwrite(&w, addr, sizeof(w));
87626326Ssam }
87726326Ssam 
87826326Ssam /*
87926326Ssam  * Unset a breakpoint; unfortunately we have to search the SAVELIST
88026326Ssam  * to find the saved value.  The assumption is that the SAVELIST will
88126326Ssam  * usually be quite small.
88226326Ssam  */
88326326Ssam public unsetbp(addr)
88426326Ssam Address addr;
88526326Ssam {
88626326Ssam 	register Savelist s, prev;
88726326Ssam 
88826326Ssam 	prev = nil;
88926326Ssam 	for (s = savelist; s != nil; s = s->link) {
89026326Ssam 		if (s->location == addr) {
89126326Ssam 			iwrite(&s->save, addr, sizeof(s->save));
89226326Ssam 			s->refcount--;
89326326Ssam 			if (s->refcount == 0) {
89426326Ssam 				if (prev == nil)
89526326Ssam 					savelist = s->link;
89626326Ssam 				else
89726326Ssam 					prev->link = s->link;
89826326Ssam 				dispose(s);
89926326Ssam 			}
90026326Ssam 			return;
90126326Ssam 		}
90226326Ssam 		prev = s;
90326326Ssam 	}
90426326Ssam 	panic("unsetbp: couldn't find address %d", addr);
90526326Ssam }
90626326Ssam 
90726326Ssam /*
90826326Ssam  * Enter a procedure by creating and executing a call instruction.
90926326Ssam  */
91026326Ssam 
91126326Ssam #define CALLSIZE 7	/* size of call instruction */
91226326Ssam 
91326326Ssam public beginproc(p, argc)
91426326Ssam 	Symbol p;
91526326Ssam 	Integer argc;
91626326Ssam {
91726326Ssam 	char save[CALLSIZE];
91826326Ssam 	struct {
91926326Ssam 		Opcode op;
92026326Ssam 		unsigned char numargs;
92126326Ssam 		unsigned char mode;
92226326Ssam 		char addr[sizeof(long)];	/* unaligned long */
92326326Ssam 	} call;
92426326Ssam 	long dest;
92526326Ssam 
92626326Ssam error("Can't do a \"call\" right now...sorry");	/* XXX */
92726326Ssam 	if (4*argc+4 > 256)
92826326Ssam 		error("too many parameters (max %d)", 256/4 - 1);
92926326Ssam 	pc = 2;
93026326Ssam 	iread(save, pc, sizeof(save));
93126326Ssam 	call.op = O_CALLF;
93226326Ssam 	call.numargs = 4*argc+4;
93326326Ssam 	call.mode = 0xef;			/* longword relative */
93426326Ssam 	dest = codeloc(p) - 2 - (pc + CALLSIZE);
93526326Ssam 	mov(&dest, call.addr, sizeof(call.addr));
93626326Ssam 	iwrite(&call, pc, sizeof(call));
93726326Ssam 	setreg(PROGCTR, pc);
93826326Ssam 	pstep(process, DEFSIG);
93926326Ssam 	iwrite(save, pc, sizeof(save));
94026326Ssam 	pc = reg(PROGCTR);
94126326Ssam 	if (not isbperr())
94226326Ssam 		printstatus();
94326326Ssam }
944*26337Ssam 
945*26337Ssam /*
946*26337Ssam  * Special variables for debugging the kernel.
947*26337Ssam  */
948*26337Ssam 
949*26337Ssam public integer masterpcbb;
950*26337Ssam public integer slr;
951*26337Ssam public struct pte *sbr;
952*26337Ssam public struct pcb pcb;
953*26337Ssam 
954*26337Ssam public getpcb ()
955*26337Ssam {
956*26337Ssam     fseek(corefile, masterpcbb & ~0xc0000000, 0);
957*26337Ssam     get(corefile, pcb);
958*26337Ssam     printf("p0br %lx p0lr %lx p2br %lx p2lr %lx\n",
959*26337Ssam 	pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p2br, pcb.pcb_p2lr
960*26337Ssam     );
961*26337Ssam     setreg(0, pcb.pcb_r0);
962*26337Ssam     setreg(1, pcb.pcb_r1);
963*26337Ssam     setreg(2, pcb.pcb_r2);
964*26337Ssam     setreg(3, pcb.pcb_r3);
965*26337Ssam     setreg(4, pcb.pcb_r4);
966*26337Ssam     setreg(5, pcb.pcb_r5);
967*26337Ssam     setreg(6, pcb.pcb_r6);
968*26337Ssam     setreg(7, pcb.pcb_r7);
969*26337Ssam     setreg(8, pcb.pcb_r8);
970*26337Ssam     setreg(9, pcb.pcb_r9);
971*26337Ssam     setreg(10, pcb.pcb_r10);
972*26337Ssam     setreg(11, pcb.pcb_r11);
973*26337Ssam     setreg(12, pcb.pcb_r12);
974*26337Ssam     setreg(FRP, pcb.pcb_fp);
975*26337Ssam     setreg(STKP, pcb.pcb_ksp);
976*26337Ssam     setreg(PROGCTR, pcb.pcb_pc);
977*26337Ssam }
978*26337Ssam 
979*26337Ssam public copyregs (savreg, reg)
980*26337Ssam Word savreg[], reg[];
981*26337Ssam {
982*26337Ssam     reg[0] = savreg[R0];
983*26337Ssam     reg[1] = savreg[R1];
984*26337Ssam     reg[2] = savreg[R2];
985*26337Ssam     reg[3] = savreg[R3];
986*26337Ssam     reg[4] = savreg[R4];
987*26337Ssam     reg[5] = savreg[R5];
988*26337Ssam     reg[6] = savreg[R6];
989*26337Ssam     reg[7] = savreg[R7];
990*26337Ssam     reg[8] = savreg[R8];
991*26337Ssam     reg[9] = savreg[R9];
992*26337Ssam     reg[10] = savreg[R10];
993*26337Ssam     reg[11] = savreg[R11];
994*26337Ssam     reg[12] = savreg[R12];
995*26337Ssam     reg[FRP] = savreg[FP];
996*26337Ssam     reg[STKP] = savreg[SP];
997*26337Ssam     reg[PROGCTR] = savreg[PC];
998*26337Ssam }
999*26337Ssam 
1000*26337Ssam /*
1001*26337Ssam  * Map a virtual address to a physical address.
1002*26337Ssam  */
1003*26337Ssam 
1004*26337Ssam public Address vmap (addr)
1005*26337Ssam Address addr;
1006*26337Ssam {
1007*26337Ssam 	int oldaddr = addr, v;
1008*26337Ssam 	struct pte pte;
1009*26337Ssam 
1010*26337Ssam 	addr &= ~0xc0000000;
1011*26337Ssam 	v = btop(addr);
1012*26337Ssam 	switch (oldaddr&0xc0000000) {
1013*26337Ssam 
1014*26337Ssam 	case 0xc0000000:
1015*26337Ssam 		/*
1016*26337Ssam 		 * In system space get system pte.  If
1017*26337Ssam 		 * valid or reclaimable then physical address
1018*26337Ssam 		 * is combination of its page number and the page
1019*26337Ssam 		 * offset of the original address.
1020*26337Ssam 		 */
1021*26337Ssam 		if (v >= slr)
1022*26337Ssam 			goto oor;
1023*26337Ssam 		addr = ((long)(sbr+v)) &~ 0xc0000000;
1024*26337Ssam 		goto simple;
1025*26337Ssam 
1026*26337Ssam 	case 0x80000000:
1027*26337Ssam 		/*
1028*26337Ssam 		 * In p2 spce must not be in shadow region.
1029*26337Ssam 		 */
1030*26337Ssam 		if (v < pcb.pcb_p2lr)
1031*26337Ssam 			goto oor;
1032*26337Ssam 		addr = (long)(pcb.pcb_p2br+v);
1033*26337Ssam 		break;
1034*26337Ssam 
1035*26337Ssam 	case 0x40000000:
1036*26337Ssam 		/*
1037*26337Ssam 		 * In p1 space everything is verboten (for now).
1038*26337Ssam 		 */
1039*26337Ssam 		goto oor;
1040*26337Ssam 
1041*26337Ssam 	case 0x00000000:
1042*26337Ssam 		/*
1043*26337Ssam 		 * In p0 space must not be off end of region.
1044*26337Ssam 		 */
1045*26337Ssam 		if (v >= pcb.pcb_p0lr)
1046*26337Ssam 			goto oor;
1047*26337Ssam 		addr = (long)(pcb.pcb_p0br+v);
1048*26337Ssam 		break;
1049*26337Ssam 	oor:
1050*26337Ssam 		error("address out of segment");
1051*26337Ssam 	}
1052*26337Ssam 	/*
1053*26337Ssam 	 * For p0/p1/p2 address, user-level page table should
1054*26337Ssam 	 * be in kernel vm.  Do second-level indirect by recursing.
1055*26337Ssam 	 */
1056*26337Ssam 	if ((addr & 0xc0000000) != 0xc0000000)
1057*26337Ssam 		error("bad p0br, p1br, or p2br in pcb");
1058*26337Ssam 	addr = vmap(addr);
1059*26337Ssam simple:
1060*26337Ssam 	/*
1061*26337Ssam 	 * Addr is now address of the pte of the page we
1062*26337Ssam 	 * are interested in; get the pte and paste up the
1063*26337Ssam 	 * physical address.
1064*26337Ssam 	 */
1065*26337Ssam 	fseek(corefile, addr, 0);
1066*26337Ssam 	if (fread(&pte, sizeof (pte), 1, corefile) != 1)
1067*26337Ssam 		error("page table botch");
1068*26337Ssam 	/* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */
1069*26337Ssam 	if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0))
1070*26337Ssam 		error("page not valid/reclaimable");
1071*26337Ssam 	return ((long)(ptob(pte.pg_pfnum) + (oldaddr & PGOFSET)));
1072*26337Ssam }
1073