126326Ssam /*
238105Sbostic * Copyright (c) 1985 The Regents of the University of California.
338105Sbostic * All rights reserved.
438105Sbostic *
5*42687Sbostic * %sccs.include.redist.c%
626326Ssam */
726326Ssam
826326Ssam #ifndef lint
9*42687Sbostic static char sccsid[] = "@(#)tahoe.c 5.8 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
1126326Ssam
1226326Ssam /*
1326326Ssam * Target machine dependent stuff.
1426326Ssam */
1526326Ssam
1626326Ssam #include "defs.h"
1726326Ssam #include "machine.h"
1826326Ssam #include "process.h"
1926326Ssam #include "runtime.h"
2026326Ssam #include "events.h"
2126326Ssam #include "main.h"
2226326Ssam #include "symbols.h"
2326326Ssam #include "source.h"
2426326Ssam #include "mappings.h"
2526326Ssam #include "object.h"
2626326Ssam #include "keywords.h"
2726326Ssam #include "ops.h"
2833338Sdonn #include "eval.h"
2926326Ssam #include <signal.h>
3026326Ssam
3126326Ssam #ifndef public
3226326Ssam typedef unsigned int Address;
3326326Ssam typedef unsigned char Byte;
3426326Ssam typedef unsigned int Word;
3526326Ssam
3626326Ssam #define NREG 16
3726326Ssam
3826326Ssam #define FRP 13
3926326Ssam #define STKP 14
4026326Ssam #define PROGCTR 15
4126326Ssam
4233338Sdonn #define CODESTART 0
4333338Sdonn #define FUNCOFFSET 2
4433338Sdonn
4526326Ssam #define BITSPERBYTE 8
4626326Ssam #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
4726326Ssam
4826337Ssam /*
4933338Sdonn * This magic macro enables us to look at the process' registers
5033338Sdonn * in its user structure.
5126337Ssam */
5226326Ssam
5333338Sdonn #define regloc(reg) (ctob(UPAGES) + (sizeof(Word) * (reg)))
5433338Sdonn
5533338Sdonn #define nargspassed(frame) (((argn(-1, frame)&0xffff)-4)/4)
5633338Sdonn
5726337Ssam #define SYSBASE 0xc0000000 /* base of system address space */
5826337Ssam #define physaddr(a) ((a) &~ 0xc0000000)
5926337Ssam
6026326Ssam #include "source.h"
6126326Ssam #include "symbols.h"
6226337Ssam #include <sys/param.h>
6326337Ssam #include <machine/psl.h>
6426337Ssam #include <sys/user.h>
6533338Sdonn #undef DELETE /* XXX */
6626337Ssam #include <sys/vm.h>
6726337Ssam #include <machine/reg.h>
6826337Ssam #include <machine/pte.h>
6926326Ssam
7026326Ssam Address pc;
7126326Ssam Address prtaddr;
7226326Ssam
7326326Ssam #endif
7426326Ssam
7526337Ssam /*
7626337Ssam * Indices into u. for use in collecting registers values.
7726337Ssam */
7826337Ssam public int rloc[] =
7926337Ssam { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, FP, SP, PC };
8026337Ssam
8126326Ssam private Address printop();
8226326Ssam
8326326Ssam Optab *ioptab[256]; /* index by opcode to optab */
8426326Ssam /*
8526326Ssam * Initialize the opcode lookup table.
8626326Ssam */
optab_init()8726326Ssam public optab_init()
8826326Ssam {
8926326Ssam register Optab *p;
9026326Ssam
9126326Ssam for (p = optab; p->iname; p++)
9226326Ssam ioptab[p->val & 0xff] = p;
9326326Ssam }
9426326Ssam
9526326Ssam /*
9626326Ssam * Decode and print the instructions within the given address range.
9726326Ssam */
printinst(lowaddr,highaddr)9826326Ssam public printinst(lowaddr, highaddr)
9926326Ssam Address lowaddr, highaddr;
10026326Ssam {
10126326Ssam register Address addr;
10226326Ssam
10326326Ssam for (addr = lowaddr; addr <= highaddr; )
10426326Ssam addr = printop(addr);
10526326Ssam prtaddr = addr;
10626326Ssam }
10726326Ssam
10826326Ssam /*
10926326Ssam * Another approach: print n instructions starting at the given address.
11026326Ssam */
printninst(count,addr)11126326Ssam public printninst(count, addr)
11226326Ssam int count;
11326326Ssam Address addr;
11426326Ssam {
11526326Ssam register Integer i;
11626326Ssam register Address newaddr;
11726326Ssam
11826326Ssam if (count <= 0)
11926326Ssam error("non-positive repetition count");
12026326Ssam for (newaddr = addr, i = 0; i < count; i++)
12126326Ssam newaddr = printop(newaddr);
12226326Ssam prtaddr = newaddr;
12326326Ssam }
12426326Ssam
12526326Ssam /*
12626326Ssam * Hacked version of adb's instruction decoder.
12726326Ssam */
printop(addr)12826326Ssam private Address printop(addr)
12926326Ssam Address addr;
13026326Ssam {
13126326Ssam register Optab *op;
13226326Ssam Opcode ins;
13326326Ssam unsigned char mode;
13426326Ssam int argtype, amode, argno, argval, r;
13526326Ssam String reg;
13626326Ssam Boolean indexf;
13726326Ssam short offset;
13826326Ssam
13926326Ssam argval = 0;
14026326Ssam indexf = false;
14126326Ssam printf("%08x ", addr);
14226326Ssam iread(&ins, addr, sizeof(ins));
14326326Ssam addr += 1;
14426326Ssam op = ioptab[ins];
14526326Ssam printf("%s", op->iname);
14626326Ssam for (argno = 0; argno < op->numargs; argno++) {
14726326Ssam if (indexf == true)
14826326Ssam indexf = false;
14926326Ssam else
15026326Ssam printf(argno == 0 ? "\t" : ",");
15126326Ssam argtype = op->argtype[argno];
15226326Ssam if (is_branch_disp(argtype))
15326326Ssam mode = 0xAF + (typelen(argtype) << 5);
15426326Ssam else
15526326Ssam iread(&mode, addr, sizeof(mode)), addr += 1;
15626326Ssam reg = regname[regnm(mode)];
15726326Ssam amode = addrmode(mode);
15826326Ssam switch (amode) {
15926326Ssam
16026326Ssam case LITSHORT: case LITUPTO31:
16126326Ssam case LITUPTO47: case LITUPTO63:
16226326Ssam if (ins == O_KCALL && mode >= 0 && mode < SYSSIZE &&
16326326Ssam systab[mode])
16426326Ssam printf("$%s", systab[mode]);
16526326Ssam else
16626326Ssam printf("$%x", mode);
16726326Ssam argval = mode;
16826326Ssam break;
16926326Ssam
17026326Ssam case INDEX:
17126326Ssam printf("[%s]", reg);
17226326Ssam indexf = true;
17326326Ssam argno--;
17426326Ssam break;
17526326Ssam
17626326Ssam case REG:
17726326Ssam printf("%s", reg);
17826326Ssam break;
17926326Ssam
18026326Ssam case REGDEF:
18126326Ssam printf("(%s)", reg);
18226326Ssam break;
18326326Ssam
18426326Ssam case AUTODEC:
18526326Ssam printf("-(%s)", reg);
18626326Ssam break;
18726326Ssam
18826326Ssam case AUTOINC:
18926326Ssam r = mode & 0xf;
19026326Ssam if (r == 0xf || r == 8 || r == 9) {
19126326Ssam int size = (mode&03) + 1;
19226326Ssam
19326326Ssam /* immediate mode */
19426326Ssam printf("$");
19526326Ssam argval = printdisp(addr, size,
19626326Ssam regname[PROGCTR], amode);
19726326Ssam addr += size;
19826326Ssam } else
19926326Ssam printf("(%s)+", reg);
20026326Ssam break;
20126326Ssam
20226326Ssam case AUTOINCDEF:
20326326Ssam if ((mode&0xf) == 0xf) {
20426326Ssam printf("*$");
20526326Ssam argval = printdisp(addr, 4, reg, amode);
20626326Ssam addr += 4;
20726326Ssam } else
20826326Ssam printf("*(%s)+", reg);
20926326Ssam break;
21026326Ssam
21126326Ssam case BYTEDISP:
21226326Ssam argval = printdisp(addr, 1, reg, amode);
21326326Ssam addr += 1;
21426326Ssam break;
21526326Ssam
21626326Ssam case BYTEDISPDEF:
21726326Ssam printf("*");
21826326Ssam argval = printdisp(addr, 1, reg, amode);
21926326Ssam addr += 1;
22026326Ssam break;
22126326Ssam
22226326Ssam case WORDDISP:
22326326Ssam argval = printdisp(addr, 2, reg, amode);
22426326Ssam addr += 2;
22526326Ssam break;
22626326Ssam
22726326Ssam case WORDDISPDEF:
22826326Ssam printf("*");
22926326Ssam argval = printdisp(addr, 2, reg, amode);
23026326Ssam addr += 2;
23126326Ssam break;
23226326Ssam
23326326Ssam case LONGDISP:
23426326Ssam argval = printdisp(addr, 4, reg, amode);
23526326Ssam addr += 4;
23626326Ssam break;
23726326Ssam
23826326Ssam case LONGDISPDEF:
23926326Ssam printf("*");
24026326Ssam argval = printdisp(addr, 4, reg, amode);
24126326Ssam addr += 4;
24226326Ssam break;
24326326Ssam }
24426326Ssam }
24526326Ssam if (ins == O_CASEL)
24626326Ssam for (argno = 0; argno <= argval; argno++) {
24726326Ssam iread(&offset, addr, sizeof(offset));
24826326Ssam printf("\n\t\t%d", offset);
24926326Ssam addr += 2;
25026326Ssam }
25126326Ssam printf("\n");
25226326Ssam return (addr);
25326326Ssam }
25426326Ssam
25526326Ssam /*
25626326Ssam * Print the displacement of an instruction that uses displacement
25726326Ssam * addressing.
25826326Ssam */
printdisp(addr,nbytes,reg,mode)25926326Ssam private int printdisp(addr, nbytes, reg, mode)
26026326Ssam Address addr;
26126326Ssam int nbytes;
26226326Ssam char *reg;
26326326Ssam int mode;
26426326Ssam {
26526326Ssam char byte;
26626326Ssam short hword;
26726326Ssam int argval;
26826326Ssam Symbol f;
26926326Ssam
27026326Ssam switch (nbytes) {
27126326Ssam
27226326Ssam case 1:
27326326Ssam iread(&byte, addr, sizeof(byte));
27426326Ssam argval = byte;
27526326Ssam break;
27626326Ssam
27726326Ssam case 2:
27826326Ssam iread(&hword, addr, sizeof(hword));
27926326Ssam argval = hword;
28026326Ssam break;
28126326Ssam
28226326Ssam case 4:
28326326Ssam iread(&argval, addr, sizeof(argval));
28426326Ssam break;
28526326Ssam }
28626326Ssam if (reg == regname[PROGCTR] && mode >= BYTEDISP)
28726326Ssam argval += addr + nbytes;
28826326Ssam if (reg == regname[PROGCTR]) {
28926326Ssam f = whatblock((Address) argval + 2);
29026326Ssam if (codeloc(f) == argval + 2)
29126326Ssam printf("%s", symname(f));
29226326Ssam else
29326326Ssam printf("%x", argval);
29426326Ssam } else {
29526326Ssam if (varIsSet("$hexoffsets")) {
29626326Ssam if (argval < 0)
29726326Ssam printf("-%x(%s)", -(argval), reg);
29826326Ssam else
29926326Ssam printf("%x(%s)", argval, reg);
30026326Ssam } else
30126326Ssam printf("%d(%s)", argval, reg);
30226326Ssam }
30326326Ssam return (argval);
30426326Ssam }
30526326Ssam
30626326Ssam /*
30726326Ssam * Print the contents of the addresses within the given range
30826326Ssam * according to the given format.
30926326Ssam */
31026326Ssam typedef struct {
31126326Ssam String name;
31226326Ssam String printfstring;
31326326Ssam int length;
31426326Ssam } Format;
31526326Ssam
31626326Ssam private Format fmt[] = {
31726326Ssam { "d", " %d", sizeof(short) },
31826326Ssam { "D", " %ld", sizeof(long) },
31926326Ssam { "o", " %o", sizeof(short) },
32026326Ssam { "O", " %lo", sizeof(long) },
32126326Ssam { "x", " %04x", sizeof(short) },
32226326Ssam { "X", " %08x", sizeof(long) },
32326326Ssam { "b", " \\%o", sizeof(char) },
32426326Ssam { "c", " '%c'", sizeof(char) },
32526326Ssam { "s", "%c", sizeof(char) },
32626326Ssam { "f", " %f", sizeof(float) },
32726326Ssam { "g", " %g", sizeof(double) },
32826326Ssam { nil, nil, 0 }
32926326Ssam };
33026326Ssam
findformat(s)33126326Ssam private Format *findformat(s)
33226326Ssam String s;
33326326Ssam {
33426326Ssam register Format *f;
33526326Ssam
33626326Ssam for (f = &fmt[0]; f->name != nil && !streq(f->name, s); f++)
33726326Ssam ;
33826326Ssam if (f->name == nil)
33926326Ssam error("bad print format \"%s\"", s);
34026326Ssam return (f);
34126326Ssam }
34226326Ssam
printdata(lowaddr,highaddr,format)34326326Ssam public Address printdata(lowaddr, highaddr, format)
34426326Ssam Address lowaddr;
34526326Ssam Address highaddr;
34626326Ssam String format;
34726326Ssam {
34826326Ssam register int n;
34926326Ssam register Address addr;
35026326Ssam register Format *f;
35126326Ssam int value;
35226326Ssam
35326326Ssam if (lowaddr > highaddr)
35426326Ssam error("first address larger than second");
35526326Ssam f = findformat(format);
35626326Ssam n = 0;
35726326Ssam value = 0;
35826326Ssam for (addr = lowaddr; addr <= highaddr; addr += f->length) {
35926326Ssam if (n == 0)
36026326Ssam printf("%08x: ", addr);
36126326Ssam dread(&value, addr, f->length);
36226326Ssam printf(f->printfstring, value);
36326326Ssam ++n;
36426326Ssam if (n >= (16 div f->length)) {
36526326Ssam putchar('\n');
36626326Ssam n = 0;
36726326Ssam }
36826326Ssam }
36926326Ssam if (n != 0)
37026326Ssam putchar('\n');
37126326Ssam prtaddr = addr;
37226326Ssam return (addr);
37326326Ssam }
37426326Ssam
37526326Ssam /*
37626326Ssam * The other approach is to print n items starting with a given address.
37726326Ssam */
37826326Ssam
printndata(count,startaddr,format)37926326Ssam public printndata(count, startaddr, format)
38026326Ssam int count;
38126326Ssam Address startaddr;
38226326Ssam String format;
38326326Ssam {
38426326Ssam register int i, n;
38526326Ssam register Address addr;
38626326Ssam register Format *f;
38726326Ssam register Boolean isstring;
38826326Ssam char c;
38926326Ssam union {
39026326Ssam char charv;
39126326Ssam short shortv;
39226326Ssam int intv;
39326326Ssam float floatv;
39426326Ssam double doublev;
39526326Ssam } value;
39626326Ssam
39726326Ssam if (count <= 0)
39826326Ssam error("non-positive repetition count");
39926326Ssam f = findformat(format);
40026326Ssam isstring = (Boolean) streq(f->name, "s");
40126326Ssam n = 0;
40226326Ssam addr = startaddr;
40326326Ssam value.intv = 0;
40426326Ssam for (i = 0; i < count; i++) {
40526326Ssam if (n == 0)
40626326Ssam printf("%08x: ", addr);
40726326Ssam if (isstring) {
40826326Ssam putchar('"');
40926326Ssam dread(&c, addr, sizeof(char));
41026326Ssam while (c != '\0') {
41126326Ssam printchar(c);
41226326Ssam ++addr;
41326326Ssam dread(&c, addr, sizeof(char));
41426326Ssam }
41526326Ssam putchar('"');
41626326Ssam putchar('\n');
41726326Ssam n = 0;
41826326Ssam addr += sizeof(String);
41926326Ssam continue;
42026326Ssam }
42126326Ssam dread(&value, addr, f->length);
42226326Ssam printf(f->printfstring, value);
42326326Ssam ++n;
42426326Ssam if (n >= (16 div f->length)) {
42526326Ssam putchar('\n');
42626326Ssam n = 0;
42726326Ssam }
42826326Ssam addr += f->length;
42926326Ssam }
43026326Ssam if (n != 0)
43126326Ssam putchar('\n');
43226326Ssam prtaddr = addr;
43326326Ssam }
43426326Ssam
43526326Ssam /*
43626326Ssam * Print out a value according to the given format.
43726326Ssam */
printvalue(v,format)43826326Ssam public printvalue(v, format)
43926326Ssam long v;
44026326Ssam String format;
44126326Ssam {
44226326Ssam Format *f;
44326326Ssam char *p, *q;
44426326Ssam
44526326Ssam f = findformat(format);
44626326Ssam if (streq(f->name, "s")) {
44726326Ssam putchar('"');
44826326Ssam for (p = (char *) &v, q = p + sizeof(v); p < q; ++p)
44926326Ssam printchar(*p);
45026326Ssam putchar('"');
45126326Ssam } else
45226326Ssam printf(f->printfstring, v);
45326326Ssam putchar('\n');
45426326Ssam }
45526326Ssam
45626326Ssam /*
45726326Ssam * Print out an execution time error.
45826326Ssam * Assumes the source position of the error has been calculated.
45926326Ssam *
46026326Ssam * Have to check if the -r option was specified; if so then
46126326Ssam * the object file information hasn't been read in yet.
46226326Ssam */
printerror()46326326Ssam public printerror()
46426326Ssam {
46526326Ssam extern Integer sys_nsig;
46626326Ssam extern String sys_siglist[];
46726326Ssam integer err;
46826326Ssam
46926326Ssam if (isfinished(process)) {
47026326Ssam err = exitcode(process);
47126326Ssam if (err) {
47226326Ssam printf("\"%s\" terminated abnormally (exit code %d)\n",
47326326Ssam objname, err);
47426326Ssam erecover();
47526326Ssam } else
47626326Ssam printf("\"%s\" terminated normally\n", objname);
47726326Ssam }
47826326Ssam if (runfirst) {
47926326Ssam fprintf(stderr, "Entering debugger ...\n");
48026326Ssam init();
48126326Ssam }
48226326Ssam err = errnum(process);
48326326Ssam putchar('\n');
48426326Ssam printsig(err);
48526326Ssam putchar(' ');
48626326Ssam printloc();
48726326Ssam putchar('\n');
48826326Ssam if (curline > 0)
48926326Ssam printlines(curline, curline);
49026326Ssam else
49126326Ssam printinst(pc, pc);
49226326Ssam erecover();
49326326Ssam }
49426326Ssam
49526326Ssam /*
49626326Ssam * Print out a signal.
49726326Ssam */
49826326Ssam private String illinames[] = {
49926326Ssam "reserved addressing fault",
50033338Sdonn "privileged instruction fault",
50126326Ssam "reserved operand fault"
50226326Ssam };
50326326Ssam #define NILLINAMES (sizeof (illinames) / sizeof (illinames[0]))
50426326Ssam
50526326Ssam private String fpenames[] = {
50626326Ssam nil,
50726326Ssam "integer overflow trap",
50826326Ssam "integer divide by zero trap",
50926326Ssam "floating point divide by zero trap",
51026326Ssam "floating point overflow trap",
51126326Ssam "floating point underflow trap",
51226326Ssam };
51326326Ssam #define NFPENAMES (sizeof (fpenames) / sizeof (fpenames[0]))
51426326Ssam
printsig(signo)51526326Ssam public printsig(signo)
51626326Ssam integer signo;
51726326Ssam {
51826326Ssam integer code;
51926326Ssam
52026326Ssam if (signo < 0 or signo > sys_nsig)
52126326Ssam printf("[signal %d]", signo);
52226326Ssam else
52326326Ssam printf("%s", sys_siglist[signo]);
52426326Ssam code = errcode(process);
52526326Ssam if (signo == SIGILL)
52626326Ssam if (code >= 0 && code < NILLINAMES)
52726326Ssam printf(" (%s)", illinames[code]);
52826326Ssam if (signo == SIGFPE)
52926326Ssam if (code > 0 and code < NFPENAMES)
53026326Ssam printf(" (%s)", fpenames[code]);
53126326Ssam }
53226326Ssam
53326326Ssam /*
53426326Ssam * Note the termination of the program. We do this so as to avoid
53526326Ssam * having the process exit, which would make the values of variables
53626326Ssam * inaccessible. We do want to flush all output buffers here,
53726326Ssam * otherwise it'll never get done.
53826326Ssam */
endprogram()53926326Ssam public endprogram()
54026326Ssam {
54126326Ssam Integer exitcode;
54226326Ssam
54326326Ssam stepto(nextaddr(pc, true));
54426326Ssam printnews();
54526326Ssam exitcode = argn(1, nil);
54626326Ssam if (exitcode != 0)
54726326Ssam printf("\nexecution completed (exit code %d)\n", exitcode);
54826326Ssam else
54926326Ssam printf("\nexecution completed\n");
55026326Ssam getsrcpos();
55126326Ssam erecover();
55226326Ssam }
55326326Ssam
55426326Ssam private Address getcall();
55526326Ssam /*
55626326Ssam * Single step the machine a source line (or instruction if "inst_tracing"
55726326Ssam * is true). If "isnext" is true, skip over procedure calls.
55826326Ssam */
dostep(isnext)55926326Ssam public dostep(isnext)
56026326Ssam Boolean isnext;
56126326Ssam {
56226326Ssam register Address addr;
56326326Ssam register Lineno line;
56426326Ssam String filename;
56526326Ssam Address startaddr;
56626326Ssam
56726326Ssam startaddr = pc;
56826326Ssam addr = nextaddr(pc, isnext);
56926326Ssam if (!inst_tracing && nlhdr.nlines != 0) {
57026326Ssam line = linelookup(addr);
57126326Ssam for (; line == 0; line = linelookup(addr))
57226326Ssam addr = nextaddr(addr, isnext);
57326326Ssam curline = line;
57426326Ssam } else
57526326Ssam curline = 0;
57626326Ssam stepto(addr);
57726326Ssam filename = srcfilename(addr);
57826326Ssam setsource(filename);
57926326Ssam }
58026326Ssam
58126326Ssam private Address findnextaddr();
58226326Ssam /*
58326326Ssam * Compute the next address that will be executed from the given one.
58426326Ssam * If "isnext" is true then consider a procedure call as straight line code.
58526326Ssam *
58626326Ssam * We must unfortunately do much of the same work that is necessary
58726326Ssam * to print instructions. In addition we have to deal with branches.
58826326Ssam * Unconditional branches we just follow, for conditional branches
58926326Ssam * we continue execution to the current location and then single step
59026326Ssam * the machine. We assume that the last argument in an instruction
59126326Ssam * that branches is the branch address (or relative offset).
59226326Ssam */
nextaddr(startaddr,isnext)59326326Ssam public Address nextaddr(startaddr, isnext)
59426326Ssam Address startaddr;
59526326Ssam boolean isnext;
59626326Ssam {
59726326Ssam Address addr;
59826326Ssam
59926326Ssam addr = usignal(process);
60026326Ssam if (addr == 0 or addr == 1)
60126326Ssam addr = findnextaddr(startaddr, isnext);
60226326Ssam return (addr);
60326326Ssam }
60426326Ssam
60526326Ssam /*
60626326Ssam * Determine if it's ok to skip function f entered by instruction ins.
60726326Ssam * If so, we're going to compute the return address and step to it.
60826326Ssam */
skipfunc(ins,f)60926326Ssam private boolean skipfunc(ins, f)
61026326Ssam Opcode ins;
61126326Ssam Symbol f;
61226326Ssam {
61326326Ssam
61426326Ssam return ((boolean) (!inst_tracing && nlhdr.nlines != 0 &&
61526326Ssam nosource(curfunc) && canskip(curfunc)));
61626326Ssam }
61726326Ssam
findnextaddr(startaddr,isnext)61826326Ssam private Address findnextaddr(startaddr, isnext)
61926326Ssam Address startaddr;
62026326Ssam Boolean isnext;
62126326Ssam {
62226326Ssam register Address addr;
62326326Ssam Optab *op;
62426326Ssam Opcode ins;
62526326Ssam unsigned char mode;
62626326Ssam int argtype, amode, argno, argval, nib;
62726326Ssam String r;
62826326Ssam Boolean indexf;
62926326Ssam enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
63026326Ssam
63126326Ssam argval = 0;
63226326Ssam indexf = false;
63326326Ssam addr = startaddr;
63426326Ssam iread(&ins, addr, sizeof(ins));
63526326Ssam switch (ins) {
63626326Ssam
63726326Ssam case O_CALLF:
63826326Ssam case O_CALLS:
63926326Ssam addrstatus = KNOWN;
64026326Ssam stepto(addr);
64126326Ssam pstep(process, DEFSIG);
64226326Ssam addr = reg(PROGCTR);
64326326Ssam pc = addr;
64426326Ssam setcurfunc(whatblock(pc));
64526326Ssam if (not isbperr()) {
64626326Ssam printstatus();
64726326Ssam /* NOTREACHED */
64826326Ssam }
64926326Ssam bpact();
65026326Ssam if (isnext or skipfunc(ins, curfunc)) {
65126326Ssam addrstatus = KNOWN;
65226326Ssam addr = return_addr();
65326326Ssam stepto(addr);
65426326Ssam bpact();
65526326Ssam } else
65626326Ssam callnews(/* iscall = */ true);
65726326Ssam break;
65826326Ssam
65926326Ssam case O_RET:
66026326Ssam addrstatus = KNOWN;
66126326Ssam stepto(addr);
66226326Ssam callnews(/* iscall = */ false);
66326326Ssam pstep(process, DEFSIG);
66426326Ssam addr = reg(PROGCTR);
66526326Ssam pc = addr;
66626326Ssam if (not isbperr())
66726326Ssam printstatus();
66826326Ssam bpact();
66926326Ssam break;
67026326Ssam
67126326Ssam case O_BRB:
67226326Ssam case O_BRW:
67326326Ssam case O_JMP:
67426326Ssam case O_BBSSI:
67526326Ssam case O_BCC:
67626326Ssam case O_BCS:
67726326Ssam case O_BEQL:
67826326Ssam case O_BGEQ:
67926326Ssam case O_BGTR:
68026326Ssam case O_BGTRU:
68126326Ssam case O_BLEQ:
68226326Ssam case O_BLEQU:
68326326Ssam case O_BLSS:
68426326Ssam case O_BNEQ:
68526326Ssam case O_BVC:
68626326Ssam case O_BVS:
68726326Ssam case O_CASEL:
68826326Ssam case O_AOBLSS:
68926326Ssam case O_AOBLEQ:
69026326Ssam addrstatus = KNOWN;
69126326Ssam stepto(addr);
69226326Ssam pstep(process, DEFSIG);
69326326Ssam addr = reg(PROGCTR);
69426326Ssam pc = addr;
69526326Ssam if (not isbperr())
69626326Ssam printstatus();
69726326Ssam break;
69826326Ssam
69926326Ssam default:
70026326Ssam addrstatus = SEQUENTIAL;
70126326Ssam break;
70226326Ssam }
70326326Ssam if (addrstatus == KNOWN)
70426326Ssam return (addr);
70526326Ssam addr += 1;
70626326Ssam op = ioptab[ins];
70726326Ssam for (argno = 0; argno < op->numargs; argno++) {
70826326Ssam if (indexf == true)
70926326Ssam indexf = false;
71026326Ssam argtype = op->argtype[argno];
71126326Ssam if (is_branch_disp(argtype))
71226326Ssam mode = 0xAF + (typelen(argtype) << 5);
71326326Ssam else
71426326Ssam iread(&mode, addr, sizeof(mode)), addr += 1;
71526326Ssam r = regname[regnm(mode)];
71626326Ssam amode = addrmode(mode);
71726326Ssam switch (amode) {
71826326Ssam
71926326Ssam case LITSHORT:
72026326Ssam case LITUPTO31:
72126326Ssam case LITUPTO47:
72226326Ssam case LITUPTO63:
72326326Ssam argval = mode;
72426326Ssam break;
72526326Ssam
72626326Ssam case INDEX:
72726326Ssam indexf = true;
72826326Ssam --argno;
72926326Ssam break;
73026326Ssam
73126326Ssam case REG:
73226326Ssam case REGDEF:
73326326Ssam case AUTODEC:
73426326Ssam break;
73526326Ssam
73626326Ssam case AUTOINC:
73726326Ssam nib = mode & 0xf;
73826326Ssam if (nib == 0xf || nib == 8 || nib == 9) {
73926326Ssam int size = (mode&03)+1;
74026326Ssam
74126326Ssam argval = getdisp(addr, size,
74226326Ssam regname[PROGCTR], amode);
74326326Ssam addr += size;
74426326Ssam }
74526326Ssam break;
74626326Ssam
74726326Ssam case AUTOINCDEF:
74826326Ssam if ((mode&0xf) != 0xf)
74926326Ssam break;
75026326Ssam argval = getdisp(addr, 4, r, amode);
75126326Ssam addr += 4;
75226326Ssam break;
75326326Ssam
75426326Ssam case BYTEDISP:
75526326Ssam case BYTEDISPDEF:
75626326Ssam argval = getdisp(addr, 1, r, amode);
75726326Ssam addr += 1;
75826326Ssam break;
75926326Ssam
76026326Ssam case WORDDISP:
76126326Ssam case WORDDISPDEF:
76226326Ssam argval = getdisp(addr, 2, r, amode);
76326326Ssam addr += 2;
76426326Ssam break;
76526326Ssam
76626326Ssam case LONGDISP:
76726326Ssam case LONGDISPDEF:
76826326Ssam argval = getdisp(addr, 4, r, amode);
76926326Ssam addr += 4;
77026326Ssam break;
77126326Ssam }
77226326Ssam }
77326326Ssam if (ins == O_CALLF or ins == O_CALLS)
77426326Ssam argval += 2;
77526326Ssam if (addrstatus == BRANCH)
77626326Ssam addr = argval;
77726326Ssam return (addr);
77826326Ssam }
77926326Ssam
78026326Ssam /*
78126326Ssam * Get the displacement of an instruction that uses displacement addressing.
78226326Ssam */
getdisp(addr,nbytes,reg,mode)78326326Ssam private int getdisp(addr, nbytes, reg, mode)
78426326Ssam Address addr;
78526326Ssam int nbytes;
78626326Ssam String reg;
78726326Ssam int mode;
78826326Ssam {
78926326Ssam char byte;
79026326Ssam short hword;
79126326Ssam int argval;
79226326Ssam
79326326Ssam switch (nbytes) {
79426326Ssam
79526326Ssam case 1:
79626326Ssam iread(&byte, addr, sizeof(byte));
79726326Ssam argval = byte;
79826326Ssam break;
79926326Ssam
80026326Ssam case 2:
80126326Ssam iread(&hword, addr, sizeof(hword));
80226326Ssam argval = hword;
80326326Ssam break;
80426326Ssam
80526326Ssam case 4:
80626326Ssam iread(&argval, addr, sizeof(argval));
80726326Ssam break;
80826326Ssam }
80926326Ssam if (reg == regname[PROGCTR] && mode >= BYTEDISP)
81026326Ssam argval += addr + nbytes;
81126326Ssam return (argval);
81226326Ssam }
81326326Ssam
81426326Ssam #define BP_OP O_BPT /* breakpoint trap */
81526326Ssam #define BP_ERRNO SIGTRAP /* signal received at a breakpoint */
81626326Ssam
81726326Ssam /*
81826326Ssam * Setting a breakpoint at a location consists of saving
81926326Ssam * the word at the location and poking a BP_OP there.
82026326Ssam *
82126326Ssam * We save the locations and words on a list for use in unsetting.
82226326Ssam */
82326326Ssam typedef struct Savelist *Savelist;
82426326Ssam
82526326Ssam struct Savelist {
82626326Ssam Address location;
82726326Ssam Byte save;
82826326Ssam Byte refcount;
82926326Ssam Savelist link;
83026326Ssam };
83126326Ssam
83226326Ssam private Savelist savelist;
83326326Ssam
83426326Ssam /*
83526326Ssam * Set a breakpoint at the given address. Only save the word there
83626326Ssam * if it's not already a breakpoint.
83726326Ssam */
setbp(addr)83826326Ssam public setbp(addr)
83926326Ssam Address addr;
84026326Ssam {
84126326Ssam Byte w, save;
84226326Ssam register Savelist newsave, s;
84326326Ssam
84426326Ssam for (s = savelist; s != nil; s = s->link)
84526326Ssam if (s->location == addr) {
84626326Ssam s->refcount++;
84726326Ssam return;
84826326Ssam }
84926326Ssam iread(&save, addr, sizeof(save));
85026326Ssam newsave = new(Savelist);
85126326Ssam newsave->location = addr;
85226326Ssam newsave->save = save;
85326326Ssam newsave->refcount = 1;
85426326Ssam newsave->link = savelist;
85526326Ssam savelist = newsave;
85626326Ssam w = BP_OP;
85726326Ssam iwrite(&w, addr, sizeof(w));
85826326Ssam }
85926326Ssam
86026326Ssam /*
86126326Ssam * Unset a breakpoint; unfortunately we have to search the SAVELIST
86226326Ssam * to find the saved value. The assumption is that the SAVELIST will
86326326Ssam * usually be quite small.
86426326Ssam */
unsetbp(addr)86526326Ssam public unsetbp(addr)
86626326Ssam Address addr;
86726326Ssam {
86826326Ssam register Savelist s, prev;
86926326Ssam
87026326Ssam prev = nil;
87126326Ssam for (s = savelist; s != nil; s = s->link) {
87226326Ssam if (s->location == addr) {
87326326Ssam iwrite(&s->save, addr, sizeof(s->save));
87426326Ssam s->refcount--;
87526326Ssam if (s->refcount == 0) {
87626326Ssam if (prev == nil)
87726326Ssam savelist = s->link;
87826326Ssam else
87926326Ssam prev->link = s->link;
88026326Ssam dispose(s);
88126326Ssam }
88226326Ssam return;
88326326Ssam }
88426326Ssam prev = s;
88526326Ssam }
88626326Ssam panic("unsetbp: couldn't find address %d", addr);
88726326Ssam }
88826326Ssam
88926326Ssam /*
89026326Ssam * Enter a procedure by creating and executing a call instruction.
89126326Ssam */
89226326Ssam
89326326Ssam #define CALLSIZE 7 /* size of call instruction */
89426326Ssam
beginproc(p,argc)89526326Ssam public beginproc(p, argc)
89626326Ssam Symbol p;
89726326Ssam Integer argc;
89826326Ssam {
89926326Ssam char save[CALLSIZE];
90026326Ssam struct {
90126326Ssam Opcode op;
90226326Ssam unsigned char numargs;
90326326Ssam unsigned char mode;
90426326Ssam char addr[sizeof(long)]; /* unaligned long */
90526326Ssam } call;
90626326Ssam long dest;
90726326Ssam
90826326Ssam if (4*argc+4 > 256)
90926326Ssam error("too many parameters (max %d)", 256/4 - 1);
91026326Ssam pc = 2;
91126326Ssam iread(save, pc, sizeof(save));
91226326Ssam call.op = O_CALLF;
91326326Ssam call.numargs = 4*argc+4;
91426326Ssam call.mode = 0xef; /* longword relative */
91526326Ssam dest = codeloc(p) - 2 - (pc + CALLSIZE);
91626326Ssam mov(&dest, call.addr, sizeof(call.addr));
91726326Ssam iwrite(&call, pc, sizeof(call));
91826326Ssam setreg(PROGCTR, pc);
91926326Ssam pstep(process, DEFSIG);
92026326Ssam iwrite(save, pc, sizeof(save));
92126326Ssam pc = reg(PROGCTR);
92226326Ssam if (not isbperr())
92326326Ssam printstatus();
92426326Ssam }
92526337Ssam
92626337Ssam /*
92726337Ssam * Special variables for debugging the kernel.
92826337Ssam */
92926337Ssam
93026337Ssam public integer masterpcbb;
93126337Ssam public integer slr;
93226337Ssam public struct pte *sbr;
93333338Sdonn private struct pcb pcb;
93426337Ssam
getpcb()93526337Ssam public getpcb ()
93626337Ssam {
93726337Ssam fseek(corefile, masterpcbb & ~0xc0000000, 0);
93826337Ssam get(corefile, pcb);
93926337Ssam printf("p0br %lx p0lr %lx p2br %lx p2lr %lx\n",
94026337Ssam pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p2br, pcb.pcb_p2lr
94126337Ssam );
94226337Ssam setreg(0, pcb.pcb_r0);
94326337Ssam setreg(1, pcb.pcb_r1);
94426337Ssam setreg(2, pcb.pcb_r2);
94526337Ssam setreg(3, pcb.pcb_r3);
94626337Ssam setreg(4, pcb.pcb_r4);
94726337Ssam setreg(5, pcb.pcb_r5);
94826337Ssam setreg(6, pcb.pcb_r6);
94926337Ssam setreg(7, pcb.pcb_r7);
95026337Ssam setreg(8, pcb.pcb_r8);
95126337Ssam setreg(9, pcb.pcb_r9);
95226337Ssam setreg(10, pcb.pcb_r10);
95326337Ssam setreg(11, pcb.pcb_r11);
95426337Ssam setreg(12, pcb.pcb_r12);
95526337Ssam setreg(FRP, pcb.pcb_fp);
95626337Ssam setreg(STKP, pcb.pcb_ksp);
95726337Ssam setreg(PROGCTR, pcb.pcb_pc);
95826337Ssam }
95926337Ssam
copyregs(savreg,reg)96026337Ssam public copyregs (savreg, reg)
96126337Ssam Word savreg[], reg[];
96226337Ssam {
96326337Ssam reg[0] = savreg[R0];
96426337Ssam reg[1] = savreg[R1];
96526337Ssam reg[2] = savreg[R2];
96626337Ssam reg[3] = savreg[R3];
96726337Ssam reg[4] = savreg[R4];
96826337Ssam reg[5] = savreg[R5];
96926337Ssam reg[6] = savreg[R6];
97026337Ssam reg[7] = savreg[R7];
97126337Ssam reg[8] = savreg[R8];
97226337Ssam reg[9] = savreg[R9];
97326337Ssam reg[10] = savreg[R10];
97426337Ssam reg[11] = savreg[R11];
97526337Ssam reg[12] = savreg[R12];
97626337Ssam reg[FRP] = savreg[FP];
97726337Ssam reg[STKP] = savreg[SP];
97826337Ssam reg[PROGCTR] = savreg[PC];
97926337Ssam }
98026337Ssam
98126337Ssam /*
98226337Ssam * Map a virtual address to a physical address.
98326337Ssam */
98426337Ssam
vmap(addr)98526337Ssam public Address vmap (addr)
98626337Ssam Address addr;
98726337Ssam {
98826337Ssam int oldaddr = addr, v;
98926337Ssam struct pte pte;
99026337Ssam
99126337Ssam addr &= ~0xc0000000;
99226337Ssam v = btop(addr);
99326337Ssam switch (oldaddr&0xc0000000) {
99426337Ssam
99526337Ssam case 0xc0000000:
99626337Ssam /*
99726337Ssam * In system space get system pte. If
99826337Ssam * valid or reclaimable then physical address
99926337Ssam * is combination of its page number and the page
100026337Ssam * offset of the original address.
100126337Ssam */
100226337Ssam if (v >= slr)
100326337Ssam goto oor;
100426337Ssam addr = ((long)(sbr+v)) &~ 0xc0000000;
100526337Ssam goto simple;
100626337Ssam
100726337Ssam case 0x80000000:
100826337Ssam /*
100926337Ssam * In p2 spce must not be in shadow region.
101026337Ssam */
101126337Ssam if (v < pcb.pcb_p2lr)
101226337Ssam goto oor;
101326337Ssam addr = (long)(pcb.pcb_p2br+v);
101426337Ssam break;
101526337Ssam
101626337Ssam case 0x40000000:
101726337Ssam /*
101826337Ssam * In p1 space everything is verboten (for now).
101926337Ssam */
102026337Ssam goto oor;
102126337Ssam
102226337Ssam case 0x00000000:
102326337Ssam /*
102426337Ssam * In p0 space must not be off end of region.
102526337Ssam */
102626337Ssam if (v >= pcb.pcb_p0lr)
102726337Ssam goto oor;
102826337Ssam addr = (long)(pcb.pcb_p0br+v);
102926337Ssam break;
103026337Ssam oor:
103126337Ssam error("address out of segment");
103226337Ssam }
103326337Ssam /*
103426337Ssam * For p0/p1/p2 address, user-level page table should
103526337Ssam * be in kernel vm. Do second-level indirect by recursing.
103626337Ssam */
103726337Ssam if ((addr & 0xc0000000) != 0xc0000000)
103826337Ssam error("bad p0br, p1br, or p2br in pcb");
103926337Ssam addr = vmap(addr);
104026337Ssam simple:
104126337Ssam /*
104226337Ssam * Addr is now address of the pte of the page we
104326337Ssam * are interested in; get the pte and paste up the
104426337Ssam * physical address.
104526337Ssam */
104626337Ssam fseek(corefile, addr, 0);
104726337Ssam if (fread(&pte, sizeof (pte), 1, corefile) != 1)
104826337Ssam error("page table botch");
104926337Ssam /* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */
105026337Ssam if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0))
105126337Ssam error("page not valid/reclaimable");
105226337Ssam return ((long)(ptob(pte.pg_pfnum) + (oldaddr & PGOFSET)));
105326337Ssam }
105433338Sdonn
105533338Sdonn /*
105633338Sdonn * Extract a bit field from an integer.
105733338Sdonn */
105833338Sdonn
extractField(s)105933338Sdonn public integer extractField (s)
106033338Sdonn Symbol s;
106133338Sdonn {
106233338Sdonn integer nbytes, nbits, n, r, off, len;
106333338Sdonn
106433338Sdonn off = s->symvalue.field.offset;
106533338Sdonn len = s->symvalue.field.length;
106633338Sdonn nbytes = size(s);
106733338Sdonn n = 0;
106833338Sdonn if (nbytes > sizeof(n)) {
106933338Sdonn printf("[bad size in extractField -- word assumed]\n");
107033338Sdonn nbytes = sizeof(n);
107133338Sdonn }
107233338Sdonn popn(nbytes, ((char *) &n) + (sizeof(Word) - nbytes));
107333338Sdonn nbits = nbytes * BITSPERBYTE;
107433338Sdonn r = n >> (nbits - ((off mod nbits) + len));
107533338Sdonn r &= ((1 << len) - 1);
107633338Sdonn return r;
107733338Sdonn }
107833338Sdonn
107933338Sdonn /*
108033338Sdonn * Change the length of a value in memory according to a given difference
108133338Sdonn * in the lengths of its new and old types.
108233338Sdonn */
108333338Sdonn
loophole(oldlen,newlen)108433338Sdonn public loophole (oldlen, newlen)
108533338Sdonn integer oldlen, newlen;
108633338Sdonn {
108733338Sdonn integer i, n;
108833338Sdonn Stack *oldsp;
108933338Sdonn
109033338Sdonn n = newlen - oldlen;
109133338Sdonn oldsp = sp - oldlen;
109233338Sdonn if (n > 0) {
109333338Sdonn for (i = oldlen - 1; i >= 0; i--) {
109433338Sdonn oldsp[n + i] = oldsp[i];
109533338Sdonn }
109633338Sdonn for (i = 0; i < n; i++) {
109733338Sdonn oldsp[i] = '\0';
109833338Sdonn }
109933338Sdonn } else {
110033338Sdonn for (i = 0; i < newlen; i++) {
110133338Sdonn oldsp[i] = oldsp[i - n];
110233338Sdonn }
110333338Sdonn }
110433338Sdonn sp += n;
110533338Sdonn }
1106