-/* Copyright (c) 1982 Regents of the University of California */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
-static char sccsid[] = "@(#)vax.c 1.2 %G%";
+#ifndef lint
+static char sccsid[] = "@(#)vax.c 5.5 (Berkeley) %G%";
+#endif not lint
+
+static char rcsid[] = "$Header: vax.c,v 1.2 88/10/26 18:50:53 donn Exp $";
/*
* Target machine dependent stuff.
#include "defs.h"
#include "machine.h"
#include "process.h"
+#include "runtime.h"
#include "events.h"
#include "main.h"
#include "symbols.h"
#include "source.h"
#include "mappings.h"
#include "object.h"
-#include "vaxops.h"
-#include <signal.h>
+#include "tree.h"
+#include "eval.h"
+#include "keywords.h"
+#include "ops.h"
#ifndef public
typedef unsigned int Address;
#define STKP 14
#define PROGCTR 15
+#define CODESTART 0
+#define FUNCOFFSET 2
+
+#define nargspassed(frame) argn(0, frame)
+
#define BITSPERBYTE 8
#define BITSPERWORD (BITSPERBYTE * sizeof(Word))
-#define nargspassed(frame) argn(0, frame)
+/*
+ * This magic macro enables us to look at the process' registers
+ * in its user structure.
+ */
+
+#define regloc(reg) (ctob(UPAGES) + (sizeof(Word) * (reg)))
#include "source.h"
#include "symbols.h"
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <machine/psl.h>
+#include <machine/pte.h>
+#include <sys/user.h>
+#undef DELETE /* XXX */
+#include <sys/vm.h>
+#include <machine/reg.h>
Address pc;
Address prtaddr;
#endif
+/*
+ * Indices into u. for use in collecting registers values.
+ */
+public int rloc[] ={
+ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
+};
+
private Address printop();
+private Optab *ioptab[256]; /* index by opcode to optab */
+private Optab *esctab[256]; /* for extended opcodes */
+
+/*
+ * Initialize the opcode lookup table.
+ */
+public optab_init()
+{
+ register Optab *p;
+
+ for (p = optab; p->iname; p++) {
+ if (p->format == O_ESCD) {
+ esctab[p->val] = p;
+ } else if (p->format != O_ESCD && p->format != O_ESCE) {
+ ioptab[p->val] = p;
+ }
+ }
+}
+
/*
* Decode and print the instructions within the given address range.
*/
}
/*
- * Hacked version of adb's VAX instruction decoder.
+ * Print the contents of the addresses within the given range
+ * according to the given format.
+ */
+
+typedef struct {
+ String name;
+ String printfstring;
+ int length;
+} Format;
+
+private Format fmt[] = {
+ { "d", " %d", sizeof(short) },
+ { "D", " %ld", sizeof(long) },
+ { "o", " %o", sizeof(short) },
+ { "O", " %lo", sizeof(long) },
+ { "x", " %04x", sizeof(short) },
+ { "X", " %08x", sizeof(long) },
+ { "b", " \\%o", sizeof(char) },
+ { "c", " '%c'", sizeof(char) },
+ { "s", "%c", sizeof(char) },
+ { "f", " %f", sizeof(float) },
+ { "g", " %g", sizeof(double) },
+ { nil, nil, 0 }
+};
+
+private Format *findformat(s)
+String s;
+{
+ register Format *f;
+
+ f = &fmt[0];
+ while (f->name != nil and not streq(f->name, s)) {
+ ++f;
+ }
+ if (f->name == nil) {
+ error("bad print format \"%s\"", s);
+ }
+ return f;
+}
+
+/*
+ * Retrieve and print out the appropriate data in the given format.
+ * Floats have to be handled specially to allow the compiler to
+ * convert them to doubles when passing to printf.
+ */
+
+private printformat (f, addr)
+Format *f;
+Address addr;
+{
+ union {
+ char charv;
+ short shortv;
+ int intv;
+ float floatv;
+ double doublev;
+ } value;
+
+ value.intv = 0;
+ dread(&value, addr, f->length);
+ if (streq(f->name, "f")) {
+ printf(f->printfstring, value.floatv);
+ } else {
+ printf(f->printfstring, value);
+ }
+}
+
+public Address printdata(lowaddr, highaddr, format)
+Address lowaddr;
+Address highaddr;
+String format;
+{
+ int n;
+ register Address addr;
+ Format *f;
+
+ if (lowaddr > highaddr) {
+ error("first address larger than second");
+ }
+ f = findformat(format);
+ n = 0;
+ for (addr = lowaddr; addr <= highaddr; addr += f->length) {
+ if (n == 0) {
+ printf("%08x: ", addr);
+ }
+ printformat(f, addr);
+ ++n;
+ if (n >= (16 div f->length)) {
+ printf("\n");
+ n = 0;
+ }
+ }
+ if (n != 0) {
+ printf("\n");
+ }
+ prtaddr = addr;
+ return addr;
+}
+
+/*
+ * The other approach is to print n items starting with a given address.
+ */
+
+public printndata(count, startaddr, format)
+int count;
+Address startaddr;
+String format;
+{
+ int i, n;
+ Address addr;
+ Format *f;
+ Boolean isstring;
+ char c;
+
+ if (count <= 0) {
+ error("non-positive repetition count");
+ }
+ f = findformat(format);
+ isstring = (Boolean) streq(f->name, "s");
+ n = 0;
+ addr = startaddr;
+ for (i = 0; i < count; i++) {
+ if (n == 0) {
+ printf("%08x: ", addr);
+ }
+ if (isstring) {
+ printf("\"");
+ dread(&c, addr, sizeof(char));
+ while (c != '\0') {
+ printchar(c);
+ ++addr;
+ dread(&c, addr, sizeof(char));
+ }
+ printf("\"\n");
+ n = 0;
+ addr += sizeof(String);
+ } else {
+ printformat(f, addr);
+ ++n;
+ if (n >= (16 div f->length)) {
+ printf("\n");
+ n = 0;
+ }
+ addr += f->length;
+ }
+ }
+ if (n != 0) {
+ printf("\n");
+ }
+ prtaddr = addr;
+}
+
+/*
+ * Print out a value according to the given format.
+ */
+
+public printvalue(v, format)
+long v;
+String format;
+{
+ Format *f;
+ char *p, *q;
+
+ f = findformat(format);
+ if (streq(f->name, "s")) {
+ putchar('"');
+ p = (char *) &v;
+ q = p + sizeof(v);
+ while (p < q) {
+ printchar(*p);
+ ++p;
+ }
+ putchar('"');
+ } else {
+ printf(f->printfstring, v);
+ }
+ putchar('\n');
+}
+
+/*
+ * Print out an execution time error.
+ * Assumes the source position of the error has been calculated.
+ *
+ * Have to check if the -r option was specified; if so then
+ * the object file information hasn't been read in yet.
+ */
+
+public printerror()
+{
+ extern Integer sys_nsig;
+ extern String sys_siglist[];
+ integer err;
+
+ if (isfinished(process)) {
+ err = exitcode(process);
+ if (err == 0) {
+ printf("\"%s\" terminated normally\n", objname);
+ } else {
+ printf("\"%s\" terminated abnormally (exit code %d)\n",
+ objname, err
+ );
+ }
+ erecover();
+ }
+ err = errnum(process);
+ putchar('\n');
+ printsig(err);
+ putchar(' ');
+ printloc();
+ putchar('\n');
+ if (curline > 0) {
+ printlines(curline, curline);
+ } else {
+ printinst(pc, pc);
+ }
+ erecover();
+}
+
+/*
+ * Print out a signal.
+ */
+
+private String illinames[] = {
+ "reserved addressing fault",
+ "privileged instruction fault",
+ "reserved operand fault"
+};
+
+private String fpenames[] = {
+ nil,
+ "integer overflow trap",
+ "integer divide by zero trap",
+ "floating overflow trap",
+ "floating/decimal divide by zero trap",
+ "floating underflow trap",
+ "decimal overflow trap",
+ "subscript out of range trap",
+ "floating overflow fault",
+ "floating divide by zero fault",
+ "floating underflow fault"
+};
+
+public printsig (signo)
+integer signo;
+{
+ integer code;
+
+ if (signo < 0 or signo > sys_nsig) {
+ printf("[signal %d]", signo);
+ } else {
+ printf("%s", sys_siglist[signo]);
+ }
+ code = errcode(process);
+ if (signo == SIGILL) {
+ if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) {
+ printf(" (%s)", illinames[code]);
+ }
+ } else if (signo == SIGFPE) {
+ if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) {
+ printf(" (%s)", fpenames[code]);
+ }
+ }
+}
+
+/*
+ * Note the termination of the program. We do this so as to avoid
+ * having the process exit, which would make the values of variables
+ * inaccessible. We do want to flush all output buffers here,
+ * otherwise it'll never get done.
+ */
+
+public endprogram()
+{
+ Integer exitcode;
+
+ stepto(nextaddr(pc, true));
+ printnews();
+ exitcode = argn(1, nil);
+ if (exitcode != 0) {
+ printf("\nexecution completed (exit code %d)\n", exitcode);
+ } else {
+ printf("\nexecution completed\n");
+ }
+ getsrcpos();
+ erecover();
+}
+
+/*
+ * Single step the machine a source line (or instruction if "inst_tracing"
+ * is true). If "isnext" is true, skip over procedure calls.
+ */
+
+private Address getcall();
+
+public dostep(isnext)
+Boolean isnext;
+{
+ register Address addr;
+ register Lineno line;
+ String filename;
+ Address startaddr;
+
+ startaddr = pc;
+ addr = nextaddr(pc, isnext);
+ if (not inst_tracing and nlhdr.nlines != 0) {
+ line = linelookup(addr);
+ while (line == 0) {
+ addr = nextaddr(addr, isnext);
+ line = linelookup(addr);
+ }
+ curline = line;
+ } else {
+ curline = 0;
+ }
+ stepto(addr);
+ filename = srcfilename(addr);
+ setsource(filename);
+}
+
+typedef char Bpinst;
+
+#define BP_OP O_BPT /* breakpoint trap */
+
+#define BP_ERRNO SIGTRAP /* signal received at a breakpoint */
+
+/*
+ * Setting a breakpoint at a location consists of saving
+ * the word at the location and poking a BP_OP there.
+ *
+ * We save the locations and words on a list for use in unsetting.
+ */
+
+typedef struct Savelist *Savelist;
+
+struct Savelist {
+ Address location;
+ Bpinst save;
+ short refcount;
+ Savelist link;
+};
+
+private Savelist savelist;
+
+/*
+ * Set a breakpoint at the given address. Only save the word there
+ * if it's not already a breakpoint.
+ */
+
+public setbp(addr)
+Address addr;
+{
+ Bpinst w, save;
+ register Savelist newsave, s;
+
+ for (s = savelist; s != nil; s = s->link) {
+ if (s->location == addr) {
+ s->refcount++;
+ return;
+ }
+ }
+ iread(&save, addr, sizeof(save));
+ newsave = new(Savelist);
+ newsave->location = addr;
+ newsave->save = save;
+ newsave->refcount = 1;
+ newsave->link = savelist;
+ savelist = newsave;
+ w = BP_OP;
+ iwrite(&w, addr, sizeof(w));
+}
+
+/*
+ * Unset a breakpoint; unfortunately we have to search the SAVELIST
+ * to find the saved value. The assumption is that the SAVELIST will
+ * usually be quite small.
+ */
+
+public unsetbp(addr)
+Address addr;
+{
+ register Savelist s, prev;
+
+ prev = nil;
+ for (s = savelist; s != nil; s = s->link) {
+ if (s->location == addr) {
+ iwrite(&s->save, addr, sizeof(s->save));
+ s->refcount--;
+ if (s->refcount == 0) {
+ if (prev == nil) {
+ savelist = s->link;
+ } else {
+ prev->link = s->link;
+ }
+ dispose(s);
+ }
+ return;
+ }
+ prev = s;
+ }
+ panic("unsetbp: couldn't find address %d", addr);
+}
+
+/*
+ * VAX instruction decoder, derived from adb.
*/
private Address printop(addr)
Address addr;
{
- Optab op;
+ register Optab *op;
VaxOpcode ins;
unsigned char mode;
int argtype, amode, argno, argval;
printf("%08x ", addr);
iread(&ins, addr, sizeof(ins));
addr += 1;
- op = optab[ins];
- printf("%s", op.iname);
- for (argno = 0; argno < op.numargs; argno++) {
+ if (ins == O_ESCF) {
+ iread(&ins, addr, sizeof(ins));
+ addr += 1;
+ op = ioptab[ins];
+ } else if (ins == O_ESCD) {
+ iread(&ins, addr, sizeof(ins));
+ addr += 1;
+ op = esctab[ins];
+ } else {
+ op = ioptab[ins];
+ }
+ if (op == nil) {
+ printf("[unrecognized opcode %#0x]\n", ins);
+ return addr;
+ }
+ printf("%s", op->iname);
+ for (argno = 0; argno < op->numargs; argno++) {
if (indexf == true) {
indexf = false;
} else if (argno == 0) {
} else {
printf(",");
}
- argtype = op.argtype[argno];
+ argtype = op->argtype[argno];
if (is_branch_disp(argtype)) {
mode = 0xAF + (typelen(argtype) << 5);
} else {
case LITUPTO31:
case LITUPTO47:
case LITUPTO63:
- if (typelen(argtype) == TYPF || typelen(argtype) ==TYPD)
+ if (typelen(argtype) == TYPF || typelen(argtype) == TYPD ||
+ typelen(argtype) == TYPG || typelen(argtype) == TYPH)
printf("$%s", fltimm[mode]);
else
printf("$%x", mode);
case TYPF:
iread(&argval, addr, sizeof(argval));
- printf("%06x", argval);
+ if ((argval & 0xffff007f) == 0x8000) {
+ printf("[reserved operand]");
+ } else {
+ printf("%g", *(float *)&argval);
+ }
addr += 4;
break;
- case TYPQ:
case TYPD:
+ /* XXX this bags the low order bits */
iread(&argval, addr, sizeof(argval));
- printf("%06x", argval);
+ if ((argval & 0xffff007f) == 0x8000) {
+ printf("[reserved operand]");
+ } else {
+ printf("%g", *(float *)&argval);
+ }
+ addr += 8;
+ break;
+
+ case TYPG:
+ case TYPQ:
iread(&argval, addr+4, sizeof(argval));
- printf("%06x", argval);
+ printf("%08x", argval);
+ iread(&argval, addr, sizeof(argval));
+ printf("%08x", argval);
addr += 8;
break;
+
+ case TYPH:
+ case TYPO:
+ iread(&argval, addr+12, sizeof(argval));
+ printf("%08x", argval);
+ iread(&argval, addr+8, sizeof(argval));
+ printf("%08x", argval);
+ iread(&argval, addr+4, sizeof(argval));
+ printf("%08x", argval);
+ iread(&argval, addr, sizeof(argval));
+ printf("%08x", argval);
+ addr += 16;
+ break;
}
}
break;
case LONGDISPDEF:
printf("*");
- argval = printdisp(addr, 4, reg, amode);
- addr += 4;
- break;
- }
- }
- if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
- for (argno = 0; argno <= argval; argno++) {
- iread(&offset, addr, sizeof(offset));
- printf("\n\t\t%d", offset);
- addr += 2;
- }
- }
- printf("\n");
- return addr;
-}
-
-/*
- * Print the displacement of an instruction that uses displacement
- * addressing.
- */
-
-private int printdisp(addr, nbytes, reg, mode)
-Address addr;
-int nbytes;
-char *reg;
-int mode;
-{
- char byte;
- short hword;
- int argval;
-
- switch (nbytes) {
- case 1:
- iread(&byte, addr, sizeof(byte));
- argval = byte;
- break;
-
- case 2:
- iread(&hword, addr, sizeof(hword));
- argval = hword;
- break;
-
- case 4:
- iread(&argval, addr, sizeof(argval));
- break;
- }
- if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
- argval += addr + nbytes;
- }
- if (reg == regname[PROGCTR]) {
- printf("%x", argval);
- } else {
- printf("%d(%s)", argval, reg);
- }
- return argval;
-}
-
-/*
- * Print the contents of the addresses within the given range
- * according to the given format.
- */
-
-typedef struct {
- String name;
- String printfstring;
- int length;
-} Format;
-
-private Format fmt[] = {
- { "d", " %d", sizeof(short) },
- { "D", " %ld", sizeof(long) },
- { "o", " %o", sizeof(short) },
- { "O", " %lo", sizeof(long) },
- { "x", " %04x", sizeof(short) },
- { "X", " %08x", sizeof(long) },
- { "b", " \\%o", sizeof(char) },
- { "c", " '%c'", sizeof(char) },
- { "s", "%c", sizeof(char) },
- { "f", " %f", sizeof(double) },
- { "g", " %g", sizeof(double) },
- { nil, nil, 0 }
-};
-
-public Address printdata(lowaddr, highaddr, format)
-Address lowaddr;
-Address highaddr;
-String format;
-{
- register int n;
- register Address addr;
- register Format *f;
- int value;
-
- if (lowaddr > highaddr) {
- error("first address larger than second");
- }
- f = &fmt[0];
- while (f->name != nil and not streq(f->name, format)) {
- ++f;
- }
- if (f->name == nil) {
- error("bad print format \"%s\"", format);
- }
- n = 0;
- value = 0;
- for (addr = lowaddr; addr <= highaddr; addr += f->length) {
- if (n == 0) {
- printf("%08x: ", addr);
- }
- dread(&value, addr, f->length);
- printf(f->printfstring, value);
- ++n;
- if (n >= (16 div f->length)) {
- putchar('\n');
- n = 0;
- }
- }
- if (n != 0) {
- putchar('\n');
- }
- prtaddr = addr;
- return addr;
-}
-
-/*
- * The other approach is to print n items starting with a given address.
- */
-
-public printndata(count, startaddr, format)
-int count;
-Address startaddr;
-String format;
-{
- register int i, n;
- register Address addr;
- register Format *f;
- register Boolean isstring;
- int value;
-
- if (count <= 0) {
- error("non-positive repetition count");
- }
- f = &fmt[0];
- while (f->name != nil and not streq(f->name, format)) {
- ++f;
- }
- if (f->name == nil) {
- error("bad print format \"%s\"", format);
- }
- isstring = (Boolean) streq(f->name, "s");
- n = 0;
- addr = startaddr;
- value = 0;
- for (i = 0; i < count; i++) {
- if (n == 0) {
- printf("%08x: ", addr);
- }
- if (isstring) {
- putchar('"');
- dread(&value, addr, sizeof(char));
- while (value != '\0') {
- printchar((char) value);
- ++addr;
- dread(&value, addr, sizeof(char));
- }
- putchar('"');
- putchar('\n');
- n = 0;
- addr += sizeof(String);
- } else {
- dread(&value, addr, f->length);
- printf(f->printfstring, value);
- ++n;
- if (n >= (16 div f->length)) {
- putchar('\n');
- n = 0;
- }
- addr += f->length;
- }
- }
- if (n != 0) {
- putchar('\n');
- }
- prtaddr = addr;
-}
-
-/*
- * Print out an execution time error.
- *
- * Have to check if the -r option was specified; if so then
- * the object file information hasn't been read in yet.
- */
-
-public printerror()
-{
- extern Integer sys_nsig;
- extern String sys_siglist[];
- String filename;
- Integer err;
-
- if (isfinished(process)) {
- printf("\"%s\" exits with code %d\n", objname, exitcode(process));
- erecover();
- }
- if (runfirst) {
- fprintf(stderr, "Entering debugger ...");
- init();
- fprintf(stderr, " type 'help' for help\n");
- }
- curline = srcline(pc);
- curfunc = whatblock(pc);
- filename = srcfilename(pc);
- setsource(filename);
- err = errnum(process);
- if (err == SIGINT) {
- printf("\n\ninterrupt ");
- printloc();
- } else if (err == SIGTRAP) {
- printf("\nerror ");
- printloc();
- } else {
- if (err < 0 or err > sys_nsig) {
- printf("\nsignal %d ", err);
- } else {
- printf("\n%s ", sys_siglist[err]);
+ argval = printdisp(addr, 4, reg, amode);
+ addr += 4;
+ break;
}
- printloc();
- }
- putchar('\n');
- if (curline > 0) {
- printlines(curline, curline);
- } else {
- printinst(pc, pc);
}
- erecover();
-}
-
-private printloc()
-{
- if (curline > 0) {
- if (nlhdr.nfiles > 1) {
- printf("at line %d in file %s", curline, cursource);
- } else {
- printf("at line %d", curline);
+ if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
+ for (argno = 0; argno <= argval; argno++) {
+ iread(&offset, addr, sizeof(offset));
+ printf("\n\t\t%d", offset);
+ addr += 2;
}
- } else {
- printf("in ");
- printname(stdout, curfunc);
- printf(" at 0x%x", pc);
}
+ printf("\n");
+ return addr;
}
/*
- * Note the termination of the program. We do this so as to avoid
- * having the process exit, which would make the values of variables
- * inaccessible. We do want to flush all output buffers here,
- * otherwise it'll never get done.
+ * Print the displacement of an instruction that uses displacement
+ * addressing.
*/
-public endprogram()
+private int printdisp(addr, nbytes, reg, mode)
+Address addr;
+int nbytes;
+char *reg;
+int mode;
{
- Integer exitcode;
-
- stepto(nextaddr(pc, true));
- printnews();
- exitcode = argn(1, nil);
- printf("\nexecution completed, exit code is %d\n", exitcode);
- getsrcpos();
- erecover();
-}
-
-/*
- * Single step the machine a source line (or instruction if "inst_tracing"
- * is true. If "isnext" is true, skip over procedure calls.
- */
+ char byte;
+ short hword;
+ int argval;
+ Symbol f;
-private Address getcall();
+ switch (nbytes) {
+ case 1:
+ iread(&byte, addr, sizeof(byte));
+ argval = byte;
+ break;
-public dostep(isnext)
-Boolean isnext;
-{
- register Address addr;
- register Lineno line;
- String filename;
+ case 2:
+ iread(&hword, addr, sizeof(hword));
+ argval = hword;
+ break;
- addr = nextaddr(pc, isnext);
- if (not inst_tracing) {
- line = linelookup(addr);
- while (line == 0) {
- addr = nextaddr(addr, isnext);
- line = linelookup(addr);
+ case 4:
+ iread(&argval, addr, sizeof(argval));
+ break;
+ }
+ if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
+ argval += addr + nbytes;
+ }
+ if (reg == regname[PROGCTR]) {
+ f = whatblock((Address) argval + 2);
+ if (codeloc(f) == argval + 2) {
+ printf("%s", symname(f));
+ } else {
+ printf("%x", argval);
+ }
+ } else {
+ if (varIsSet("$hexoffsets")) {
+ if (argval < 0) {
+ printf("-%x(%s)", -(argval), reg);
+ } else {
+ printf("%x(%s)", argval, reg);
+ }
+ } else {
+ printf("%d(%s)", argval, reg);
}
}
- stepto(addr);
- curline = line;
- filename = srcfilename(addr);
- setsource(filename);
+ return argval;
}
/*
* that branches is the branch address (or relative offset).
*/
+private Address findnextaddr();
+
public Address nextaddr(startaddr, isnext)
Address startaddr;
+boolean isnext;
+{
+ Address addr;
+
+ addr = usignal(process);
+ if (addr == 0 or addr == 1) {
+ addr = findnextaddr(startaddr, isnext);
+ }
+ return addr;
+}
+
+/*
+ * Determine if it's ok to skip function f entered by instruction ins.
+ * If so, we're going to compute the return address and step to it.
+ * Therefore we cannot skip over a function entered by a jsb or bsb,
+ * since the return address is not easily computed for them.
+ */
+
+private boolean skipfunc (ins, f)
+VaxOpcode ins;
+Symbol f;
+{
+ boolean b;
+
+ b = (boolean) (
+ ins != O_JSB and ins != O_BSBB and ins != O_BSBW and
+ not inst_tracing and nlhdr.nlines != 0 and
+ nosource(curfunc) and canskip(curfunc)
+ );
+ return b;
+}
+
+private Address findnextaddr(startaddr, isnext)
+Address startaddr;
Boolean isnext;
{
register Address addr;
- Optab op;
- VaxOpcode ins;
+ register Optab *op;
+ VaxOpcode ins, ins2;
unsigned char mode;
int argtype, amode, argno, argval;
String r;
addr = startaddr;
iread(&ins, addr, sizeof(ins));
switch (ins) {
+ /*
+ * It used to be that unconditional jumps and branches were handled
+ * by taking their destination address as the next address. While
+ * saving the cost of starting up the process, this approach
+ * doesn't work when jumping indirect (since the value in the
+ * register might not yet have been set).
+ *
+ * So unconditional jumps and branches are now handled the same way
+ * as conditional jumps and branches.
+ *
case O_BRB:
case O_BRW:
- case O_JMP:
addrstatus = BRANCH;
break;
+ *
+ */
case O_BSBB:
case O_BSBW:
case O_JSB:
case O_CALLG:
case O_CALLS:
- if (isnext) {
- addrstatus = SEQUENTIAL;
- } else {
+ addrstatus = KNOWN;
+ stepto(addr);
+ pstep(process, DEFSIG);
+ addr = reg(PROGCTR);
+ pc = addr;
+ setcurfunc(whatblock(pc));
+ if (not isbperr()) {
+ printstatus();
+ /* NOTREACHED */
+ }
+ bpact();
+ if (isnext or skipfunc(ins, curfunc)) {
addrstatus = KNOWN;
+ addr = return_addr();
stepto(addr);
- pstep(process);
- addr = reg(PROGCTR);
- pc = addr;
+ bpact();
+ } else {
callnews(/* iscall = */ true);
- if (not isbperr()) {
- printstatus();
- } else {
- bpact();
- }
}
break;
case O_RSB:
case O_RET:
addrstatus = KNOWN;
- callnews(/* iscall = */ false);
- addr = return_addr();
stepto(addr);
+ callnews(/* iscall = */ false);
+ pstep(process, DEFSIG);
+ addr = reg(PROGCTR);
+ pc = addr;
+ if (not isbperr()) {
+ printstatus();
+ }
+ bpact();
break;
+ case O_BRB: case O_BRW:
+ case O_JMP: /* because it may be jmp (r1) */
case O_BNEQ: case O_BEQL: case O_BGTR:
case O_BLEQ: case O_BGEQ: case O_BLSS:
case O_BGTRU: case O_BLEQU: case O_BVC:
case O_BBCCI: case O_BLBS: case O_BLBC:
case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
case O_SOBGEQ: case O_SOBGTR:
+ case O_ESCF: /* bugchecks */
+ branches:
addrstatus = KNOWN;
stepto(addr);
- pstep(process);
+ pstep(process, DEFSIG);
addr = reg(PROGCTR);
pc = addr;
if (not isbperr()) {
}
break;
+ case O_ESCD:
+ iread(&ins2, addr+1, sizeof(ins2));
+ if (ins2 == O_ACBF || ins2 == O_ACBD)
+ /* actually ACBG and ACBH */
+ goto branches;
+ /* fall through */
+
default:
addrstatus = SEQUENTIAL;
break;
}
if (addrstatus != KNOWN) {
addr += 1;
- op = optab[ins];
- for (argno = 0; argno < op.numargs; argno++) {
+ if (ins == O_ESCD) {
+ ins = ins2;
+ addr += 1;
+ op = esctab[ins];
+ if (op == nil) {
+ printf("[bad extended opcode %#x in findnextaddr]\n", ins);
+ return addr;
+ }
+ } else {
+ op = ioptab[ins];
+ if (op == nil) {
+ printf("[bad opcode %#x in findnextaddr]\n", ins);
+ return addr;
+ }
+ }
+ for (argno = 0; argno < op->numargs; argno++) {
if (indexf == true) {
indexf = false;
}
- argtype = op.argtype[argno];
+ argtype = op->argtype[argno];
if (is_branch_disp(argtype)) {
mode = 0xAF + (typelen(argtype) << 5);
} else {
case TYPQ:
case TYPD:
+ case TYPG:
iread(&argval, addr+4, sizeof(argval));
addr += 8;
break;
+
+ case TYPO:
+ case TYPH:
+ iread(&argval, addr+12, sizeof(argval));
+ addr += 16;
+ break;
}
}
break;
return argval;
}
-#define BP_OP O_BPT /* breakpoint trap */
-#define BP_ERRNO SIGTRAP /* signal received at a breakpoint */
-
/*
- * Setting a breakpoint at a location consists of saving
- * the word at the location and poking a BP_OP there.
- *
- * We save the locations and words on a list for use in unsetting.
+ * Enter a procedure by creating and executing a call instruction.
*/
-typedef struct Savelist *Savelist;
+#define CALLSIZE 7 /* size of call instruction */
-struct Savelist {
- Address location;
- Byte save;
- Byte refcount;
- Savelist link;
-};
+public beginproc(p, argc)
+Symbol p;
+Integer argc;
+{
+ char save[CALLSIZE];
+ struct {
+ VaxOpcode op;
+ unsigned char numargs;
+ unsigned char mode;
+ char addr[sizeof(long)]; /* unaligned long */
+ } call;
+ long dest;
-private Savelist savelist;
+ pc = 2;
+ iread(save, pc, sizeof(save));
+ call.op = O_CALLS;
+ call.numargs = argc;
+ call.mode = 0xef;
+ dest = codeloc(p) - 2 - (pc + 7);
+ mov(&dest, call.addr, sizeof(call.addr));
+ iwrite(&call, pc, sizeof(call));
+ setreg(PROGCTR, pc);
+ pstep(process, DEFSIG);
+ iwrite(save, pc, sizeof(save));
+ pc = reg(PROGCTR);
+ if (not isbperr()) {
+ printstatus();
+ }
+}
/*
- * Set a breakpoint at the given address. Only save the word there
- * if it's not already a breakpoint.
+ * Special variables for debugging the kernel.
*/
-public setbp(addr)
-Address addr;
+public integer masterpcbb;
+public integer slr;
+public struct pte *sbr;
+private struct pcb pcb;
+
+public getpcb ()
{
- Byte w;
- Byte save;
- register Savelist newsave, s;
+ integer i;
+
+ fseek(corefile, masterpcbb & ~0x80000000, 0);
+ get(corefile, pcb);
+ pcb.pcb_p0lr &= ~AST_CLR;
+ printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n",
+ pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr
+ );
+ setreg(0, pcb.pcb_r0);
+ setreg(1, pcb.pcb_r1);
+ setreg(2, pcb.pcb_r2);
+ setreg(3, pcb.pcb_r3);
+ setreg(4, pcb.pcb_r4);
+ setreg(5, pcb.pcb_r5);
+ setreg(6, pcb.pcb_r6);
+ setreg(7, pcb.pcb_r7);
+ setreg(8, pcb.pcb_r8);
+ setreg(9, pcb.pcb_r9);
+ setreg(10, pcb.pcb_r10);
+ setreg(11, pcb.pcb_r11);
+ setreg(ARGP, pcb.pcb_ap);
+ setreg(FRP, pcb.pcb_fp);
+ setreg(STKP, pcb.pcb_ksp);
+ setreg(PROGCTR, pcb.pcb_pc);
+}
- for (s = savelist; s != nil; s = s->link) {
- if (s->location == addr) {
- s->refcount++;
- return;
- }
- }
- iread(&save, addr, sizeof(addr));
- newsave = new(Savelist);
- newsave->location = addr;
- newsave->save = save;
- newsave->refcount = 1;
- newsave->link = savelist;
- savelist = newsave;
- w = BP_OP;
- iwrite(&w, addr, sizeof(w));
+public copyregs (savreg, reg)
+Word savreg[], reg[];
+{
+ reg[0] = savreg[R0];
+ reg[1] = savreg[R1];
+ reg[2] = savreg[R2];
+ reg[3] = savreg[R3];
+ reg[4] = savreg[R4];
+ reg[5] = savreg[R5];
+ reg[6] = savreg[R6];
+ reg[7] = savreg[R7];
+ reg[8] = savreg[R8];
+ reg[9] = savreg[R9];
+ reg[10] = savreg[R10];
+ reg[11] = savreg[R11];
+ reg[ARGP] = savreg[AP];
+ reg[FRP] = savreg[FP];
+ reg[STKP] = savreg[SP];
+ reg[PROGCTR] = savreg[PC];
}
/*
- * Unset a breakpoint; unfortunately we have to search the SAVELIST
- * to find the saved value. The assumption is that the SAVELIST will
- * usually be quite small.
+ * Map a virtual address to a physical address.
*/
-public unsetbp(addr)
+public Address vmap (addr)
Address addr;
{
- register Savelist s, prev;
+ Address r;
+ integer v, n;
+ struct pte pte;
+
+ r = addr & ~0xc0000000;
+ v = btop(r);
+ switch (addr&0xc0000000) {
+ case 0xc0000000:
+ case 0x80000000:
+ /*
+ * In system space, so get system pte.
+ * If it is valid or reclaimable then the physical address
+ * is the combination of its page number and the page offset
+ * of the original address.
+ */
+ if (v >= slr) {
+ error("address %x out of segment", addr);
+ }
+ r = ((long) (sbr + v)) & ~0x80000000;
+ goto simple;
+
+ case 0x40000000:
+ /*
+ * In p1 space, must not be in shadow region.
+ */
+ if (v < pcb.pcb_p1lr) {
+ error("address %x out of segment", addr);
+ }
+ r = (Address) (pcb.pcb_p1br + v);
+ break;
- prev = nil;
- for (s = savelist; s != nil; s = s->link) {
- if (s->location == addr) {
- iwrite(&s->save, addr, sizeof(s->save));
- s->refcount--;
- if (s->refcount == 0) {
- if (prev == nil) {
- savelist = s->link;
- } else {
- prev->link = s->link;
- }
- dispose(s);
+ case 0x00000000:
+ /*
+ * In p0 space, must not be off end of region.
+ */
+ if (v >= pcb.pcb_p0lr) {
+ error("address %x out of segment", addr);
}
- return;
- }
- prev = s;
+ r = (Address) (pcb.pcb_p0br + v);
+ break;
+
+ default:
+ /* do nothing */
+ break;
}
- panic("unsetbp: couldn't find address %d", addr);
+ /*
+ * For p0/p1 address, user-level page table should be in
+ * kernel virtual memory. Do second-level indirect by recursing.
+ */
+ if ((r & 0x80000000) == 0) {
+ error("bad p0br or p1br in pcb");
+ }
+ r = vmap(r);
+simple:
+ /*
+ * "r" is now the address of the pte of the page
+ * we are interested in; get the pte and paste up the physical address.
+ */
+ fseek(corefile, r, 0);
+ n = fread(&pte, sizeof(pte), 1, corefile);
+ if (n != 1) {
+ error("page table botch (fread at %x returns %d)", r, n);
+ }
+ if (pte.pg_v == 0 and (pte.pg_fod != 0 or pte.pg_pfnum == 0)) {
+ error("page no valid or reclamable");
+ }
+ return (addr&PGOFSET) + ((Address) ptob(pte.pg_pfnum));
}
/*
- * Predicate to test if the reason the process stopped was because
- * of a breakpoint.
+ * Extract a bit field from an integer.
*/
-public Boolean isbperr()
+public integer extractField (s)
+Symbol s;
{
- return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP);
+ integer n, nbytes, r;
+
+ n = 0;
+ nbytes = size(s);
+ if (nbytes > sizeof(n)) {
+ printf("[bad size in extractField -- word assumed]\n");
+ nbytes = sizeof(n);
+ }
+ popn(nbytes, &n);
+ r = n >> (s->symvalue.field.offset mod BITSPERBYTE);
+ r &= ((1 << s->symvalue.field.length) - 1);
+ return r;
}
/*
- * Enter a procedure by creating and executing a call instruction.
+ * Change the length of a value in memory according to a given difference
+ * in the lengths of its new and old types.
*/
-#define CALLSIZE 7 /* size of call instruction */
-
-public beginproc(p, argc)
-Symbol p;
-Integer argc;
+public loophole (oldlen, newlen)
+integer oldlen, newlen;
{
- char save[CALLSIZE];
- struct {
- VaxOpcode op;
- unsigned char numargs;
- unsigned char mode;
- char addr[sizeof(long)]; /* unaligned long */
- } call;
- long dest;
+ integer n, i;
- pc = 2;
- iread(save, pc, sizeof(save));
- call.op = O_CALLS;
- call.numargs = argc;
- call.mode = 0xef;
- dest = codeloc(p) - 2 - (pc + 7);
- mov(&dest, call.addr, sizeof(call.addr));
- iwrite(&call, pc, sizeof(call));
- setreg(PROGCTR, pc);
- pstep(process);
- iwrite(save, pc, sizeof(save));
- pc = reg(PROGCTR);
- if (not isbperr()) {
- printstatus();
+ n = newlen - oldlen;
+ if (n > 0) {
+ for (i = 0; i < n; i++) {
+ sp[i] = '\0';
+ }
}
+ sp += n;
}