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