xref: /csrg-svn/old/dbx/vax.c (revision 18222)
19668Slinton /* Copyright (c) 1982 Regents of the University of California */
29668Slinton 
3*18222Slinton static	char sccsid[] = "@(#)vax.c	1.13 (Berkeley) 03/01/85";
49668Slinton 
5*18222Slinton static char rcsid[] = "$Header: machine.c,v 1.5 84/12/26 10:40:05 linton Exp $";
6*18222Slinton 
79668Slinton /*
89668Slinton  * Target machine dependent stuff.
99668Slinton  */
109668Slinton 
119668Slinton #include "defs.h"
129668Slinton #include "machine.h"
139668Slinton #include "process.h"
1416612Ssam #include "runtime.h"
159668Slinton #include "events.h"
169668Slinton #include "main.h"
179668Slinton #include "symbols.h"
189668Slinton #include "source.h"
199668Slinton #include "mappings.h"
209668Slinton #include "object.h"
21*18222Slinton #include "keywords.h"
229693Slinton #include "ops.h"
239668Slinton #include <signal.h>
249668Slinton 
259668Slinton #ifndef public
269668Slinton typedef unsigned int Address;
279668Slinton typedef unsigned char Byte;
289668Slinton typedef unsigned int Word;
299668Slinton 
309668Slinton #define NREG 16
319668Slinton 
329668Slinton #define ARGP 12
339668Slinton #define FRP 13
349668Slinton #define STKP 14
359668Slinton #define PROGCTR 15
369668Slinton 
379668Slinton #define BITSPERBYTE 8
389668Slinton #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
399668Slinton 
409668Slinton #define nargspassed(frame) argn(0, frame)
419668Slinton 
429668Slinton #include "source.h"
439668Slinton #include "symbols.h"
449668Slinton 
459668Slinton Address pc;
469668Slinton Address prtaddr;
479668Slinton 
489668Slinton #endif
499668Slinton 
509668Slinton private Address printop();
519668Slinton 
529668Slinton /*
539668Slinton  * Decode and print the instructions within the given address range.
549668Slinton  */
559668Slinton 
569668Slinton public printinst(lowaddr, highaddr)
579668Slinton Address lowaddr;
589668Slinton Address highaddr;
599668Slinton {
609668Slinton     register Address addr;
619668Slinton 
629668Slinton     for (addr = lowaddr; addr <= highaddr; ) {
639668Slinton 	addr = printop(addr);
649668Slinton     }
659668Slinton     prtaddr = addr;
669668Slinton }
679668Slinton 
689668Slinton /*
699668Slinton  * Another approach:  print n instructions starting at the given address.
709668Slinton  */
719668Slinton 
729668Slinton public printninst(count, addr)
739668Slinton int count;
749668Slinton Address addr;
759668Slinton {
769668Slinton     register Integer i;
779668Slinton     register Address newaddr;
789668Slinton 
799668Slinton     if (count <= 0) {
809668Slinton 	error("non-positive repetition count");
819668Slinton     } else {
829668Slinton 	newaddr = addr;
839668Slinton 	for (i = 0; i < count; i++) {
849668Slinton 	    newaddr = printop(newaddr);
859668Slinton 	}
869668Slinton 	prtaddr = newaddr;
879668Slinton     }
889668Slinton }
899668Slinton 
909668Slinton /*
919668Slinton  * Hacked version of adb's VAX instruction decoder.
929668Slinton  */
939668Slinton 
949668Slinton private Address printop(addr)
959668Slinton Address addr;
969668Slinton {
979668Slinton     Optab op;
989668Slinton     VaxOpcode ins;
999668Slinton     unsigned char mode;
1009668Slinton     int argtype, amode, argno, argval;
1019668Slinton     String reg;
1029668Slinton     Boolean indexf;
1039668Slinton     short offset;
1049668Slinton 
1059668Slinton     argval = 0;
1069668Slinton     indexf = false;
1079668Slinton     printf("%08x  ", addr);
1089668Slinton     iread(&ins, addr, sizeof(ins));
1099668Slinton     addr += 1;
1109668Slinton     op = optab[ins];
1119668Slinton     printf("%s", op.iname);
1129668Slinton     for (argno = 0; argno < op.numargs; argno++) {
1139668Slinton 	if (indexf == true) {
1149668Slinton 	    indexf = false;
1159668Slinton 	} else if (argno == 0) {
1169668Slinton 	    printf("\t");
1179668Slinton 	} else {
1189668Slinton 	    printf(",");
1199668Slinton 	}
1209668Slinton 	argtype = op.argtype[argno];
1219668Slinton 	if (is_branch_disp(argtype)) {
1229668Slinton 	    mode = 0xAF + (typelen(argtype) << 5);
1239668Slinton 	} else {
1249668Slinton 	    iread(&mode, addr, sizeof(mode));
1259668Slinton 	    addr += 1;
1269668Slinton 	}
1279668Slinton 	reg = regname[regnm(mode)];
1289668Slinton 	amode = addrmode(mode);
1299668Slinton 	switch (amode) {
1309668Slinton 	    case LITSHORT:
1319668Slinton 	    case LITUPTO31:
1329668Slinton 	    case LITUPTO47:
1339668Slinton 	    case LITUPTO63:
1349668Slinton 		if (typelen(argtype) == TYPF || typelen(argtype) ==TYPD)
1359668Slinton 		    printf("$%s", fltimm[mode]);
1369668Slinton 		else
1379668Slinton 		    printf("$%x", mode);
1389668Slinton 		argval = mode;
1399668Slinton 		break;
1409668Slinton 
1419668Slinton 	    case INDEX:
1429668Slinton 		printf("[%s]", reg);
1439668Slinton 		indexf = true;
1449668Slinton 		argno--;
1459668Slinton 		break;
1469668Slinton 
1479668Slinton 	    case REG:
1489668Slinton 		printf("%s", reg);
1499668Slinton 		break;
1509668Slinton 
1519668Slinton 	    case REGDEF:
1529668Slinton 		printf("(%s)", reg);
1539668Slinton 		break;
1549668Slinton 
1559668Slinton 	    case AUTODEC:
1569668Slinton 		printf("-(%s)", reg);
1579668Slinton 		break;
1589668Slinton 
1599668Slinton 	    case AUTOINC:
1609668Slinton 		if (reg != regname[PROGCTR]) {
1619668Slinton 		    printf("(%s)+", reg);
1629668Slinton 		} else {
1639668Slinton 		    printf("$");
1649668Slinton 		    switch (typelen(argtype)) {
1659668Slinton 			case TYPB:
1669668Slinton 			    argval = printdisp(addr, 1, reg, amode);
1679668Slinton 			    addr += 1;
1689668Slinton 			    break;
1699668Slinton 
1709668Slinton 			case TYPW:
1719668Slinton 			    argval = printdisp(addr, 2, reg, amode);
1729668Slinton 			    addr += 2;
1739668Slinton 			    break;
1749668Slinton 
1759668Slinton 			case TYPL:
1769668Slinton 			    argval = printdisp(addr, 4, reg, amode);
1779668Slinton 			    addr += 4;
1789668Slinton 			    break;
1799668Slinton 
1809668Slinton 			case TYPF:
1819668Slinton 			    iread(&argval, addr, sizeof(argval));
1829668Slinton 			    printf("%06x", argval);
1839668Slinton 			    addr += 4;
1849668Slinton 			    break;
1859668Slinton 
1869668Slinton 			case TYPQ:
1879668Slinton 			case TYPD:
1889668Slinton 			    iread(&argval, addr, sizeof(argval));
1899668Slinton 			    printf("%06x", argval);
1909668Slinton 			    iread(&argval, addr+4, sizeof(argval));
1919668Slinton 			    printf("%06x", argval);
1929668Slinton 			    addr += 8;
1939668Slinton 			    break;
1949668Slinton 		    }
1959668Slinton 		}
1969668Slinton 		break;
1979668Slinton 
1989668Slinton 	    case AUTOINCDEF:
1999668Slinton 		if (reg == regname[PROGCTR]) {
2009668Slinton 		    printf("*$");
2019668Slinton 		    argval = printdisp(addr, 4, reg, amode);
2029668Slinton 		    addr += 4;
2039668Slinton 		} else {
2049668Slinton 		    printf("*(%s)+", reg);
2059668Slinton 		}
2069668Slinton 		break;
2079668Slinton 
2089668Slinton 	    case BYTEDISP:
2099668Slinton 		argval = printdisp(addr, 1, reg, amode);
2109668Slinton 		addr += 1;
2119668Slinton 		break;
2129668Slinton 
2139668Slinton 	    case BYTEDISPDEF:
2149668Slinton 		printf("*");
2159668Slinton 		argval = printdisp(addr, 1, reg, amode);
2169668Slinton 		addr += 1;
2179668Slinton 		break;
2189668Slinton 
2199668Slinton 	    case WORDDISP:
2209668Slinton 		argval = printdisp(addr, 2, reg, amode);
2219668Slinton 		addr += 2;
2229668Slinton 		break;
2239668Slinton 
2249668Slinton 	    case WORDDISPDEF:
2259668Slinton 		printf("*");
2269668Slinton 		argval = printdisp(addr, 2, reg, amode);
2279668Slinton 		addr += 2;
2289668Slinton 		break;
2299668Slinton 
2309668Slinton 	    case LONGDISP:
2319668Slinton 		argval = printdisp(addr, 4, reg, amode);
2329668Slinton 		addr += 4;
2339668Slinton 		break;
2349668Slinton 
2359668Slinton 	    case LONGDISPDEF:
2369668Slinton 		printf("*");
2379668Slinton 		argval = printdisp(addr, 4, reg, amode);
2389668Slinton 		addr += 4;
2399668Slinton 		break;
2409668Slinton 	}
2419668Slinton     }
2429668Slinton     if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
2439668Slinton 	for (argno = 0; argno <= argval; argno++) {
2449668Slinton 	    iread(&offset, addr, sizeof(offset));
2459668Slinton 	    printf("\n\t\t%d", offset);
2469668Slinton 	    addr += 2;
2479668Slinton 	}
2489668Slinton     }
2499668Slinton     printf("\n");
2509668Slinton     return addr;
2519668Slinton }
2529668Slinton 
2539668Slinton /*
2549668Slinton  * Print the displacement of an instruction that uses displacement
2559668Slinton  * addressing.
2569668Slinton  */
2579668Slinton 
2589668Slinton private int printdisp(addr, nbytes, reg, mode)
2599668Slinton Address addr;
2609668Slinton int nbytes;
2619668Slinton char *reg;
2629668Slinton int mode;
2639668Slinton {
2649668Slinton     char byte;
2659668Slinton     short hword;
2669668Slinton     int argval;
26714338Slinton     Symbol f;
2689668Slinton 
2699668Slinton     switch (nbytes) {
2709668Slinton 	case 1:
2719668Slinton 	    iread(&byte, addr, sizeof(byte));
2729668Slinton 	    argval = byte;
2739668Slinton 	    break;
2749668Slinton 
2759668Slinton 	case 2:
2769668Slinton 	    iread(&hword, addr, sizeof(hword));
2779668Slinton 	    argval = hword;
2789668Slinton 	    break;
2799668Slinton 
2809668Slinton 	case 4:
2819668Slinton 	    iread(&argval, addr, sizeof(argval));
2829668Slinton 	    break;
2839668Slinton     }
2849668Slinton     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
2859668Slinton 	argval += addr + nbytes;
2869668Slinton     }
2879668Slinton     if (reg == regname[PROGCTR]) {
28814338Slinton 	f = whatblock((Address) argval + 2);
28914338Slinton 	if (codeloc(f) == argval + 2) {
29014338Slinton 	    printf("%s", symname(f));
29114338Slinton 	} else {
29214338Slinton 	    printf("%x", argval);
29314338Slinton 	}
2949668Slinton     } else {
295*18222Slinton 	if (varIsSet("$hexoffsets")) {
296*18222Slinton 	    if (argval < 0) {
297*18222Slinton 		printf("-%x(%s)", -(argval), reg);
298*18222Slinton 	    } else {
299*18222Slinton 		printf("%x(%s)", argval, reg);
300*18222Slinton 	    }
301*18222Slinton 	} else {
302*18222Slinton 	    printf("%d(%s)", argval, reg);
303*18222Slinton 	}
3049668Slinton     }
3059668Slinton     return argval;
3069668Slinton }
3079668Slinton 
3089668Slinton /*
3099668Slinton  * Print the contents of the addresses within the given range
3109668Slinton  * according to the given format.
3119668Slinton  */
3129668Slinton 
3139668Slinton typedef struct {
3149668Slinton     String name;
3159668Slinton     String printfstring;
3169668Slinton     int length;
3179668Slinton } Format;
3189668Slinton 
3199668Slinton private Format fmt[] = {
3209668Slinton     { "d", " %d", sizeof(short) },
3219668Slinton     { "D", " %ld", sizeof(long) },
3229668Slinton     { "o", " %o", sizeof(short) },
3239668Slinton     { "O", " %lo", sizeof(long) },
3249668Slinton     { "x", " %04x", sizeof(short) },
3259668Slinton     { "X", " %08x", sizeof(long) },
3269668Slinton     { "b", " \\%o", sizeof(char) },
3279668Slinton     { "c", " '%c'", sizeof(char) },
3289668Slinton     { "s", "%c", sizeof(char) },
32914338Slinton     { "f", " %f", sizeof(float) },
3309668Slinton     { "g", " %g", sizeof(double) },
3319668Slinton     { nil, nil, 0 }
3329668Slinton };
3339668Slinton 
33411174Slinton private Format *findformat(s)
33511174Slinton String s;
33611174Slinton {
33711174Slinton     register Format *f;
33811174Slinton 
33911174Slinton     f = &fmt[0];
34011174Slinton     while (f->name != nil and not streq(f->name, s)) {
34111174Slinton 	++f;
34211174Slinton     }
34311174Slinton     if (f->name == nil) {
34411174Slinton 	error("bad print format \"%s\"", s);
34511174Slinton     }
34611174Slinton     return f;
34711174Slinton }
34811174Slinton 
3499668Slinton public Address printdata(lowaddr, highaddr, format)
3509668Slinton Address lowaddr;
3519668Slinton Address highaddr;
3529668Slinton String format;
3539668Slinton {
3549668Slinton     register int n;
3559668Slinton     register Address addr;
3569668Slinton     register Format *f;
3579668Slinton     int value;
3589668Slinton 
3599668Slinton     if (lowaddr > highaddr) {
3609668Slinton 	error("first address larger than second");
3619668Slinton     }
36211174Slinton     f = findformat(format);
3639668Slinton     n = 0;
3649668Slinton     value = 0;
3659668Slinton     for (addr = lowaddr; addr <= highaddr; addr += f->length) {
3669668Slinton 	if (n == 0) {
3679668Slinton 	    printf("%08x: ", addr);
3689668Slinton 	}
3699668Slinton 	dread(&value, addr, f->length);
3709668Slinton 	printf(f->printfstring, value);
3719668Slinton 	++n;
3729668Slinton 	if (n >= (16 div f->length)) {
3739668Slinton 	    putchar('\n');
3749668Slinton 	    n = 0;
3759668Slinton 	}
3769668Slinton     }
3779668Slinton     if (n != 0) {
3789668Slinton 	putchar('\n');
3799668Slinton     }
3809668Slinton     prtaddr = addr;
3819668Slinton     return addr;
3829668Slinton }
3839668Slinton 
3849668Slinton /*
3859668Slinton  * The other approach is to print n items starting with a given address.
3869668Slinton  */
3879668Slinton 
3889668Slinton public printndata(count, startaddr, format)
3899668Slinton int count;
3909668Slinton Address startaddr;
3919668Slinton String format;
3929668Slinton {
3939668Slinton     register int i, n;
3949668Slinton     register Address addr;
3959668Slinton     register Format *f;
3969668Slinton     register Boolean isstring;
39714338Slinton     char c;
39814338Slinton     union {
39914338Slinton 	char charv;
40014338Slinton 	short shortv;
40114338Slinton 	int intv;
40214338Slinton 	float floatv;
40314338Slinton 	double doublev;
40414338Slinton     } value;
4059668Slinton 
4069668Slinton     if (count <= 0) {
4079668Slinton 	error("non-positive repetition count");
4089668Slinton     }
40911174Slinton     f = findformat(format);
4109668Slinton     isstring = (Boolean) streq(f->name, "s");
4119668Slinton     n = 0;
4129668Slinton     addr = startaddr;
41314338Slinton     value.intv = 0;
4149668Slinton     for (i = 0; i < count; i++) {
4159668Slinton 	if (n == 0) {
4169668Slinton 	    printf("%08x: ", addr);
4179668Slinton 	}
4189668Slinton 	if (isstring) {
4199668Slinton 	    putchar('"');
42014338Slinton 	    dread(&c, addr, sizeof(char));
42114338Slinton 	    while (c != '\0') {
42214338Slinton 		printchar(c);
4239668Slinton 		++addr;
42414338Slinton 		dread(&c, addr, sizeof(char));
4259668Slinton 	    }
4269668Slinton 	    putchar('"');
4279668Slinton 	    putchar('\n');
4289668Slinton 	    n = 0;
4299668Slinton 	    addr += sizeof(String);
4309668Slinton 	} else {
4319668Slinton 	    dread(&value, addr, f->length);
4329668Slinton 	    printf(f->printfstring, value);
4339668Slinton 	    ++n;
4349668Slinton 	    if (n >= (16 div f->length)) {
4359668Slinton 		putchar('\n');
4369668Slinton 		n = 0;
4379668Slinton 	    }
4389668Slinton 	    addr += f->length;
4399668Slinton 	}
4409668Slinton     }
4419668Slinton     if (n != 0) {
4429668Slinton 	putchar('\n');
4439668Slinton     }
4449668Slinton     prtaddr = addr;
4459668Slinton }
4469668Slinton 
4479668Slinton /*
44811174Slinton  * Print out a value according to the given format.
44911174Slinton  */
45011174Slinton 
45111174Slinton public printvalue(v, format)
45211174Slinton long v;
45311174Slinton String format;
45411174Slinton {
45511174Slinton     Format *f;
45611174Slinton     char *p, *q;
45711174Slinton 
45811174Slinton     f = findformat(format);
45911174Slinton     if (streq(f->name, "s")) {
46011174Slinton 	putchar('"');
46111174Slinton 	p = (char *) &v;
46211174Slinton 	q = p + sizeof(v);
46311174Slinton 	while (p < q) {
46411174Slinton 	    printchar(*p);
46511174Slinton 	    ++p;
46611174Slinton 	}
46711174Slinton 	putchar('"');
46811174Slinton     } else {
46911174Slinton 	printf(f->printfstring, v);
47011174Slinton     }
47111174Slinton     putchar('\n');
47211174Slinton }
47311174Slinton 
47411174Slinton /*
4759668Slinton  * Print out an execution time error.
4769842Slinton  * Assumes the source position of the error has been calculated.
4779668Slinton  *
4789668Slinton  * Have to check if the -r option was specified; if so then
4799668Slinton  * the object file information hasn't been read in yet.
4809668Slinton  */
4819668Slinton 
4829668Slinton public printerror()
4839668Slinton {
4849668Slinton     extern Integer sys_nsig;
4859668Slinton     extern String sys_siglist[];
486*18222Slinton     integer err;
4879668Slinton 
4889668Slinton     if (isfinished(process)) {
48916932Ssam 	err = exitcode(process);
490*18222Slinton 	if (err == 0) {
491*18222Slinton 	    printf("\"%s\" terminated normally\n", objname);
492*18222Slinton 	} else {
493*18222Slinton 	    printf("\"%s\" terminated abnormally (exit code %d)\n",
494*18222Slinton 		objname, err
495*18222Slinton 	    );
496*18222Slinton 	}
4979668Slinton 	erecover();
4989668Slinton     }
4999668Slinton     if (runfirst) {
500*18222Slinton 	fprintf(stderr, "Entering debugger ...\n");
5019668Slinton 	init();
5029668Slinton     }
5039668Slinton     err = errnum(process);
5049668Slinton     putchar('\n');
50516932Ssam     printsig(err);
506*18222Slinton     putchar(' ');
50716932Ssam     printloc();
50816932Ssam     putchar('\n');
5099668Slinton     if (curline > 0) {
5109668Slinton 	printlines(curline, curline);
5119668Slinton     } else {
5129668Slinton 	printinst(pc, pc);
5139668Slinton     }
5149668Slinton     erecover();
5159668Slinton }
5169668Slinton 
517*18222Slinton /*
518*18222Slinton  * Print out a signal.
519*18222Slinton  */
520*18222Slinton 
52116932Ssam private String illinames[] = {
522*18222Slinton     "reserved addressing fault",
523*18222Slinton     "priviliged instruction fault",
524*18222Slinton     "reserved operand fault"
52516932Ssam };
526*18222Slinton 
52716932Ssam private String fpenames[] = {
528*18222Slinton     nil,
529*18222Slinton     "integer overflow trap",
530*18222Slinton     "integer divide by zero trap",
531*18222Slinton     "floating overflow trap",
532*18222Slinton     "floating/decimal divide by zero trap",
533*18222Slinton     "floating underflow trap",
534*18222Slinton     "decimal overflow trap",
535*18222Slinton     "subscript out of range trap",
536*18222Slinton     "floating overflow fault",
537*18222Slinton     "floating divide by zero fault",
538*18222Slinton     "floating undeflow fault"
53916932Ssam };
54016932Ssam 
541*18222Slinton public printsig (signo)
542*18222Slinton integer signo;
54316932Ssam {
544*18222Slinton     integer code;
54516932Ssam 
546*18222Slinton     if (signo < 0 or signo > sys_nsig) {
547*18222Slinton 	printf("[signal %d]", signo);
548*18222Slinton     } else {
549*18222Slinton 	printf("%s", sys_siglist[signo]);
55016932Ssam     }
551*18222Slinton     code = errcode(process);
552*18222Slinton     if (signo == SIGILL) {
553*18222Slinton 	if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) {
554*18222Slinton 	    printf(" (%s)", illinames[code]);
555*18222Slinton 	}
556*18222Slinton     } else if (signo == SIGFPE) {
557*18222Slinton 	if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) {
558*18222Slinton 	    printf(" (%s)", fpenames[code]);
559*18222Slinton 	}
560*18222Slinton     }
56116932Ssam }
56216932Ssam 
5639668Slinton /*
5649668Slinton  * Note the termination of the program.  We do this so as to avoid
5659668Slinton  * having the process exit, which would make the values of variables
5669668Slinton  * inaccessible.  We do want to flush all output buffers here,
5679668Slinton  * otherwise it'll never get done.
5689668Slinton  */
5699668Slinton 
5709668Slinton public endprogram()
5719668Slinton {
5729668Slinton     Integer exitcode;
5739668Slinton 
5749668Slinton     stepto(nextaddr(pc, true));
5759668Slinton     printnews();
5769668Slinton     exitcode = argn(1, nil);
577*18222Slinton     if (exitcode != 0) {
578*18222Slinton 	printf("\nexecution completed (exit code %d)\n", exitcode);
579*18222Slinton     } else {
580*18222Slinton 	printf("\nexecution completed\n");
581*18222Slinton     }
5829668Slinton     getsrcpos();
5839668Slinton     erecover();
5849668Slinton }
5859668Slinton 
5869668Slinton /*
5879668Slinton  * Single step the machine a source line (or instruction if "inst_tracing"
58810621Slinton  * is true).  If "isnext" is true, skip over procedure calls.
5899668Slinton  */
5909668Slinton 
5919668Slinton private Address getcall();
5929668Slinton 
5939668Slinton public dostep(isnext)
5949668Slinton Boolean isnext;
5959668Slinton {
5969668Slinton     register Address addr;
5979668Slinton     register Lineno line;
5989668Slinton     String filename;
599*18222Slinton     Address startaddr;
6009668Slinton 
60116612Ssam     startaddr = pc;
6029668Slinton     addr = nextaddr(pc, isnext);
60310621Slinton     if (not inst_tracing and nlhdr.nlines != 0) {
6049668Slinton 	line = linelookup(addr);
6059668Slinton 	while (line == 0) {
606*18222Slinton 	    addr = nextaddr(addr, isnext);
6079668Slinton 	    line = linelookup(addr);
6089668Slinton 	}
60910621Slinton 	curline = line;
61010621Slinton     } else {
61110621Slinton 	curline = 0;
6129668Slinton     }
6139668Slinton     stepto(addr);
6149668Slinton     filename = srcfilename(addr);
6159668Slinton     setsource(filename);
6169668Slinton }
6179668Slinton 
6189668Slinton /*
6199668Slinton  * Compute the next address that will be executed from the given one.
6209668Slinton  * If "isnext" is true then consider a procedure call as straight line code.
6219668Slinton  *
6229668Slinton  * We must unfortunately do much of the same work that is necessary
6239668Slinton  * to print instructions.  In addition we have to deal with branches.
6249668Slinton  * Unconditional branches we just follow, for conditional branches
6259668Slinton  * we continue execution to the current location and then single step
6269668Slinton  * the machine.  We assume that the last argument in an instruction
6279668Slinton  * that branches is the branch address (or relative offset).
6289668Slinton  */
6299668Slinton 
630*18222Slinton private Address findnextaddr();
631*18222Slinton 
6329668Slinton public Address nextaddr(startaddr, isnext)
6339668Slinton Address startaddr;
63416612Ssam boolean isnext;
63516612Ssam {
63616612Ssam     Address addr;
63716612Ssam 
63816612Ssam     addr = usignal(process);
63916612Ssam     if (addr == 0 or addr == 1) {
64016612Ssam 	addr = findnextaddr(startaddr, isnext);
64116612Ssam     }
64216612Ssam     return addr;
64316612Ssam }
64416612Ssam 
645*18222Slinton /*
646*18222Slinton  * Determine if it's ok to skip function f entered by instruction ins.
647*18222Slinton  * If so, we're going to compute the return address and step to it.
648*18222Slinton  * Therefore we cannot skip over a function entered by a jsb or bsb,
649*18222Slinton  * since the return address is not easily computed for them.
650*18222Slinton  */
651*18222Slinton 
652*18222Slinton private boolean skipfunc (ins, f)
653*18222Slinton VaxOpcode ins;
654*18222Slinton Symbol f;
655*18222Slinton {
656*18222Slinton     boolean b;
657*18222Slinton 
658*18222Slinton     b = (boolean) (
659*18222Slinton 	ins != O_JSB and ins != O_BSBB and ins != O_BSBW and
660*18222Slinton 	not inst_tracing and nlhdr.nlines != 0 and
661*18222Slinton 	nosource(curfunc) and canskip(curfunc)
662*18222Slinton     );
663*18222Slinton     return b;
664*18222Slinton }
665*18222Slinton 
66616612Ssam private Address findnextaddr(startaddr, isnext)
66716612Ssam Address startaddr;
6689668Slinton Boolean isnext;
6699668Slinton {
6709668Slinton     register Address addr;
6719668Slinton     Optab op;
6729668Slinton     VaxOpcode ins;
6739668Slinton     unsigned char mode;
6749668Slinton     int argtype, amode, argno, argval;
6759668Slinton     String r;
6769668Slinton     Boolean indexf;
6779668Slinton     enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
6789668Slinton 
6799668Slinton     argval = 0;
6809668Slinton     indexf = false;
6819668Slinton     addr = startaddr;
6829668Slinton     iread(&ins, addr, sizeof(ins));
6839668Slinton     switch (ins) {
684*18222Slinton 	/*
685*18222Slinton 	 * It used to be that unconditional jumps and branches were handled
686*18222Slinton 	 * by taking their destination address as the next address.  While
687*18222Slinton 	 * saving the cost of starting up the process, this approach
688*18222Slinton 	 * doesn't work when jumping indirect (since the value in the
689*18222Slinton 	 * register might not yet have been set).
690*18222Slinton 	 *
691*18222Slinton 	 * So unconditional jumps and branches are now handled the same way
692*18222Slinton 	 * as conditional jumps and branches.
693*18222Slinton 	 *
6949668Slinton 	case O_BRB:
6959668Slinton 	case O_BRW:
6969668Slinton 	    addrstatus = BRANCH;
6979668Slinton 	    break;
698*18222Slinton 	 *
699*18222Slinton 	 */
7009668Slinton 
7019668Slinton 	case O_BSBB:
7029668Slinton 	case O_BSBW:
7039668Slinton 	case O_JSB:
7049668Slinton 	case O_CALLG:
7059668Slinton 	case O_CALLS:
706*18222Slinton 	    addrstatus = KNOWN;
707*18222Slinton 	    stepto(addr);
708*18222Slinton 	    pstep(process, DEFSIG);
709*18222Slinton 	    addr = reg(PROGCTR);
710*18222Slinton 	    pc = addr;
711*18222Slinton 	    setcurfunc(whatblock(pc));
712*18222Slinton 	    if (not isbperr()) {
713*18222Slinton 		printstatus();
714*18222Slinton 		/* NOTREACHED */
715*18222Slinton 	    }
716*18222Slinton 	    bpact();
717*18222Slinton 	    if (isnext or skipfunc(ins, curfunc)) {
7189668Slinton 		addrstatus = KNOWN;
719*18222Slinton 		addr = return_addr();
7209668Slinton 		stepto(addr);
72111864Slinton 		bpact();
722*18222Slinton 	    } else {
723*18222Slinton 		callnews(/* iscall = */ true);
7249668Slinton 	    }
7259668Slinton 	    break;
7269668Slinton 
7279668Slinton 	case O_RSB:
7289668Slinton 	case O_RET:
7299668Slinton 	    addrstatus = KNOWN;
730*18222Slinton 	    stepto(addr);
7319668Slinton 	    callnews(/* iscall = */ false);
732*18222Slinton 	    pstep(process, DEFSIG);
733*18222Slinton 	    addr = reg(PROGCTR);
734*18222Slinton 	    pc = addr;
735*18222Slinton 	    if (not isbperr()) {
736*18222Slinton 		printstatus();
73716612Ssam 	    }
73811874Slinton 	    bpact();
7399668Slinton 	    break;
7409668Slinton 
741*18222Slinton 	case O_BRB: case O_BRW:
74216612Ssam 	case O_JMP: /* because it may be jmp (r1) */
7439668Slinton 	case O_BNEQ: case O_BEQL: case O_BGTR:
7449668Slinton 	case O_BLEQ: case O_BGEQ: case O_BLSS:
7459668Slinton 	case O_BGTRU: case O_BLEQU: case O_BVC:
7469668Slinton 	case O_BVS: case O_BCC: case O_BCS:
7479668Slinton 	case O_CASEB: case O_CASEW: case O_CASEL:
7489668Slinton 	case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
7499668Slinton 	case O_BBSC: case O_BBCC: case O_BBSSI:
7509668Slinton 	case O_BBCCI: case O_BLBS: case O_BLBC:
7519668Slinton 	case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
7529668Slinton 	case O_SOBGEQ: case O_SOBGTR:
7539668Slinton 	    addrstatus = KNOWN;
7549668Slinton 	    stepto(addr);
75516612Ssam 	    pstep(process, DEFSIG);
7569668Slinton 	    addr = reg(PROGCTR);
7579668Slinton 	    pc = addr;
7589668Slinton 	    if (not isbperr()) {
7599668Slinton 		printstatus();
7609668Slinton 	    }
7619668Slinton 	    break;
7629668Slinton 
7639668Slinton 	default:
7649668Slinton 	    addrstatus = SEQUENTIAL;
7659668Slinton 	    break;
7669668Slinton     }
7679668Slinton     if (addrstatus != KNOWN) {
7689668Slinton 	addr += 1;
7699668Slinton 	op = optab[ins];
7709668Slinton 	for (argno = 0; argno < op.numargs; argno++) {
7719668Slinton 	    if (indexf == true) {
7729668Slinton 		indexf = false;
7739668Slinton 	    }
7749668Slinton 	    argtype = op.argtype[argno];
7759668Slinton 	    if (is_branch_disp(argtype)) {
7769668Slinton 		mode = 0xAF + (typelen(argtype) << 5);
7779668Slinton 	    } else {
7789668Slinton 		iread(&mode, addr, sizeof(mode));
7799668Slinton 		addr += 1;
7809668Slinton 	    }
7819668Slinton 	    r = regname[regnm(mode)];
7829668Slinton 	    amode = addrmode(mode);
7839668Slinton 	    switch (amode) {
7849668Slinton 		case LITSHORT:
7859668Slinton 		case LITUPTO31:
7869668Slinton 		case LITUPTO47:
7879668Slinton 		case LITUPTO63:
7889668Slinton 		    argval = mode;
7899668Slinton 		    break;
7909668Slinton 
7919668Slinton 		case INDEX:
7929668Slinton 		    indexf = true;
7939668Slinton 		    --argno;
7949668Slinton 		    break;
7959668Slinton 
7969668Slinton 		case REG:
7979668Slinton 		case REGDEF:
7989668Slinton 		case AUTODEC:
7999668Slinton 		    break;
8009668Slinton 
8019668Slinton 		case AUTOINC:
8029668Slinton 		    if (r == regname[PROGCTR]) {
8039668Slinton 			switch (typelen(argtype)) {
8049668Slinton 			    case TYPB:
8059668Slinton 				argval = getdisp(addr, 1, r, amode);
8069668Slinton 				addr += 1;
8079668Slinton 				break;
8089668Slinton 
8099668Slinton 			    case TYPW:
8109668Slinton 				argval = getdisp(addr, 2, r, amode);
8119668Slinton 				addr += 2;
8129668Slinton 				break;
8139668Slinton 
8149668Slinton 			    case TYPL:
8159668Slinton 				argval = getdisp(addr, 4, r, amode);
8169668Slinton 				addr += 4;
8179668Slinton 				break;
8189668Slinton 
8199668Slinton 			    case TYPF:
8209668Slinton 				iread(&argval, addr, sizeof(argval));
8219668Slinton 				addr += 4;
8229668Slinton 				break;
8239668Slinton 
8249668Slinton 			    case TYPQ:
8259668Slinton 			    case TYPD:
8269668Slinton 				iread(&argval, addr+4, sizeof(argval));
8279668Slinton 				addr += 8;
8289668Slinton 				break;
8299668Slinton 			}
8309668Slinton 		    }
8319668Slinton 		    break;
8329668Slinton 
8339668Slinton 		case AUTOINCDEF:
8349668Slinton 		    if (r == regname[PROGCTR]) {
8359668Slinton 			argval = getdisp(addr, 4, r, amode);
8369668Slinton 			addr += 4;
8379668Slinton 		    }
8389668Slinton 		    break;
8399668Slinton 
8409668Slinton 		case BYTEDISP:
8419668Slinton 		case BYTEDISPDEF:
8429668Slinton 		    argval = getdisp(addr, 1, r, amode);
8439668Slinton 		    addr += 1;
8449668Slinton 		    break;
8459668Slinton 
8469668Slinton 		case WORDDISP:
8479668Slinton 		case WORDDISPDEF:
8489668Slinton 		    argval = getdisp(addr, 2, r, amode);
8499668Slinton 		    addr += 2;
8509668Slinton 		    break;
8519668Slinton 
8529668Slinton 		case LONGDISP:
8539668Slinton 		case LONGDISPDEF:
8549668Slinton 		    argval = getdisp(addr, 4, r, amode);
8559668Slinton 		    addr += 4;
8569668Slinton 		    break;
8579668Slinton 	    }
8589668Slinton 	}
8599668Slinton 	if (ins == O_CALLS or ins == O_CALLG) {
8609668Slinton 	    argval += 2;
8619668Slinton 	}
8629668Slinton 	if (addrstatus == BRANCH) {
8639668Slinton 	    addr = argval;
8649668Slinton 	}
8659668Slinton     }
8669668Slinton     return addr;
8679668Slinton }
8689668Slinton 
8699668Slinton /*
8709668Slinton  * Get the displacement of an instruction that uses displacement addressing.
8719668Slinton  */
8729668Slinton 
8739668Slinton private int getdisp(addr, nbytes, reg, mode)
8749668Slinton Address addr;
8759668Slinton int nbytes;
8769668Slinton String reg;
8779668Slinton int mode;
8789668Slinton {
8799668Slinton     char byte;
8809668Slinton     short hword;
8819668Slinton     int argval;
8829668Slinton 
8839668Slinton     switch (nbytes) {
8849668Slinton 	case 1:
8859668Slinton 	    iread(&byte, addr, sizeof(byte));
8869668Slinton 	    argval = byte;
8879668Slinton 	    break;
8889668Slinton 
8899668Slinton 	case 2:
8909668Slinton 	    iread(&hword, addr, sizeof(hword));
8919668Slinton 	    argval = hword;
8929668Slinton 	    break;
8939668Slinton 
8949668Slinton 	case 4:
8959668Slinton 	    iread(&argval, addr, sizeof(argval));
8969668Slinton 	    break;
8979668Slinton     }
8989668Slinton     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
8999668Slinton 	argval += addr + nbytes;
9009668Slinton     }
9019668Slinton     return argval;
9029668Slinton }
9039668Slinton 
9049668Slinton #define BP_OP       O_BPT       /* breakpoint trap */
9059668Slinton #define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */
9069668Slinton 
9079668Slinton /*
9089668Slinton  * Setting a breakpoint at a location consists of saving
9099668Slinton  * the word at the location and poking a BP_OP there.
9109668Slinton  *
9119668Slinton  * We save the locations and words on a list for use in unsetting.
9129668Slinton  */
9139668Slinton 
9149668Slinton typedef struct Savelist *Savelist;
9159668Slinton 
9169668Slinton struct Savelist {
9179668Slinton     Address location;
9189668Slinton     Byte save;
9199668Slinton     Byte refcount;
9209668Slinton     Savelist link;
9219668Slinton };
9229668Slinton 
9239668Slinton private Savelist savelist;
9249668Slinton 
9259668Slinton /*
9269668Slinton  * Set a breakpoint at the given address.  Only save the word there
9279668Slinton  * if it's not already a breakpoint.
9289668Slinton  */
9299668Slinton 
9309668Slinton public setbp(addr)
9319668Slinton Address addr;
9329668Slinton {
9339668Slinton     Byte w;
9349668Slinton     Byte save;
9359668Slinton     register Savelist newsave, s;
9369668Slinton 
9379668Slinton     for (s = savelist; s != nil; s = s->link) {
9389668Slinton 	if (s->location == addr) {
9399668Slinton 	    s->refcount++;
9409668Slinton 	    return;
9419668Slinton 	}
9429668Slinton     }
94311174Slinton     iread(&save, addr, sizeof(save));
9449668Slinton     newsave = new(Savelist);
9459668Slinton     newsave->location = addr;
9469668Slinton     newsave->save = save;
9479668Slinton     newsave->refcount = 1;
9489668Slinton     newsave->link = savelist;
9499668Slinton     savelist = newsave;
9509668Slinton     w = BP_OP;
9519668Slinton     iwrite(&w, addr, sizeof(w));
9529668Slinton }
9539668Slinton 
9549668Slinton /*
9559668Slinton  * Unset a breakpoint; unfortunately we have to search the SAVELIST
9569668Slinton  * to find the saved value.  The assumption is that the SAVELIST will
9579668Slinton  * usually be quite small.
9589668Slinton  */
9599668Slinton 
9609668Slinton public unsetbp(addr)
9619668Slinton Address addr;
9629668Slinton {
9639668Slinton     register Savelist s, prev;
9649668Slinton 
9659668Slinton     prev = nil;
9669668Slinton     for (s = savelist; s != nil; s = s->link) {
9679668Slinton 	if (s->location == addr) {
9689668Slinton 	    iwrite(&s->save, addr, sizeof(s->save));
9699668Slinton 	    s->refcount--;
9709668Slinton 	    if (s->refcount == 0) {
9719668Slinton 		if (prev == nil) {
9729668Slinton 		    savelist = s->link;
9739668Slinton 		} else {
9749668Slinton 		    prev->link = s->link;
9759668Slinton 		}
9769668Slinton 		dispose(s);
9779668Slinton 	    }
9789668Slinton 	    return;
9799668Slinton 	}
9809668Slinton 	prev = s;
9819668Slinton     }
9829668Slinton     panic("unsetbp: couldn't find address %d", addr);
9839668Slinton }
9849668Slinton 
9859668Slinton /*
9869668Slinton  * Enter a procedure by creating and executing a call instruction.
9879668Slinton  */
9889668Slinton 
9899668Slinton #define CALLSIZE 7	/* size of call instruction */
9909668Slinton 
9919668Slinton public beginproc(p, argc)
9929668Slinton Symbol p;
9939668Slinton Integer argc;
9949668Slinton {
9959668Slinton     char save[CALLSIZE];
9969668Slinton     struct {
9979668Slinton 	VaxOpcode op;
9989668Slinton 	unsigned char numargs;
9999668Slinton 	unsigned char mode;
10009668Slinton 	char addr[sizeof(long)];	/* unaligned long */
10019668Slinton     } call;
10029668Slinton     long dest;
10039668Slinton 
10049668Slinton     pc = 2;
10059668Slinton     iread(save, pc, sizeof(save));
10069668Slinton     call.op = O_CALLS;
10079668Slinton     call.numargs = argc;
10089668Slinton     call.mode = 0xef;
10099668Slinton     dest = codeloc(p) - 2 - (pc + 7);
10109668Slinton     mov(&dest, call.addr, sizeof(call.addr));
10119668Slinton     iwrite(&call, pc, sizeof(call));
10129668Slinton     setreg(PROGCTR, pc);
101316612Ssam     pstep(process, DEFSIG);
10149668Slinton     iwrite(save, pc, sizeof(save));
10159668Slinton     pc = reg(PROGCTR);
10169668Slinton     if (not isbperr()) {
10179668Slinton 	printstatus();
10189668Slinton     }
10199668Slinton }
1020