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