xref: /csrg-svn/old/dbx/vax.c (revision 16932)
19668Slinton /* Copyright (c) 1982 Regents of the University of California */
29668Slinton 
3*16932Ssam static	char sccsid[] = "@(#)vax.c	1.11 (Berkeley) 08/12/84";
49668Slinton 
59668Slinton /*
69668Slinton  * Target machine dependent stuff.
79668Slinton  */
89668Slinton 
99668Slinton #include "defs.h"
109668Slinton #include "machine.h"
119668Slinton #include "process.h"
1216612Ssam #include "runtime.h"
139668Slinton #include "events.h"
149668Slinton #include "main.h"
159668Slinton #include "symbols.h"
169668Slinton #include "source.h"
179668Slinton #include "mappings.h"
189668Slinton #include "object.h"
199693Slinton #include "ops.h"
209668Slinton #include <signal.h>
219668Slinton 
229668Slinton #ifndef public
239668Slinton typedef unsigned int Address;
249668Slinton typedef unsigned char Byte;
259668Slinton typedef unsigned int Word;
269668Slinton 
279668Slinton #define NREG 16
289668Slinton 
299668Slinton #define ARGP 12
309668Slinton #define FRP 13
319668Slinton #define STKP 14
329668Slinton #define PROGCTR 15
339668Slinton 
349668Slinton #define BITSPERBYTE 8
359668Slinton #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
369668Slinton 
379668Slinton #define nargspassed(frame) argn(0, frame)
389668Slinton 
399668Slinton #include "source.h"
409668Slinton #include "symbols.h"
419668Slinton 
429668Slinton Address pc;
439668Slinton Address prtaddr;
449668Slinton 
459668Slinton #endif
469668Slinton 
479668Slinton private Address printop();
489668Slinton 
499668Slinton /*
509668Slinton  * Decode and print the instructions within the given address range.
519668Slinton  */
529668Slinton 
539668Slinton public printinst(lowaddr, highaddr)
549668Slinton Address lowaddr;
559668Slinton Address highaddr;
569668Slinton {
579668Slinton     register Address addr;
589668Slinton 
599668Slinton     for (addr = lowaddr; addr <= highaddr; ) {
609668Slinton 	addr = printop(addr);
619668Slinton     }
629668Slinton     prtaddr = addr;
639668Slinton }
649668Slinton 
659668Slinton /*
669668Slinton  * Another approach:  print n instructions starting at the given address.
679668Slinton  */
689668Slinton 
699668Slinton public printninst(count, addr)
709668Slinton int count;
719668Slinton Address addr;
729668Slinton {
739668Slinton     register Integer i;
749668Slinton     register Address newaddr;
759668Slinton 
769668Slinton     if (count <= 0) {
779668Slinton 	error("non-positive repetition count");
789668Slinton     } else {
799668Slinton 	newaddr = addr;
809668Slinton 	for (i = 0; i < count; i++) {
819668Slinton 	    newaddr = printop(newaddr);
829668Slinton 	}
839668Slinton 	prtaddr = newaddr;
849668Slinton     }
859668Slinton }
869668Slinton 
879668Slinton /*
889668Slinton  * Hacked version of adb's VAX instruction decoder.
899668Slinton  */
909668Slinton 
919668Slinton private Address printop(addr)
929668Slinton Address addr;
939668Slinton {
949668Slinton     Optab op;
959668Slinton     VaxOpcode ins;
969668Slinton     unsigned char mode;
979668Slinton     int argtype, amode, argno, argval;
989668Slinton     String reg;
999668Slinton     Boolean indexf;
1009668Slinton     short offset;
1019668Slinton 
1029668Slinton     argval = 0;
1039668Slinton     indexf = false;
1049668Slinton     printf("%08x  ", addr);
1059668Slinton     iread(&ins, addr, sizeof(ins));
1069668Slinton     addr += 1;
1079668Slinton     op = optab[ins];
1089668Slinton     printf("%s", op.iname);
1099668Slinton     for (argno = 0; argno < op.numargs; argno++) {
1109668Slinton 	if (indexf == true) {
1119668Slinton 	    indexf = false;
1129668Slinton 	} else if (argno == 0) {
1139668Slinton 	    printf("\t");
1149668Slinton 	} else {
1159668Slinton 	    printf(",");
1169668Slinton 	}
1179668Slinton 	argtype = op.argtype[argno];
1189668Slinton 	if (is_branch_disp(argtype)) {
1199668Slinton 	    mode = 0xAF + (typelen(argtype) << 5);
1209668Slinton 	} else {
1219668Slinton 	    iread(&mode, addr, sizeof(mode));
1229668Slinton 	    addr += 1;
1239668Slinton 	}
1249668Slinton 	reg = regname[regnm(mode)];
1259668Slinton 	amode = addrmode(mode);
1269668Slinton 	switch (amode) {
1279668Slinton 	    case LITSHORT:
1289668Slinton 	    case LITUPTO31:
1299668Slinton 	    case LITUPTO47:
1309668Slinton 	    case LITUPTO63:
1319668Slinton 		if (typelen(argtype) == TYPF || typelen(argtype) ==TYPD)
1329668Slinton 		    printf("$%s", fltimm[mode]);
1339668Slinton 		else
1349668Slinton 		    printf("$%x", mode);
1359668Slinton 		argval = mode;
1369668Slinton 		break;
1379668Slinton 
1389668Slinton 	    case INDEX:
1399668Slinton 		printf("[%s]", reg);
1409668Slinton 		indexf = true;
1419668Slinton 		argno--;
1429668Slinton 		break;
1439668Slinton 
1449668Slinton 	    case REG:
1459668Slinton 		printf("%s", reg);
1469668Slinton 		break;
1479668Slinton 
1489668Slinton 	    case REGDEF:
1499668Slinton 		printf("(%s)", reg);
1509668Slinton 		break;
1519668Slinton 
1529668Slinton 	    case AUTODEC:
1539668Slinton 		printf("-(%s)", reg);
1549668Slinton 		break;
1559668Slinton 
1569668Slinton 	    case AUTOINC:
1579668Slinton 		if (reg != regname[PROGCTR]) {
1589668Slinton 		    printf("(%s)+", reg);
1599668Slinton 		} else {
1609668Slinton 		    printf("$");
1619668Slinton 		    switch (typelen(argtype)) {
1629668Slinton 			case TYPB:
1639668Slinton 			    argval = printdisp(addr, 1, reg, amode);
1649668Slinton 			    addr += 1;
1659668Slinton 			    break;
1669668Slinton 
1679668Slinton 			case TYPW:
1689668Slinton 			    argval = printdisp(addr, 2, reg, amode);
1699668Slinton 			    addr += 2;
1709668Slinton 			    break;
1719668Slinton 
1729668Slinton 			case TYPL:
1739668Slinton 			    argval = printdisp(addr, 4, reg, amode);
1749668Slinton 			    addr += 4;
1759668Slinton 			    break;
1769668Slinton 
1779668Slinton 			case TYPF:
1789668Slinton 			    iread(&argval, addr, sizeof(argval));
1799668Slinton 			    printf("%06x", argval);
1809668Slinton 			    addr += 4;
1819668Slinton 			    break;
1829668Slinton 
1839668Slinton 			case TYPQ:
1849668Slinton 			case TYPD:
1859668Slinton 			    iread(&argval, addr, sizeof(argval));
1869668Slinton 			    printf("%06x", argval);
1879668Slinton 			    iread(&argval, addr+4, sizeof(argval));
1889668Slinton 			    printf("%06x", argval);
1899668Slinton 			    addr += 8;
1909668Slinton 			    break;
1919668Slinton 		    }
1929668Slinton 		}
1939668Slinton 		break;
1949668Slinton 
1959668Slinton 	    case AUTOINCDEF:
1969668Slinton 		if (reg == regname[PROGCTR]) {
1979668Slinton 		    printf("*$");
1989668Slinton 		    argval = printdisp(addr, 4, reg, amode);
1999668Slinton 		    addr += 4;
2009668Slinton 		} else {
2019668Slinton 		    printf("*(%s)+", reg);
2029668Slinton 		}
2039668Slinton 		break;
2049668Slinton 
2059668Slinton 	    case BYTEDISP:
2069668Slinton 		argval = printdisp(addr, 1, reg, amode);
2079668Slinton 		addr += 1;
2089668Slinton 		break;
2099668Slinton 
2109668Slinton 	    case BYTEDISPDEF:
2119668Slinton 		printf("*");
2129668Slinton 		argval = printdisp(addr, 1, reg, amode);
2139668Slinton 		addr += 1;
2149668Slinton 		break;
2159668Slinton 
2169668Slinton 	    case WORDDISP:
2179668Slinton 		argval = printdisp(addr, 2, reg, amode);
2189668Slinton 		addr += 2;
2199668Slinton 		break;
2209668Slinton 
2219668Slinton 	    case WORDDISPDEF:
2229668Slinton 		printf("*");
2239668Slinton 		argval = printdisp(addr, 2, reg, amode);
2249668Slinton 		addr += 2;
2259668Slinton 		break;
2269668Slinton 
2279668Slinton 	    case LONGDISP:
2289668Slinton 		argval = printdisp(addr, 4, reg, amode);
2299668Slinton 		addr += 4;
2309668Slinton 		break;
2319668Slinton 
2329668Slinton 	    case LONGDISPDEF:
2339668Slinton 		printf("*");
2349668Slinton 		argval = printdisp(addr, 4, reg, amode);
2359668Slinton 		addr += 4;
2369668Slinton 		break;
2379668Slinton 	}
2389668Slinton     }
2399668Slinton     if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
2409668Slinton 	for (argno = 0; argno <= argval; argno++) {
2419668Slinton 	    iread(&offset, addr, sizeof(offset));
2429668Slinton 	    printf("\n\t\t%d", offset);
2439668Slinton 	    addr += 2;
2449668Slinton 	}
2459668Slinton     }
2469668Slinton     printf("\n");
2479668Slinton     return addr;
2489668Slinton }
2499668Slinton 
2509668Slinton /*
2519668Slinton  * Print the displacement of an instruction that uses displacement
2529668Slinton  * addressing.
2539668Slinton  */
2549668Slinton 
2559668Slinton private int printdisp(addr, nbytes, reg, mode)
2569668Slinton Address addr;
2579668Slinton int nbytes;
2589668Slinton char *reg;
2599668Slinton int mode;
2609668Slinton {
2619668Slinton     char byte;
2629668Slinton     short hword;
2639668Slinton     int argval;
26414338Slinton     Symbol f;
2659668Slinton 
2669668Slinton     switch (nbytes) {
2679668Slinton 	case 1:
2689668Slinton 	    iread(&byte, addr, sizeof(byte));
2699668Slinton 	    argval = byte;
2709668Slinton 	    break;
2719668Slinton 
2729668Slinton 	case 2:
2739668Slinton 	    iread(&hword, addr, sizeof(hword));
2749668Slinton 	    argval = hword;
2759668Slinton 	    break;
2769668Slinton 
2779668Slinton 	case 4:
2789668Slinton 	    iread(&argval, addr, sizeof(argval));
2799668Slinton 	    break;
2809668Slinton     }
2819668Slinton     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
2829668Slinton 	argval += addr + nbytes;
2839668Slinton     }
2849668Slinton     if (reg == regname[PROGCTR]) {
28514338Slinton 	f = whatblock((Address) argval + 2);
28614338Slinton 	if (codeloc(f) == argval + 2) {
28714338Slinton 	    printf("%s", symname(f));
28814338Slinton 	} else {
28914338Slinton 	    printf("%x", argval);
29014338Slinton 	}
2919668Slinton     } else {
2929668Slinton 	printf("%d(%s)", argval, reg);
2939668Slinton     }
2949668Slinton     return argval;
2959668Slinton }
2969668Slinton 
2979668Slinton /*
2989668Slinton  * Print the contents of the addresses within the given range
2999668Slinton  * according to the given format.
3009668Slinton  */
3019668Slinton 
3029668Slinton typedef struct {
3039668Slinton     String name;
3049668Slinton     String printfstring;
3059668Slinton     int length;
3069668Slinton } Format;
3079668Slinton 
3089668Slinton private Format fmt[] = {
3099668Slinton     { "d", " %d", sizeof(short) },
3109668Slinton     { "D", " %ld", sizeof(long) },
3119668Slinton     { "o", " %o", sizeof(short) },
3129668Slinton     { "O", " %lo", sizeof(long) },
3139668Slinton     { "x", " %04x", sizeof(short) },
3149668Slinton     { "X", " %08x", sizeof(long) },
3159668Slinton     { "b", " \\%o", sizeof(char) },
3169668Slinton     { "c", " '%c'", sizeof(char) },
3179668Slinton     { "s", "%c", sizeof(char) },
31814338Slinton     { "f", " %f", sizeof(float) },
3199668Slinton     { "g", " %g", sizeof(double) },
3209668Slinton     { nil, nil, 0 }
3219668Slinton };
3229668Slinton 
32311174Slinton private Format *findformat(s)
32411174Slinton String s;
32511174Slinton {
32611174Slinton     register Format *f;
32711174Slinton 
32811174Slinton     f = &fmt[0];
32911174Slinton     while (f->name != nil and not streq(f->name, s)) {
33011174Slinton 	++f;
33111174Slinton     }
33211174Slinton     if (f->name == nil) {
33311174Slinton 	error("bad print format \"%s\"", s);
33411174Slinton     }
33511174Slinton     return f;
33611174Slinton }
33711174Slinton 
3389668Slinton public Address printdata(lowaddr, highaddr, format)
3399668Slinton Address lowaddr;
3409668Slinton Address highaddr;
3419668Slinton String format;
3429668Slinton {
3439668Slinton     register int n;
3449668Slinton     register Address addr;
3459668Slinton     register Format *f;
3469668Slinton     int value;
3479668Slinton 
3489668Slinton     if (lowaddr > highaddr) {
3499668Slinton 	error("first address larger than second");
3509668Slinton     }
35111174Slinton     f = findformat(format);
3529668Slinton     n = 0;
3539668Slinton     value = 0;
3549668Slinton     for (addr = lowaddr; addr <= highaddr; addr += f->length) {
3559668Slinton 	if (n == 0) {
3569668Slinton 	    printf("%08x: ", addr);
3579668Slinton 	}
3589668Slinton 	dread(&value, addr, f->length);
3599668Slinton 	printf(f->printfstring, value);
3609668Slinton 	++n;
3619668Slinton 	if (n >= (16 div f->length)) {
3629668Slinton 	    putchar('\n');
3639668Slinton 	    n = 0;
3649668Slinton 	}
3659668Slinton     }
3669668Slinton     if (n != 0) {
3679668Slinton 	putchar('\n');
3689668Slinton     }
3699668Slinton     prtaddr = addr;
3709668Slinton     return addr;
3719668Slinton }
3729668Slinton 
3739668Slinton /*
3749668Slinton  * The other approach is to print n items starting with a given address.
3759668Slinton  */
3769668Slinton 
3779668Slinton public printndata(count, startaddr, format)
3789668Slinton int count;
3799668Slinton Address startaddr;
3809668Slinton String format;
3819668Slinton {
3829668Slinton     register int i, n;
3839668Slinton     register Address addr;
3849668Slinton     register Format *f;
3859668Slinton     register Boolean isstring;
38614338Slinton     char c;
38714338Slinton     union {
38814338Slinton 	char charv;
38914338Slinton 	short shortv;
39014338Slinton 	int intv;
39114338Slinton 	float floatv;
39214338Slinton 	double doublev;
39314338Slinton     } value;
3949668Slinton 
3959668Slinton     if (count <= 0) {
3969668Slinton 	error("non-positive repetition count");
3979668Slinton     }
39811174Slinton     f = findformat(format);
3999668Slinton     isstring = (Boolean) streq(f->name, "s");
4009668Slinton     n = 0;
4019668Slinton     addr = startaddr;
40214338Slinton     value.intv = 0;
4039668Slinton     for (i = 0; i < count; i++) {
4049668Slinton 	if (n == 0) {
4059668Slinton 	    printf("%08x: ", addr);
4069668Slinton 	}
4079668Slinton 	if (isstring) {
4089668Slinton 	    putchar('"');
40914338Slinton 	    dread(&c, addr, sizeof(char));
41014338Slinton 	    while (c != '\0') {
41114338Slinton 		printchar(c);
4129668Slinton 		++addr;
41314338Slinton 		dread(&c, addr, sizeof(char));
4149668Slinton 	    }
4159668Slinton 	    putchar('"');
4169668Slinton 	    putchar('\n');
4179668Slinton 	    n = 0;
4189668Slinton 	    addr += sizeof(String);
4199668Slinton 	} else {
4209668Slinton 	    dread(&value, addr, f->length);
4219668Slinton 	    printf(f->printfstring, value);
4229668Slinton 	    ++n;
4239668Slinton 	    if (n >= (16 div f->length)) {
4249668Slinton 		putchar('\n');
4259668Slinton 		n = 0;
4269668Slinton 	    }
4279668Slinton 	    addr += f->length;
4289668Slinton 	}
4299668Slinton     }
4309668Slinton     if (n != 0) {
4319668Slinton 	putchar('\n');
4329668Slinton     }
4339668Slinton     prtaddr = addr;
4349668Slinton }
4359668Slinton 
4369668Slinton /*
43711174Slinton  * Print out a value according to the given format.
43811174Slinton  */
43911174Slinton 
44011174Slinton public printvalue(v, format)
44111174Slinton long v;
44211174Slinton String format;
44311174Slinton {
44411174Slinton     Format *f;
44511174Slinton     char *p, *q;
44611174Slinton 
44711174Slinton     f = findformat(format);
44811174Slinton     if (streq(f->name, "s")) {
44911174Slinton 	putchar('"');
45011174Slinton 	p = (char *) &v;
45111174Slinton 	q = p + sizeof(v);
45211174Slinton 	while (p < q) {
45311174Slinton 	    printchar(*p);
45411174Slinton 	    ++p;
45511174Slinton 	}
45611174Slinton 	putchar('"');
45711174Slinton     } else {
45811174Slinton 	printf(f->printfstring, v);
45911174Slinton     }
46011174Slinton     putchar('\n');
46111174Slinton }
46211174Slinton 
46311174Slinton /*
4649668Slinton  * Print out an execution time error.
4659842Slinton  * Assumes the source position of the error has been calculated.
4669668Slinton  *
4679668Slinton  * Have to check if the -r option was specified; if so then
4689668Slinton  * the object file information hasn't been read in yet.
4699668Slinton  */
4709668Slinton 
4719668Slinton public printerror()
4729668Slinton {
4739668Slinton     extern Integer sys_nsig;
4749668Slinton     extern String sys_siglist[];
4759668Slinton     Integer err;
4769668Slinton 
4779668Slinton     if (isfinished(process)) {
478*16932Ssam 	err = exitcode(process);
479*16932Ssam 	printf("\"%s\" terminated", objname);
480*16932Ssam 	if (err)
481*16932Ssam 	    printf("abnormally (exit code %d)", err);
482*16932Ssam 	putchar('\n');
4839668Slinton 	erecover();
4849668Slinton     }
4859668Slinton     if (runfirst) {
4869668Slinton 	fprintf(stderr, "Entering debugger ...");
4879668Slinton 	init();
4889668Slinton 	fprintf(stderr, " type 'help' for help\n");
4899668Slinton     }
4909668Slinton     err = errnum(process);
4919668Slinton     putchar('\n');
492*16932Ssam     printsig(err);
493*16932Ssam     printloc();
494*16932Ssam     putchar('\n');
4959668Slinton     if (curline > 0) {
4969668Slinton 	printlines(curline, curline);
4979668Slinton     } else {
4989668Slinton 	printinst(pc, pc);
4999668Slinton     }
5009668Slinton     erecover();
5019668Slinton }
5029668Slinton 
503*16932Ssam private String illinames[] = {
504*16932Ssam 	"reserved addressing fault",
505*16932Ssam 	"priviliged instruction fault",
506*16932Ssam 	"reserved operand fault"
507*16932Ssam };
508*16932Ssam private String fpenames[] = {
509*16932Ssam 	nil,
510*16932Ssam 	"integer overflow trap",
511*16932Ssam 	"integer divide by zero trap",
512*16932Ssam 	"floating overflow trap",
513*16932Ssam 	"floating/decimal divide by zero trap",
514*16932Ssam 	"floating underflow trap",
515*16932Ssam 	"decimal overflow trap",
516*16932Ssam 	"subscript out of range trap",
517*16932Ssam 	"floating overflow fault",
518*16932Ssam 	"floating divide by zero fault",
519*16932Ssam 	"floating undeflow fault"
520*16932Ssam };
521*16932Ssam 
522*16932Ssam public printsig(signo)
523*16932Ssam     Integer signo;
524*16932Ssam {
525*16932Ssam     Integer sigcode;
526*16932Ssam 
527*16932Ssam     if (0 < signo && signo < sys_nsig)
528*16932Ssam 	printf("%s ", sys_siglist[signo]);
529*16932Ssam     else
530*16932Ssam 	printf("signal %d ", signo);
531*16932Ssam     sigcode = errcode(process);
532*16932Ssam     switch (signo) {
533*16932Ssam 
534*16932Ssam     case SIGFPE:
535*16932Ssam 	    if (sigcode > 0 &&
536*16932Ssam 		sigcode < sizeof fpenames / sizeof fpenames[0])
537*16932Ssam 		    printf("(%s) ",  fpenames[sigcode]);
538*16932Ssam 	    break;
539*16932Ssam 
540*16932Ssam     case SIGILL:
541*16932Ssam 	    if (sigcode >= 0 &&
542*16932Ssam 		sigcode < sizeof illinames / sizeof illinames[0])
543*16932Ssam 		    printf("(%s) ", illinames[sigcode]);
544*16932Ssam 	    break;
545*16932Ssam     }
546*16932Ssam }
547*16932Ssam 
5489668Slinton /*
5499668Slinton  * Note the termination of the program.  We do this so as to avoid
5509668Slinton  * having the process exit, which would make the values of variables
5519668Slinton  * inaccessible.  We do want to flush all output buffers here,
5529668Slinton  * otherwise it'll never get done.
5539668Slinton  */
5549668Slinton 
5559668Slinton public endprogram()
5569668Slinton {
5579668Slinton     Integer exitcode;
5589668Slinton 
5599668Slinton     stepto(nextaddr(pc, true));
5609668Slinton     printnews();
5619668Slinton     exitcode = argn(1, nil);
562*16932Ssam     printf("\nexecution completed");
563*16932Ssam     if (exitcode)
564*16932Ssam 	printf(" (exit code %d)", exitcode);
565*16932Ssam     putchar('\n');
5669668Slinton     getsrcpos();
5679668Slinton     erecover();
5689668Slinton }
5699668Slinton 
5709668Slinton /*
5719668Slinton  * Single step the machine a source line (or instruction if "inst_tracing"
57210621Slinton  * is true).  If "isnext" is true, skip over procedure calls.
5739668Slinton  */
5749668Slinton 
5759668Slinton private Address getcall();
5769668Slinton 
5779668Slinton public dostep(isnext)
5789668Slinton Boolean isnext;
5799668Slinton {
5809668Slinton     register Address addr;
5819668Slinton     register Lineno line;
5829668Slinton     String filename;
58316612Ssam     Address startaddr, prevaddr;
5849668Slinton 
58516612Ssam     startaddr = pc;
58616612Ssam     prevaddr = startaddr;
5879668Slinton     addr = nextaddr(pc, isnext);
58810621Slinton     if (not inst_tracing and nlhdr.nlines != 0) {
5899668Slinton 	line = linelookup(addr);
5909668Slinton 	while (line == 0) {
59116612Ssam 	    prevaddr = addr;
5929668Slinton 	    addr = nextaddr(addr, isnext);
5939668Slinton 	    line = linelookup(addr);
5949668Slinton 	}
59510621Slinton 	curline = line;
59610621Slinton     } else {
59710621Slinton 	curline = 0;
5989668Slinton     }
59916612Ssam     if (addr == startaddr) {
60016612Ssam 	stepto(prevaddr);
60116612Ssam     }
6029668Slinton     stepto(addr);
6039668Slinton     filename = srcfilename(addr);
6049668Slinton     setsource(filename);
6059668Slinton }
6069668Slinton 
6079668Slinton /*
6089668Slinton  * Compute the next address that will be executed from the given one.
6099668Slinton  * If "isnext" is true then consider a procedure call as straight line code.
6109668Slinton  *
6119668Slinton  * We must unfortunately do much of the same work that is necessary
6129668Slinton  * to print instructions.  In addition we have to deal with branches.
6139668Slinton  * Unconditional branches we just follow, for conditional branches
6149668Slinton  * we continue execution to the current location and then single step
6159668Slinton  * the machine.  We assume that the last argument in an instruction
6169668Slinton  * that branches is the branch address (or relative offset).
6179668Slinton  */
6189668Slinton 
61916612Ssam private Address findnextaddr();
62016612Ssam 
6219668Slinton public Address nextaddr(startaddr, isnext)
6229668Slinton Address startaddr;
62316612Ssam boolean isnext;
62416612Ssam {
62516612Ssam     Address addr;
62616612Ssam 
62716612Ssam     addr = usignal(process);
62816612Ssam     if (addr == 0 or addr == 1) {
62916612Ssam 	addr = findnextaddr(startaddr, isnext);
63016612Ssam     }
63116612Ssam     return addr;
63216612Ssam }
63316612Ssam 
63416612Ssam private Address findnextaddr(startaddr, isnext)
63516612Ssam Address startaddr;
6369668Slinton Boolean isnext;
6379668Slinton {
6389668Slinton     register Address addr;
6399668Slinton     Optab op;
6409668Slinton     VaxOpcode ins;
6419668Slinton     unsigned char mode;
6429668Slinton     int argtype, amode, argno, argval;
6439668Slinton     String r;
6449668Slinton     Boolean indexf;
6459668Slinton     enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
6469668Slinton 
6479668Slinton     argval = 0;
6489668Slinton     indexf = false;
6499668Slinton     addr = startaddr;
6509668Slinton     iread(&ins, addr, sizeof(ins));
6519668Slinton     switch (ins) {
6529668Slinton 	case O_BRB:
6539668Slinton 	case O_BRW:
6549668Slinton 	    addrstatus = BRANCH;
6559668Slinton 	    break;
6569668Slinton 
6579668Slinton 	case O_BSBB:
6589668Slinton 	case O_BSBW:
6599668Slinton 	case O_JSB:
6609668Slinton 	case O_CALLG:
6619668Slinton 	case O_CALLS:
6629668Slinton 	    if (isnext) {
6639668Slinton 		addrstatus = SEQUENTIAL;
6649668Slinton 	    } else {
6659668Slinton 		addrstatus = KNOWN;
6669668Slinton 		stepto(addr);
66716612Ssam 		pstep(process, DEFSIG);
6689668Slinton 		addr = reg(PROGCTR);
6699668Slinton 		pc = addr;
67016612Ssam 		setcurfunc(whatblock(pc));
6719668Slinton 		if (not isbperr()) {
6729668Slinton 		    printstatus();
67311864Slinton 		    /* NOTREACHED */
67411864Slinton 		}
67511864Slinton 		bpact();
67611864Slinton 		if (nosource(curfunc) and canskip(curfunc) and
67711864Slinton 		  nlhdr.nlines != 0) {
67811864Slinton 		    addrstatus = KNOWN;
67911864Slinton 		    addr = return_addr();
68011864Slinton 		    stepto(addr);
68111874Slinton 		    bpact();
6829668Slinton 		} else {
68311864Slinton 		    callnews(/* iscall = */ true);
6849668Slinton 		}
6859668Slinton 	    }
6869668Slinton 	    break;
6879668Slinton 
6889668Slinton 	case O_RSB:
6899668Slinton 	case O_RET:
6909668Slinton 	    addrstatus = KNOWN;
6919668Slinton 	    callnews(/* iscall = */ false);
6929668Slinton 	    addr = return_addr();
69316612Ssam 	    if (addr == pc) {	/* recursive ret to self */
69416612Ssam 		pstep(process, DEFSIG);
69516612Ssam 	    } else {
69616612Ssam 		stepto(addr);
69716612Ssam 	    }
69811874Slinton 	    bpact();
6999668Slinton 	    break;
7009668Slinton 
70116612Ssam 	case O_JMP: /* because it may be jmp (r1) */
7029668Slinton 	case O_BNEQ: case O_BEQL: case O_BGTR:
7039668Slinton 	case O_BLEQ: case O_BGEQ: case O_BLSS:
7049668Slinton 	case O_BGTRU: case O_BLEQU: case O_BVC:
7059668Slinton 	case O_BVS: case O_BCC: case O_BCS:
7069668Slinton 	case O_CASEB: case O_CASEW: case O_CASEL:
7079668Slinton 	case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
7089668Slinton 	case O_BBSC: case O_BBCC: case O_BBSSI:
7099668Slinton 	case O_BBCCI: case O_BLBS: case O_BLBC:
7109668Slinton 	case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
7119668Slinton 	case O_SOBGEQ: case O_SOBGTR:
7129668Slinton 	    addrstatus = KNOWN;
7139668Slinton 	    stepto(addr);
71416612Ssam 	    pstep(process, DEFSIG);
7159668Slinton 	    addr = reg(PROGCTR);
7169668Slinton 	    pc = addr;
7179668Slinton 	    if (not isbperr()) {
7189668Slinton 		printstatus();
7199668Slinton 	    }
7209668Slinton 	    break;
7219668Slinton 
7229668Slinton 	default:
7239668Slinton 	    addrstatus = SEQUENTIAL;
7249668Slinton 	    break;
7259668Slinton     }
7269668Slinton     if (addrstatus != KNOWN) {
7279668Slinton 	addr += 1;
7289668Slinton 	op = optab[ins];
7299668Slinton 	for (argno = 0; argno < op.numargs; argno++) {
7309668Slinton 	    if (indexf == true) {
7319668Slinton 		indexf = false;
7329668Slinton 	    }
7339668Slinton 	    argtype = op.argtype[argno];
7349668Slinton 	    if (is_branch_disp(argtype)) {
7359668Slinton 		mode = 0xAF + (typelen(argtype) << 5);
7369668Slinton 	    } else {
7379668Slinton 		iread(&mode, addr, sizeof(mode));
7389668Slinton 		addr += 1;
7399668Slinton 	    }
7409668Slinton 	    r = regname[regnm(mode)];
7419668Slinton 	    amode = addrmode(mode);
7429668Slinton 	    switch (amode) {
7439668Slinton 		case LITSHORT:
7449668Slinton 		case LITUPTO31:
7459668Slinton 		case LITUPTO47:
7469668Slinton 		case LITUPTO63:
7479668Slinton 		    argval = mode;
7489668Slinton 		    break;
7499668Slinton 
7509668Slinton 		case INDEX:
7519668Slinton 		    indexf = true;
7529668Slinton 		    --argno;
7539668Slinton 		    break;
7549668Slinton 
7559668Slinton 		case REG:
7569668Slinton 		case REGDEF:
7579668Slinton 		case AUTODEC:
7589668Slinton 		    break;
7599668Slinton 
7609668Slinton 		case AUTOINC:
7619668Slinton 		    if (r == regname[PROGCTR]) {
7629668Slinton 			switch (typelen(argtype)) {
7639668Slinton 			    case TYPB:
7649668Slinton 				argval = getdisp(addr, 1, r, amode);
7659668Slinton 				addr += 1;
7669668Slinton 				break;
7679668Slinton 
7689668Slinton 			    case TYPW:
7699668Slinton 				argval = getdisp(addr, 2, r, amode);
7709668Slinton 				addr += 2;
7719668Slinton 				break;
7729668Slinton 
7739668Slinton 			    case TYPL:
7749668Slinton 				argval = getdisp(addr, 4, r, amode);
7759668Slinton 				addr += 4;
7769668Slinton 				break;
7779668Slinton 
7789668Slinton 			    case TYPF:
7799668Slinton 				iread(&argval, addr, sizeof(argval));
7809668Slinton 				addr += 4;
7819668Slinton 				break;
7829668Slinton 
7839668Slinton 			    case TYPQ:
7849668Slinton 			    case TYPD:
7859668Slinton 				iread(&argval, addr+4, sizeof(argval));
7869668Slinton 				addr += 8;
7879668Slinton 				break;
7889668Slinton 			}
7899668Slinton 		    }
7909668Slinton 		    break;
7919668Slinton 
7929668Slinton 		case AUTOINCDEF:
7939668Slinton 		    if (r == regname[PROGCTR]) {
7949668Slinton 			argval = getdisp(addr, 4, r, amode);
7959668Slinton 			addr += 4;
7969668Slinton 		    }
7979668Slinton 		    break;
7989668Slinton 
7999668Slinton 		case BYTEDISP:
8009668Slinton 		case BYTEDISPDEF:
8019668Slinton 		    argval = getdisp(addr, 1, r, amode);
8029668Slinton 		    addr += 1;
8039668Slinton 		    break;
8049668Slinton 
8059668Slinton 		case WORDDISP:
8069668Slinton 		case WORDDISPDEF:
8079668Slinton 		    argval = getdisp(addr, 2, r, amode);
8089668Slinton 		    addr += 2;
8099668Slinton 		    break;
8109668Slinton 
8119668Slinton 		case LONGDISP:
8129668Slinton 		case LONGDISPDEF:
8139668Slinton 		    argval = getdisp(addr, 4, r, amode);
8149668Slinton 		    addr += 4;
8159668Slinton 		    break;
8169668Slinton 	    }
8179668Slinton 	}
8189668Slinton 	if (ins == O_CALLS or ins == O_CALLG) {
8199668Slinton 	    argval += 2;
8209668Slinton 	}
8219668Slinton 	if (addrstatus == BRANCH) {
8229668Slinton 	    addr = argval;
8239668Slinton 	}
8249668Slinton     }
8259668Slinton     return addr;
8269668Slinton }
8279668Slinton 
8289668Slinton /*
8299668Slinton  * Get the displacement of an instruction that uses displacement addressing.
8309668Slinton  */
8319668Slinton 
8329668Slinton private int getdisp(addr, nbytes, reg, mode)
8339668Slinton Address addr;
8349668Slinton int nbytes;
8359668Slinton String reg;
8369668Slinton int mode;
8379668Slinton {
8389668Slinton     char byte;
8399668Slinton     short hword;
8409668Slinton     int argval;
8419668Slinton 
8429668Slinton     switch (nbytes) {
8439668Slinton 	case 1:
8449668Slinton 	    iread(&byte, addr, sizeof(byte));
8459668Slinton 	    argval = byte;
8469668Slinton 	    break;
8479668Slinton 
8489668Slinton 	case 2:
8499668Slinton 	    iread(&hword, addr, sizeof(hword));
8509668Slinton 	    argval = hword;
8519668Slinton 	    break;
8529668Slinton 
8539668Slinton 	case 4:
8549668Slinton 	    iread(&argval, addr, sizeof(argval));
8559668Slinton 	    break;
8569668Slinton     }
8579668Slinton     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
8589668Slinton 	argval += addr + nbytes;
8599668Slinton     }
8609668Slinton     return argval;
8619668Slinton }
8629668Slinton 
8639668Slinton #define BP_OP       O_BPT       /* breakpoint trap */
8649668Slinton #define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */
8659668Slinton 
8669668Slinton /*
8679668Slinton  * Setting a breakpoint at a location consists of saving
8689668Slinton  * the word at the location and poking a BP_OP there.
8699668Slinton  *
8709668Slinton  * We save the locations and words on a list for use in unsetting.
8719668Slinton  */
8729668Slinton 
8739668Slinton typedef struct Savelist *Savelist;
8749668Slinton 
8759668Slinton struct Savelist {
8769668Slinton     Address location;
8779668Slinton     Byte save;
8789668Slinton     Byte refcount;
8799668Slinton     Savelist link;
8809668Slinton };
8819668Slinton 
8829668Slinton private Savelist savelist;
8839668Slinton 
8849668Slinton /*
8859668Slinton  * Set a breakpoint at the given address.  Only save the word there
8869668Slinton  * if it's not already a breakpoint.
8879668Slinton  */
8889668Slinton 
8899668Slinton public setbp(addr)
8909668Slinton Address addr;
8919668Slinton {
8929668Slinton     Byte w;
8939668Slinton     Byte save;
8949668Slinton     register Savelist newsave, s;
8959668Slinton 
8969668Slinton     for (s = savelist; s != nil; s = s->link) {
8979668Slinton 	if (s->location == addr) {
8989668Slinton 	    s->refcount++;
8999668Slinton 	    return;
9009668Slinton 	}
9019668Slinton     }
90211174Slinton     iread(&save, addr, sizeof(save));
9039668Slinton     newsave = new(Savelist);
9049668Slinton     newsave->location = addr;
9059668Slinton     newsave->save = save;
9069668Slinton     newsave->refcount = 1;
9079668Slinton     newsave->link = savelist;
9089668Slinton     savelist = newsave;
9099668Slinton     w = BP_OP;
9109668Slinton     iwrite(&w, addr, sizeof(w));
9119668Slinton }
9129668Slinton 
9139668Slinton /*
9149668Slinton  * Unset a breakpoint; unfortunately we have to search the SAVELIST
9159668Slinton  * to find the saved value.  The assumption is that the SAVELIST will
9169668Slinton  * usually be quite small.
9179668Slinton  */
9189668Slinton 
9199668Slinton public unsetbp(addr)
9209668Slinton Address addr;
9219668Slinton {
9229668Slinton     register Savelist s, prev;
9239668Slinton 
9249668Slinton     prev = nil;
9259668Slinton     for (s = savelist; s != nil; s = s->link) {
9269668Slinton 	if (s->location == addr) {
9279668Slinton 	    iwrite(&s->save, addr, sizeof(s->save));
9289668Slinton 	    s->refcount--;
9299668Slinton 	    if (s->refcount == 0) {
9309668Slinton 		if (prev == nil) {
9319668Slinton 		    savelist = s->link;
9329668Slinton 		} else {
9339668Slinton 		    prev->link = s->link;
9349668Slinton 		}
9359668Slinton 		dispose(s);
9369668Slinton 	    }
9379668Slinton 	    return;
9389668Slinton 	}
9399668Slinton 	prev = s;
9409668Slinton     }
9419668Slinton     panic("unsetbp: couldn't find address %d", addr);
9429668Slinton }
9439668Slinton 
9449668Slinton /*
9459668Slinton  * Predicate to test if the reason the process stopped was because
9469668Slinton  * of a breakpoint.
9479668Slinton  */
9489668Slinton 
9499668Slinton public Boolean isbperr()
9509668Slinton {
9519668Slinton     return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP);
9529668Slinton }
9539668Slinton 
9549668Slinton /*
9559668Slinton  * Enter a procedure by creating and executing a call instruction.
9569668Slinton  */
9579668Slinton 
9589668Slinton #define CALLSIZE 7	/* size of call instruction */
9599668Slinton 
9609668Slinton public beginproc(p, argc)
9619668Slinton Symbol p;
9629668Slinton Integer argc;
9639668Slinton {
9649668Slinton     char save[CALLSIZE];
9659668Slinton     struct {
9669668Slinton 	VaxOpcode op;
9679668Slinton 	unsigned char numargs;
9689668Slinton 	unsigned char mode;
9699668Slinton 	char addr[sizeof(long)];	/* unaligned long */
9709668Slinton     } call;
9719668Slinton     long dest;
9729668Slinton 
9739668Slinton     pc = 2;
9749668Slinton     iread(save, pc, sizeof(save));
9759668Slinton     call.op = O_CALLS;
9769668Slinton     call.numargs = argc;
9779668Slinton     call.mode = 0xef;
9789668Slinton     dest = codeloc(p) - 2 - (pc + 7);
9799668Slinton     mov(&dest, call.addr, sizeof(call.addr));
9809668Slinton     iwrite(&call, pc, sizeof(call));
9819668Slinton     setreg(PROGCTR, pc);
98216612Ssam     pstep(process, DEFSIG);
9839668Slinton     iwrite(save, pc, sizeof(save));
9849668Slinton     pc = reg(PROGCTR);
9859668Slinton     if (not isbperr()) {
9869668Slinton 	printstatus();
9879668Slinton     }
9889668Slinton }
989