xref: /csrg-svn/old/dbx/tahoe.c (revision 26326)
1*26326Ssam /*
2*26326Ssam  * Copyright (c) 1985 Regents of the University of California.
3*26326Ssam  * All rights reserved.  The Berkeley software License Agreement
4*26326Ssam  * specifies the terms and conditions for redistribution.
5*26326Ssam  */
6*26326Ssam 
7*26326Ssam #ifndef lint
8*26326Ssam static char sccsid[] = "@(#)tahoe.c	1.1 (Berkeley) 02/22/86";
9*26326Ssam #endif not lint
10*26326Ssam 
11*26326Ssam /*
12*26326Ssam  * Target machine dependent stuff.
13*26326Ssam  */
14*26326Ssam 
15*26326Ssam #include "defs.h"
16*26326Ssam #include "machine.h"
17*26326Ssam #include "process.h"
18*26326Ssam #include "runtime.h"
19*26326Ssam #include "events.h"
20*26326Ssam #include "main.h"
21*26326Ssam #include "symbols.h"
22*26326Ssam #include "source.h"
23*26326Ssam #include "mappings.h"
24*26326Ssam #include "object.h"
25*26326Ssam #include "keywords.h"
26*26326Ssam #include "ops.h"
27*26326Ssam #include <signal.h>
28*26326Ssam 
29*26326Ssam #ifndef public
30*26326Ssam typedef unsigned int Address;
31*26326Ssam typedef unsigned char Byte;
32*26326Ssam typedef unsigned int Word;
33*26326Ssam 
34*26326Ssam #define NREG 16
35*26326Ssam 
36*26326Ssam #define FRP 13
37*26326Ssam #define STKP 14
38*26326Ssam #define PROGCTR 15
39*26326Ssam 
40*26326Ssam #define BITSPERBYTE 8
41*26326Ssam #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
42*26326Ssam 
43*26326Ssam #define nargspassed(frame) ((frame->removed-4)/4)
44*26326Ssam 
45*26326Ssam #include "source.h"
46*26326Ssam #include "symbols.h"
47*26326Ssam 
48*26326Ssam Address pc;
49*26326Ssam Address prtaddr;
50*26326Ssam 
51*26326Ssam #endif
52*26326Ssam 
53*26326Ssam private Address printop();
54*26326Ssam 
55*26326Ssam Optab	*ioptab[256];	/* index by opcode to optab */
56*26326Ssam /*
57*26326Ssam  * Initialize the opcode lookup table.
58*26326Ssam  */
59*26326Ssam public optab_init()
60*26326Ssam {
61*26326Ssam 	register Optab *p;
62*26326Ssam 
63*26326Ssam 	for (p = optab; p->iname; p++)
64*26326Ssam 		ioptab[p->val & 0xff] = p;
65*26326Ssam }
66*26326Ssam 
67*26326Ssam /*
68*26326Ssam  * Decode and print the instructions within the given address range.
69*26326Ssam  */
70*26326Ssam public printinst(lowaddr, highaddr)
71*26326Ssam 	Address lowaddr, highaddr;
72*26326Ssam {
73*26326Ssam 	register Address addr;
74*26326Ssam 
75*26326Ssam 	for (addr = lowaddr; addr <= highaddr; )
76*26326Ssam 		addr = printop(addr);
77*26326Ssam 	prtaddr = addr;
78*26326Ssam }
79*26326Ssam 
80*26326Ssam /*
81*26326Ssam  * Another approach:  print n instructions starting at the given address.
82*26326Ssam  */
83*26326Ssam public printninst(count, addr)
84*26326Ssam 	int count;
85*26326Ssam 	Address addr;
86*26326Ssam {
87*26326Ssam 	register Integer i;
88*26326Ssam 	register Address newaddr;
89*26326Ssam 
90*26326Ssam 	if (count <= 0)
91*26326Ssam 		error("non-positive repetition count");
92*26326Ssam 	for (newaddr = addr, i = 0; i < count; i++)
93*26326Ssam 		newaddr = printop(newaddr);
94*26326Ssam 	prtaddr = newaddr;
95*26326Ssam }
96*26326Ssam 
97*26326Ssam /*
98*26326Ssam  * Hacked version of adb's instruction decoder.
99*26326Ssam  */
100*26326Ssam private Address printop(addr)
101*26326Ssam 	Address addr;
102*26326Ssam {
103*26326Ssam 	register Optab *op;
104*26326Ssam 	Opcode ins;
105*26326Ssam 	unsigned char mode;
106*26326Ssam 	int argtype, amode, argno, argval, r;
107*26326Ssam 	String reg;
108*26326Ssam 	Boolean indexf;
109*26326Ssam 	short offset;
110*26326Ssam 
111*26326Ssam 	argval = 0;
112*26326Ssam 	indexf = false;
113*26326Ssam 	printf("%08x  ", addr);
114*26326Ssam 	iread(&ins, addr, sizeof(ins));
115*26326Ssam 	addr += 1;
116*26326Ssam 	op = ioptab[ins];
117*26326Ssam 	printf("%s", op->iname);
118*26326Ssam 	for (argno = 0; argno < op->numargs; argno++) {
119*26326Ssam 		if (indexf == true)
120*26326Ssam 			indexf = false;
121*26326Ssam 		else
122*26326Ssam 			printf(argno == 0 ? "\t" : ",");
123*26326Ssam 		argtype = op->argtype[argno];
124*26326Ssam 		if (is_branch_disp(argtype))
125*26326Ssam 			mode = 0xAF + (typelen(argtype) << 5);
126*26326Ssam 		else
127*26326Ssam 			iread(&mode, addr, sizeof(mode)), addr += 1;
128*26326Ssam 		reg = regname[regnm(mode)];
129*26326Ssam 		amode = addrmode(mode);
130*26326Ssam 		switch (amode) {
131*26326Ssam 
132*26326Ssam 		case LITSHORT: case LITUPTO31:
133*26326Ssam 		case LITUPTO47: case LITUPTO63:
134*26326Ssam 			if (ins == O_KCALL && mode >= 0 && mode < SYSSIZE &&
135*26326Ssam 			   systab[mode])
136*26326Ssam 				printf("$%s", systab[mode]);
137*26326Ssam 			else
138*26326Ssam 				printf("$%x", mode);
139*26326Ssam 			argval = mode;
140*26326Ssam 			break;
141*26326Ssam 
142*26326Ssam 		case INDEX:
143*26326Ssam 			printf("[%s]", reg);
144*26326Ssam 			indexf = true;
145*26326Ssam 			argno--;
146*26326Ssam 			break;
147*26326Ssam 
148*26326Ssam 		case REG:
149*26326Ssam 			printf("%s", reg);
150*26326Ssam 			break;
151*26326Ssam 
152*26326Ssam 		case REGDEF:
153*26326Ssam 			printf("(%s)", reg);
154*26326Ssam 			break;
155*26326Ssam 
156*26326Ssam 		case AUTODEC:
157*26326Ssam 			printf("-(%s)", reg);
158*26326Ssam 			break;
159*26326Ssam 
160*26326Ssam 		case AUTOINC:
161*26326Ssam 			r = mode & 0xf;
162*26326Ssam 			if (r == 0xf || r == 8 || r == 9) {
163*26326Ssam 				int size = (mode&03) + 1;
164*26326Ssam 
165*26326Ssam 				/* immediate mode */
166*26326Ssam 				printf("$");
167*26326Ssam 				argval = printdisp(addr, size,
168*26326Ssam 				    regname[PROGCTR], amode);
169*26326Ssam 				addr += size;
170*26326Ssam 			} else
171*26326Ssam 				printf("(%s)+", reg);
172*26326Ssam 			break;
173*26326Ssam 
174*26326Ssam 		case AUTOINCDEF:
175*26326Ssam 			if ((mode&0xf) == 0xf) {
176*26326Ssam 				printf("*$");
177*26326Ssam 				argval = printdisp(addr, 4, reg, amode);
178*26326Ssam 				addr += 4;
179*26326Ssam 			} else
180*26326Ssam 				printf("*(%s)+", reg);
181*26326Ssam 			break;
182*26326Ssam 
183*26326Ssam 		case BYTEDISP:
184*26326Ssam 			argval = printdisp(addr, 1, reg, amode);
185*26326Ssam 			addr += 1;
186*26326Ssam 			break;
187*26326Ssam 
188*26326Ssam 		case BYTEDISPDEF:
189*26326Ssam 			printf("*");
190*26326Ssam 			argval = printdisp(addr, 1, reg, amode);
191*26326Ssam 			addr += 1;
192*26326Ssam 			break;
193*26326Ssam 
194*26326Ssam 		case WORDDISP:
195*26326Ssam 			argval = printdisp(addr, 2, reg, amode);
196*26326Ssam 			addr += 2;
197*26326Ssam 			break;
198*26326Ssam 
199*26326Ssam 		case WORDDISPDEF:
200*26326Ssam 			printf("*");
201*26326Ssam 			argval = printdisp(addr, 2, reg, amode);
202*26326Ssam 			addr += 2;
203*26326Ssam 			break;
204*26326Ssam 
205*26326Ssam 		case LONGDISP:
206*26326Ssam 			argval = printdisp(addr, 4, reg, amode);
207*26326Ssam 			addr += 4;
208*26326Ssam 			break;
209*26326Ssam 
210*26326Ssam 		case LONGDISPDEF:
211*26326Ssam 			printf("*");
212*26326Ssam 			argval = printdisp(addr, 4, reg, amode);
213*26326Ssam 			addr += 4;
214*26326Ssam 			break;
215*26326Ssam 		}
216*26326Ssam 	}
217*26326Ssam 	if (ins == O_CASEL)
218*26326Ssam 		for (argno = 0; argno <= argval; argno++) {
219*26326Ssam 			iread(&offset, addr, sizeof(offset));
220*26326Ssam 			printf("\n\t\t%d", offset);
221*26326Ssam 			addr += 2;
222*26326Ssam 		}
223*26326Ssam 	printf("\n");
224*26326Ssam 	return (addr);
225*26326Ssam }
226*26326Ssam 
227*26326Ssam /*
228*26326Ssam  * Print the displacement of an instruction that uses displacement
229*26326Ssam  * addressing.
230*26326Ssam  */
231*26326Ssam private int printdisp(addr, nbytes, reg, mode)
232*26326Ssam 	Address addr;
233*26326Ssam 	int nbytes;
234*26326Ssam 	char *reg;
235*26326Ssam 	int mode;
236*26326Ssam {
237*26326Ssam 	char byte;
238*26326Ssam 	short hword;
239*26326Ssam 	int argval;
240*26326Ssam 	Symbol f;
241*26326Ssam 
242*26326Ssam 	switch (nbytes) {
243*26326Ssam 
244*26326Ssam 	case 1:
245*26326Ssam 		iread(&byte, addr, sizeof(byte));
246*26326Ssam 		argval = byte;
247*26326Ssam 		break;
248*26326Ssam 
249*26326Ssam 	case 2:
250*26326Ssam 		iread(&hword, addr, sizeof(hword));
251*26326Ssam 		argval = hword;
252*26326Ssam 		break;
253*26326Ssam 
254*26326Ssam 	case 4:
255*26326Ssam 		iread(&argval, addr, sizeof(argval));
256*26326Ssam 		break;
257*26326Ssam 	}
258*26326Ssam 	if (reg == regname[PROGCTR] && mode >= BYTEDISP)
259*26326Ssam 		argval += addr + nbytes;
260*26326Ssam 	if (reg == regname[PROGCTR]) {
261*26326Ssam 		f = whatblock((Address) argval + 2);
262*26326Ssam 		if (codeloc(f) == argval + 2)
263*26326Ssam 			printf("%s", symname(f));
264*26326Ssam 		else
265*26326Ssam 			printf("%x", argval);
266*26326Ssam 	} else {
267*26326Ssam 		if (varIsSet("$hexoffsets")) {
268*26326Ssam 			if (argval < 0)
269*26326Ssam 				printf("-%x(%s)", -(argval), reg);
270*26326Ssam 			else
271*26326Ssam 				printf("%x(%s)", argval, reg);
272*26326Ssam 		} else
273*26326Ssam 			printf("%d(%s)", argval, reg);
274*26326Ssam 	}
275*26326Ssam 	return (argval);
276*26326Ssam }
277*26326Ssam 
278*26326Ssam /*
279*26326Ssam  * Print the contents of the addresses within the given range
280*26326Ssam  * according to the given format.
281*26326Ssam  */
282*26326Ssam typedef struct {
283*26326Ssam 	String	name;
284*26326Ssam 	String	printfstring;
285*26326Ssam 	int	length;
286*26326Ssam } Format;
287*26326Ssam 
288*26326Ssam private Format fmt[] = {
289*26326Ssam 	{ "d", " %d", sizeof(short) },
290*26326Ssam 	{ "D", " %ld", sizeof(long) },
291*26326Ssam 	{ "o", " %o", sizeof(short) },
292*26326Ssam 	{ "O", " %lo", sizeof(long) },
293*26326Ssam 	{ "x", " %04x", sizeof(short) },
294*26326Ssam 	{ "X", " %08x", sizeof(long) },
295*26326Ssam 	{ "b", " \\%o", sizeof(char) },
296*26326Ssam 	{ "c", " '%c'", sizeof(char) },
297*26326Ssam 	{ "s", "%c", sizeof(char) },
298*26326Ssam 	{ "f", " %f", sizeof(float) },
299*26326Ssam 	{ "g", " %g", sizeof(double) },
300*26326Ssam 	{ nil, nil, 0 }
301*26326Ssam };
302*26326Ssam 
303*26326Ssam private Format *findformat(s)
304*26326Ssam 	String s;
305*26326Ssam {
306*26326Ssam 	register Format *f;
307*26326Ssam 
308*26326Ssam 	for (f = &fmt[0]; f->name != nil && !streq(f->name, s); f++)
309*26326Ssam 		;
310*26326Ssam 	if (f->name == nil)
311*26326Ssam 		error("bad print format \"%s\"", s);
312*26326Ssam 	return (f);
313*26326Ssam }
314*26326Ssam 
315*26326Ssam public Address printdata(lowaddr, highaddr, format)
316*26326Ssam 	Address lowaddr;
317*26326Ssam 	Address highaddr;
318*26326Ssam 	String format;
319*26326Ssam {
320*26326Ssam 	register int n;
321*26326Ssam 	register Address addr;
322*26326Ssam 	register Format *f;
323*26326Ssam 	int value;
324*26326Ssam 
325*26326Ssam 	if (lowaddr > highaddr)
326*26326Ssam 		error("first address larger than second");
327*26326Ssam 	f = findformat(format);
328*26326Ssam 	n = 0;
329*26326Ssam 	value = 0;
330*26326Ssam 	for (addr = lowaddr; addr <= highaddr; addr += f->length) {
331*26326Ssam 		if (n == 0)
332*26326Ssam 			printf("%08x: ", addr);
333*26326Ssam 		dread(&value, addr, f->length);
334*26326Ssam 		printf(f->printfstring, value);
335*26326Ssam 		++n;
336*26326Ssam 		if (n >= (16 div f->length)) {
337*26326Ssam 			putchar('\n');
338*26326Ssam 			n = 0;
339*26326Ssam 		}
340*26326Ssam 	}
341*26326Ssam 	if (n != 0)
342*26326Ssam 		putchar('\n');
343*26326Ssam 	prtaddr = addr;
344*26326Ssam 	return (addr);
345*26326Ssam }
346*26326Ssam 
347*26326Ssam /*
348*26326Ssam  * The other approach is to print n items starting with a given address.
349*26326Ssam  */
350*26326Ssam 
351*26326Ssam public printndata(count, startaddr, format)
352*26326Ssam int count;
353*26326Ssam Address startaddr;
354*26326Ssam String format;
355*26326Ssam {
356*26326Ssam 	register int i, n;
357*26326Ssam 	register Address addr;
358*26326Ssam 	register Format *f;
359*26326Ssam 	register Boolean isstring;
360*26326Ssam 	char c;
361*26326Ssam 	union {
362*26326Ssam 		char	charv;
363*26326Ssam 		short	shortv;
364*26326Ssam 		int	intv;
365*26326Ssam 		float	floatv;
366*26326Ssam 		double	doublev;
367*26326Ssam 	} value;
368*26326Ssam 
369*26326Ssam 	if (count <= 0)
370*26326Ssam 		error("non-positive repetition count");
371*26326Ssam 	f = findformat(format);
372*26326Ssam 	isstring = (Boolean) streq(f->name, "s");
373*26326Ssam 	n = 0;
374*26326Ssam 	addr = startaddr;
375*26326Ssam 	value.intv = 0;
376*26326Ssam 	for (i = 0; i < count; i++) {
377*26326Ssam 		if (n == 0)
378*26326Ssam 			printf("%08x: ", addr);
379*26326Ssam 		if (isstring) {
380*26326Ssam 			putchar('"');
381*26326Ssam 			dread(&c, addr, sizeof(char));
382*26326Ssam 			while (c != '\0') {
383*26326Ssam 				printchar(c);
384*26326Ssam 				++addr;
385*26326Ssam 				dread(&c, addr, sizeof(char));
386*26326Ssam 			}
387*26326Ssam 			putchar('"');
388*26326Ssam 			putchar('\n');
389*26326Ssam 			n = 0;
390*26326Ssam 			addr += sizeof(String);
391*26326Ssam 			continue;
392*26326Ssam 		}
393*26326Ssam 		dread(&value, addr, f->length);
394*26326Ssam 		printf(f->printfstring, value);
395*26326Ssam 		++n;
396*26326Ssam 		if (n >= (16 div f->length)) {
397*26326Ssam 			putchar('\n');
398*26326Ssam 			n = 0;
399*26326Ssam 		}
400*26326Ssam 		addr += f->length;
401*26326Ssam 	}
402*26326Ssam 	if (n != 0)
403*26326Ssam 		putchar('\n');
404*26326Ssam 	prtaddr = addr;
405*26326Ssam }
406*26326Ssam 
407*26326Ssam /*
408*26326Ssam  * Print out a value according to the given format.
409*26326Ssam  */
410*26326Ssam public printvalue(v, format)
411*26326Ssam 	long v;
412*26326Ssam 	String format;
413*26326Ssam {
414*26326Ssam 	Format *f;
415*26326Ssam 	char *p, *q;
416*26326Ssam 
417*26326Ssam 	f = findformat(format);
418*26326Ssam 	if (streq(f->name, "s")) {
419*26326Ssam 		putchar('"');
420*26326Ssam 		for (p = (char *) &v, q = p + sizeof(v); p < q; ++p)
421*26326Ssam 			printchar(*p);
422*26326Ssam 		putchar('"');
423*26326Ssam 	} else
424*26326Ssam 		printf(f->printfstring, v);
425*26326Ssam 	putchar('\n');
426*26326Ssam }
427*26326Ssam 
428*26326Ssam /*
429*26326Ssam  * Print out an execution time error.
430*26326Ssam  * Assumes the source position of the error has been calculated.
431*26326Ssam  *
432*26326Ssam  * Have to check if the -r option was specified; if so then
433*26326Ssam  * the object file information hasn't been read in yet.
434*26326Ssam  */
435*26326Ssam public printerror()
436*26326Ssam {
437*26326Ssam 	extern Integer sys_nsig;
438*26326Ssam 	extern String sys_siglist[];
439*26326Ssam 	integer err;
440*26326Ssam 
441*26326Ssam 	if (isfinished(process)) {
442*26326Ssam 		err = exitcode(process);
443*26326Ssam 		if (err) {
444*26326Ssam 			printf("\"%s\" terminated abnormally (exit code %d)\n",
445*26326Ssam 			    objname, err);
446*26326Ssam 			erecover();
447*26326Ssam 		} else
448*26326Ssam 			printf("\"%s\" terminated normally\n", objname);
449*26326Ssam 	}
450*26326Ssam 	if (runfirst) {
451*26326Ssam 		fprintf(stderr, "Entering debugger ...\n");
452*26326Ssam 		init();
453*26326Ssam 	}
454*26326Ssam 	err = errnum(process);
455*26326Ssam 	putchar('\n');
456*26326Ssam 	printsig(err);
457*26326Ssam 	putchar(' ');
458*26326Ssam 	printloc();
459*26326Ssam 	putchar('\n');
460*26326Ssam 	if (curline > 0)
461*26326Ssam 		printlines(curline, curline);
462*26326Ssam 	else
463*26326Ssam 		printinst(pc, pc);
464*26326Ssam 	erecover();
465*26326Ssam }
466*26326Ssam 
467*26326Ssam /*
468*26326Ssam  * Print out a signal.
469*26326Ssam  */
470*26326Ssam private String illinames[] = {
471*26326Ssam 	"reserved addressing fault",
472*26326Ssam 	"priviliged instruction fault",
473*26326Ssam 	"reserved operand fault"
474*26326Ssam };
475*26326Ssam #define	NILLINAMES	(sizeof (illinames) / sizeof (illinames[0]))
476*26326Ssam 
477*26326Ssam private String fpenames[] = {
478*26326Ssam 	nil,
479*26326Ssam 	"integer overflow trap",
480*26326Ssam 	"integer divide by zero trap",
481*26326Ssam 	"floating point divide by zero trap",
482*26326Ssam 	"floating point overflow trap",
483*26326Ssam 	"floating point underflow trap",
484*26326Ssam };
485*26326Ssam #define	NFPENAMES	(sizeof (fpenames) / sizeof (fpenames[0]))
486*26326Ssam 
487*26326Ssam public printsig(signo)
488*26326Ssam integer signo;
489*26326Ssam {
490*26326Ssam 	integer code;
491*26326Ssam 
492*26326Ssam 	if (signo < 0 or signo > sys_nsig)
493*26326Ssam 		printf("[signal %d]", signo);
494*26326Ssam 	else
495*26326Ssam 		printf("%s", sys_siglist[signo]);
496*26326Ssam 	code = errcode(process);
497*26326Ssam 	if (signo == SIGILL)
498*26326Ssam 		if (code >= 0 && code < NILLINAMES)
499*26326Ssam 			printf(" (%s)", illinames[code]);
500*26326Ssam 	if (signo == SIGFPE)
501*26326Ssam 		if (code > 0 and code < NFPENAMES)
502*26326Ssam 			printf(" (%s)", fpenames[code]);
503*26326Ssam }
504*26326Ssam 
505*26326Ssam /*
506*26326Ssam  * Note the termination of the program.  We do this so as to avoid
507*26326Ssam  * having the process exit, which would make the values of variables
508*26326Ssam  * inaccessible.  We do want to flush all output buffers here,
509*26326Ssam  * otherwise it'll never get done.
510*26326Ssam  */
511*26326Ssam public endprogram()
512*26326Ssam {
513*26326Ssam 	Integer exitcode;
514*26326Ssam 
515*26326Ssam 	stepto(nextaddr(pc, true));
516*26326Ssam 	printnews();
517*26326Ssam 	exitcode = argn(1, nil);
518*26326Ssam 	if (exitcode != 0)
519*26326Ssam 		printf("\nexecution completed (exit code %d)\n", exitcode);
520*26326Ssam 	else
521*26326Ssam 		printf("\nexecution completed\n");
522*26326Ssam 	getsrcpos();
523*26326Ssam 	erecover();
524*26326Ssam }
525*26326Ssam 
526*26326Ssam private Address getcall();
527*26326Ssam /*
528*26326Ssam  * Single step the machine a source line (or instruction if "inst_tracing"
529*26326Ssam  * is true).  If "isnext" is true, skip over procedure calls.
530*26326Ssam  */
531*26326Ssam public dostep(isnext)
532*26326Ssam 	Boolean isnext;
533*26326Ssam {
534*26326Ssam 	register Address addr;
535*26326Ssam 	register Lineno line;
536*26326Ssam 	String filename;
537*26326Ssam 	Address startaddr;
538*26326Ssam 
539*26326Ssam 	startaddr = pc;
540*26326Ssam 	addr = nextaddr(pc, isnext);
541*26326Ssam 	if (!inst_tracing && nlhdr.nlines != 0) {
542*26326Ssam 		line = linelookup(addr);
543*26326Ssam 		for (; line == 0; line = linelookup(addr))
544*26326Ssam 			addr = nextaddr(addr, isnext);
545*26326Ssam 		curline = line;
546*26326Ssam 	} else
547*26326Ssam 		curline = 0;
548*26326Ssam 	stepto(addr);
549*26326Ssam 	filename = srcfilename(addr);
550*26326Ssam 	setsource(filename);
551*26326Ssam }
552*26326Ssam 
553*26326Ssam private Address findnextaddr();
554*26326Ssam /*
555*26326Ssam  * Compute the next address that will be executed from the given one.
556*26326Ssam  * If "isnext" is true then consider a procedure call as straight line code.
557*26326Ssam  *
558*26326Ssam  * We must unfortunately do much of the same work that is necessary
559*26326Ssam  * to print instructions.  In addition we have to deal with branches.
560*26326Ssam  * Unconditional branches we just follow, for conditional branches
561*26326Ssam  * we continue execution to the current location and then single step
562*26326Ssam  * the machine.  We assume that the last argument in an instruction
563*26326Ssam  * that branches is the branch address (or relative offset).
564*26326Ssam  */
565*26326Ssam public Address nextaddr(startaddr, isnext)
566*26326Ssam 	Address startaddr;
567*26326Ssam 	boolean isnext;
568*26326Ssam {
569*26326Ssam 	Address addr;
570*26326Ssam 
571*26326Ssam 	addr = usignal(process);
572*26326Ssam 	if (addr == 0 or addr == 1)
573*26326Ssam 		addr = findnextaddr(startaddr, isnext);
574*26326Ssam 	return (addr);
575*26326Ssam }
576*26326Ssam 
577*26326Ssam /*
578*26326Ssam  * Determine if it's ok to skip function f entered by instruction ins.
579*26326Ssam  * If so, we're going to compute the return address and step to it.
580*26326Ssam  */
581*26326Ssam private boolean skipfunc(ins, f)
582*26326Ssam 	Opcode ins;
583*26326Ssam 	Symbol f;
584*26326Ssam {
585*26326Ssam 
586*26326Ssam 	return ((boolean) (!inst_tracing && nlhdr.nlines != 0 &&
587*26326Ssam 		nosource(curfunc) && canskip(curfunc)));
588*26326Ssam }
589*26326Ssam 
590*26326Ssam private Address findnextaddr(startaddr, isnext)
591*26326Ssam 	Address startaddr;
592*26326Ssam 	Boolean isnext;
593*26326Ssam {
594*26326Ssam 	register Address addr;
595*26326Ssam 	Optab *op;
596*26326Ssam 	Opcode ins;
597*26326Ssam 	unsigned char mode;
598*26326Ssam 	int argtype, amode, argno, argval, nib;
599*26326Ssam 	String r;
600*26326Ssam 	Boolean indexf;
601*26326Ssam 	enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
602*26326Ssam 
603*26326Ssam 	argval = 0;
604*26326Ssam 	indexf = false;
605*26326Ssam 	addr = startaddr;
606*26326Ssam 	iread(&ins, addr, sizeof(ins));
607*26326Ssam 	switch (ins) {
608*26326Ssam 
609*26326Ssam 	case O_CALLF:
610*26326Ssam 	case O_CALLS:
611*26326Ssam 		addrstatus = KNOWN;
612*26326Ssam 		stepto(addr);
613*26326Ssam 		pstep(process, DEFSIG);
614*26326Ssam 		addr = reg(PROGCTR);
615*26326Ssam 		pc = addr;
616*26326Ssam 		setcurfunc(whatblock(pc));
617*26326Ssam 		if (not isbperr()) {
618*26326Ssam 			printstatus();
619*26326Ssam 			/* NOTREACHED */
620*26326Ssam 		}
621*26326Ssam 		bpact();
622*26326Ssam 		if (isnext or skipfunc(ins, curfunc)) {
623*26326Ssam 			addrstatus = KNOWN;
624*26326Ssam 			addr = return_addr();
625*26326Ssam 			stepto(addr);
626*26326Ssam 			bpact();
627*26326Ssam 		} else
628*26326Ssam 			callnews(/* iscall = */ true);
629*26326Ssam 		break;
630*26326Ssam 
631*26326Ssam 	case O_RET:
632*26326Ssam 		addrstatus = KNOWN;
633*26326Ssam 		stepto(addr);
634*26326Ssam 		callnews(/* iscall = */ false);
635*26326Ssam 		pstep(process, DEFSIG);
636*26326Ssam 		addr = reg(PROGCTR);
637*26326Ssam 		pc = addr;
638*26326Ssam 		if (not isbperr())
639*26326Ssam 			printstatus();
640*26326Ssam 		bpact();
641*26326Ssam 		break;
642*26326Ssam 
643*26326Ssam 	case O_BRB:
644*26326Ssam 	case O_BRW:
645*26326Ssam 	case O_JMP:
646*26326Ssam 	case O_BBSSI:
647*26326Ssam 	case O_BCC:
648*26326Ssam 	case O_BCS:
649*26326Ssam 	case O_BEQL:
650*26326Ssam 	case O_BGEQ:
651*26326Ssam 	case O_BGTR:
652*26326Ssam 	case O_BGTRU:
653*26326Ssam 	case O_BLEQ:
654*26326Ssam 	case O_BLEQU:
655*26326Ssam 	case O_BLSS:
656*26326Ssam 	case O_BNEQ:
657*26326Ssam 	case O_BVC:
658*26326Ssam 	case O_BVS:
659*26326Ssam 	case O_CASEL:
660*26326Ssam 	case O_AOBLSS:
661*26326Ssam 	case O_AOBLEQ:
662*26326Ssam 		addrstatus = KNOWN;
663*26326Ssam 		stepto(addr);
664*26326Ssam 		pstep(process, DEFSIG);
665*26326Ssam 		addr = reg(PROGCTR);
666*26326Ssam 		pc = addr;
667*26326Ssam 		if (not isbperr())
668*26326Ssam 			printstatus();
669*26326Ssam 		break;
670*26326Ssam 
671*26326Ssam 	default:
672*26326Ssam 		addrstatus = SEQUENTIAL;
673*26326Ssam 		break;
674*26326Ssam 	}
675*26326Ssam 	if (addrstatus == KNOWN)
676*26326Ssam 		return (addr);
677*26326Ssam 	addr += 1;
678*26326Ssam 	op = ioptab[ins];
679*26326Ssam 	for (argno = 0; argno < op->numargs; argno++) {
680*26326Ssam 		if (indexf == true)
681*26326Ssam 			indexf = false;
682*26326Ssam 		argtype = op->argtype[argno];
683*26326Ssam 		if (is_branch_disp(argtype))
684*26326Ssam 			mode = 0xAF + (typelen(argtype) << 5);
685*26326Ssam 		else
686*26326Ssam 			iread(&mode, addr, sizeof(mode)), addr += 1;
687*26326Ssam 		r = regname[regnm(mode)];
688*26326Ssam 		amode = addrmode(mode);
689*26326Ssam 		switch (amode) {
690*26326Ssam 
691*26326Ssam 		case LITSHORT:
692*26326Ssam 		case LITUPTO31:
693*26326Ssam 		case LITUPTO47:
694*26326Ssam 		case LITUPTO63:
695*26326Ssam 			argval = mode;
696*26326Ssam 			break;
697*26326Ssam 
698*26326Ssam 		case INDEX:
699*26326Ssam 			indexf = true;
700*26326Ssam 			--argno;
701*26326Ssam 			break;
702*26326Ssam 
703*26326Ssam 		case REG:
704*26326Ssam 		case REGDEF:
705*26326Ssam 		case AUTODEC:
706*26326Ssam 			break;
707*26326Ssam 
708*26326Ssam 		case AUTOINC:
709*26326Ssam 			nib = mode & 0xf;
710*26326Ssam 			if (nib == 0xf || nib == 8 || nib == 9) {
711*26326Ssam 				int size = (mode&03)+1;
712*26326Ssam 
713*26326Ssam 				argval = getdisp(addr, size,
714*26326Ssam 				    regname[PROGCTR], amode);
715*26326Ssam 				addr += size;
716*26326Ssam 			}
717*26326Ssam 			break;
718*26326Ssam 
719*26326Ssam 		case AUTOINCDEF:
720*26326Ssam 			if ((mode&0xf) != 0xf)
721*26326Ssam 				break;
722*26326Ssam 			argval = getdisp(addr, 4, r, amode);
723*26326Ssam 			addr += 4;
724*26326Ssam 			break;
725*26326Ssam 
726*26326Ssam 		case BYTEDISP:
727*26326Ssam 		case BYTEDISPDEF:
728*26326Ssam 			argval = getdisp(addr, 1, r, amode);
729*26326Ssam 			addr += 1;
730*26326Ssam 			break;
731*26326Ssam 
732*26326Ssam 		case WORDDISP:
733*26326Ssam 		case WORDDISPDEF:
734*26326Ssam 			argval = getdisp(addr, 2, r, amode);
735*26326Ssam 			addr += 2;
736*26326Ssam 			break;
737*26326Ssam 
738*26326Ssam 		case LONGDISP:
739*26326Ssam 		case LONGDISPDEF:
740*26326Ssam 			argval = getdisp(addr, 4, r, amode);
741*26326Ssam 			addr += 4;
742*26326Ssam 			break;
743*26326Ssam 		}
744*26326Ssam 	}
745*26326Ssam 	if (ins == O_CALLF or ins == O_CALLS)
746*26326Ssam 		argval += 2;
747*26326Ssam 	if (addrstatus == BRANCH)
748*26326Ssam 		addr = argval;
749*26326Ssam 	return (addr);
750*26326Ssam }
751*26326Ssam 
752*26326Ssam /*
753*26326Ssam  * Get the displacement of an instruction that uses displacement addressing.
754*26326Ssam  */
755*26326Ssam private int getdisp(addr, nbytes, reg, mode)
756*26326Ssam 	Address addr;
757*26326Ssam 	int nbytes;
758*26326Ssam 	String reg;
759*26326Ssam 	int mode;
760*26326Ssam {
761*26326Ssam 	char byte;
762*26326Ssam 	short hword;
763*26326Ssam 	int argval;
764*26326Ssam 
765*26326Ssam 	switch (nbytes) {
766*26326Ssam 
767*26326Ssam 	case 1:
768*26326Ssam 		iread(&byte, addr, sizeof(byte));
769*26326Ssam 		argval = byte;
770*26326Ssam 		break;
771*26326Ssam 
772*26326Ssam 	case 2:
773*26326Ssam 		iread(&hword, addr, sizeof(hword));
774*26326Ssam 		argval = hword;
775*26326Ssam 		break;
776*26326Ssam 
777*26326Ssam 	case 4:
778*26326Ssam 		iread(&argval, addr, sizeof(argval));
779*26326Ssam 		break;
780*26326Ssam 	}
781*26326Ssam 	if (reg == regname[PROGCTR] && mode >= BYTEDISP)
782*26326Ssam 		argval += addr + nbytes;
783*26326Ssam 	return (argval);
784*26326Ssam }
785*26326Ssam 
786*26326Ssam #define BP_OP	   	O_BPT	   /* breakpoint trap */
787*26326Ssam #define BP_ERRNO	SIGTRAP	 /* signal received at a breakpoint */
788*26326Ssam 
789*26326Ssam /*
790*26326Ssam  * Setting a breakpoint at a location consists of saving
791*26326Ssam  * the word at the location and poking a BP_OP there.
792*26326Ssam  *
793*26326Ssam  * We save the locations and words on a list for use in unsetting.
794*26326Ssam  */
795*26326Ssam typedef struct Savelist *Savelist;
796*26326Ssam 
797*26326Ssam struct Savelist {
798*26326Ssam 	Address location;
799*26326Ssam 	Byte save;
800*26326Ssam 	Byte refcount;
801*26326Ssam 	Savelist link;
802*26326Ssam };
803*26326Ssam 
804*26326Ssam private Savelist savelist;
805*26326Ssam 
806*26326Ssam /*
807*26326Ssam  * Set a breakpoint at the given address.  Only save the word there
808*26326Ssam  * if it's not already a breakpoint.
809*26326Ssam  */
810*26326Ssam public setbp(addr)
811*26326Ssam 	Address addr;
812*26326Ssam {
813*26326Ssam 	Byte w, save;
814*26326Ssam 	register Savelist newsave, s;
815*26326Ssam 
816*26326Ssam 	for (s = savelist; s != nil; s = s->link)
817*26326Ssam 		if (s->location == addr) {
818*26326Ssam 			s->refcount++;
819*26326Ssam 			return;
820*26326Ssam 		}
821*26326Ssam 	iread(&save, addr, sizeof(save));
822*26326Ssam 	newsave = new(Savelist);
823*26326Ssam 	newsave->location = addr;
824*26326Ssam 	newsave->save = save;
825*26326Ssam 	newsave->refcount = 1;
826*26326Ssam 	newsave->link = savelist;
827*26326Ssam 	savelist = newsave;
828*26326Ssam 	w = BP_OP;
829*26326Ssam 	iwrite(&w, addr, sizeof(w));
830*26326Ssam }
831*26326Ssam 
832*26326Ssam /*
833*26326Ssam  * Unset a breakpoint; unfortunately we have to search the SAVELIST
834*26326Ssam  * to find the saved value.  The assumption is that the SAVELIST will
835*26326Ssam  * usually be quite small.
836*26326Ssam  */
837*26326Ssam public unsetbp(addr)
838*26326Ssam Address addr;
839*26326Ssam {
840*26326Ssam 	register Savelist s, prev;
841*26326Ssam 
842*26326Ssam 	prev = nil;
843*26326Ssam 	for (s = savelist; s != nil; s = s->link) {
844*26326Ssam 		if (s->location == addr) {
845*26326Ssam 			iwrite(&s->save, addr, sizeof(s->save));
846*26326Ssam 			s->refcount--;
847*26326Ssam 			if (s->refcount == 0) {
848*26326Ssam 				if (prev == nil)
849*26326Ssam 					savelist = s->link;
850*26326Ssam 				else
851*26326Ssam 					prev->link = s->link;
852*26326Ssam 				dispose(s);
853*26326Ssam 			}
854*26326Ssam 			return;
855*26326Ssam 		}
856*26326Ssam 		prev = s;
857*26326Ssam 	}
858*26326Ssam 	panic("unsetbp: couldn't find address %d", addr);
859*26326Ssam }
860*26326Ssam 
861*26326Ssam /*
862*26326Ssam  * Enter a procedure by creating and executing a call instruction.
863*26326Ssam  */
864*26326Ssam 
865*26326Ssam #define CALLSIZE 7	/* size of call instruction */
866*26326Ssam 
867*26326Ssam public beginproc(p, argc)
868*26326Ssam 	Symbol p;
869*26326Ssam 	Integer argc;
870*26326Ssam {
871*26326Ssam 	char save[CALLSIZE];
872*26326Ssam 	struct {
873*26326Ssam 		Opcode op;
874*26326Ssam 		unsigned char numargs;
875*26326Ssam 		unsigned char mode;
876*26326Ssam 		char addr[sizeof(long)];	/* unaligned long */
877*26326Ssam 	} call;
878*26326Ssam 	long dest;
879*26326Ssam 
880*26326Ssam error("Can't do a \"call\" right now...sorry");	/* XXX */
881*26326Ssam 	if (4*argc+4 > 256)
882*26326Ssam 		error("too many parameters (max %d)", 256/4 - 1);
883*26326Ssam 	pc = 2;
884*26326Ssam 	iread(save, pc, sizeof(save));
885*26326Ssam 	call.op = O_CALLF;
886*26326Ssam 	call.numargs = 4*argc+4;
887*26326Ssam 	call.mode = 0xef;			/* longword relative */
888*26326Ssam 	dest = codeloc(p) - 2 - (pc + CALLSIZE);
889*26326Ssam 	mov(&dest, call.addr, sizeof(call.addr));
890*26326Ssam 	iwrite(&call, pc, sizeof(call));
891*26326Ssam 	setreg(PROGCTR, pc);
892*26326Ssam 	pstep(process, DEFSIG);
893*26326Ssam 	iwrite(save, pc, sizeof(save));
894*26326Ssam 	pc = reg(PROGCTR);
895*26326Ssam 	if (not isbperr())
896*26326Ssam 		printstatus();
897*26326Ssam }
898