126326Ssam /* 226326Ssam * Copyright (c) 1985 Regents of the University of California. 326326Ssam * All rights reserved. The Berkeley software License Agreement 426326Ssam * specifies the terms and conditions for redistribution. 526326Ssam */ 626326Ssam 726326Ssam #ifndef lint 8*33338Sdonn static char sccsid[] = "@(#)tahoe.c 5.5 (Berkeley) 01/12/88"; 926326Ssam #endif not lint 1026326Ssam 1126326Ssam /* 1226326Ssam * Target machine dependent stuff. 1326326Ssam */ 1426326Ssam 1526326Ssam #include "defs.h" 1626326Ssam #include "machine.h" 1726326Ssam #include "process.h" 1826326Ssam #include "runtime.h" 1926326Ssam #include "events.h" 2026326Ssam #include "main.h" 2126326Ssam #include "symbols.h" 2226326Ssam #include "source.h" 2326326Ssam #include "mappings.h" 2426326Ssam #include "object.h" 2526326Ssam #include "keywords.h" 2626326Ssam #include "ops.h" 27*33338Sdonn #include "eval.h" 2826326Ssam #include <signal.h> 2926326Ssam 3026326Ssam #ifndef public 3126326Ssam typedef unsigned int Address; 3226326Ssam typedef unsigned char Byte; 3326326Ssam typedef unsigned int Word; 3426326Ssam 3526326Ssam #define NREG 16 3626326Ssam 3726326Ssam #define FRP 13 3826326Ssam #define STKP 14 3926326Ssam #define PROGCTR 15 4026326Ssam 41*33338Sdonn #define CODESTART 0 42*33338Sdonn #define FUNCOFFSET 2 43*33338Sdonn 4426326Ssam #define BITSPERBYTE 8 4526326Ssam #define BITSPERWORD (BITSPERBYTE * sizeof(Word)) 4626326Ssam 4726337Ssam /* 48*33338Sdonn * This magic macro enables us to look at the process' registers 49*33338Sdonn * in its user structure. 5026337Ssam */ 5126326Ssam 52*33338Sdonn #define regloc(reg) (ctob(UPAGES) + (sizeof(Word) * (reg))) 53*33338Sdonn 54*33338Sdonn #define nargspassed(frame) (((argn(-1, frame)&0xffff)-4)/4) 55*33338Sdonn 5626337Ssam #define SYSBASE 0xc0000000 /* base of system address space */ 5726337Ssam #define physaddr(a) ((a) &~ 0xc0000000) 5826337Ssam 5926326Ssam #include "source.h" 6026326Ssam #include "symbols.h" 6126337Ssam #include <sys/param.h> 6226337Ssam #include <sys/dir.h> 6326337Ssam #include <machine/psl.h> 6426337Ssam #include <sys/user.h> 65*33338Sdonn #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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 */ 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 */ 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", 500*33338Sdonn "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 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 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; 933*33338Sdonn private struct pcb pcb; 93426337Ssam 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 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 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 } 1054*33338Sdonn 1055*33338Sdonn /* 1056*33338Sdonn * Extract a bit field from an integer. 1057*33338Sdonn */ 1058*33338Sdonn 1059*33338Sdonn public integer extractField (s) 1060*33338Sdonn Symbol s; 1061*33338Sdonn { 1062*33338Sdonn integer nbytes, nbits, n, r, off, len; 1063*33338Sdonn 1064*33338Sdonn off = s->symvalue.field.offset; 1065*33338Sdonn len = s->symvalue.field.length; 1066*33338Sdonn nbytes = size(s); 1067*33338Sdonn n = 0; 1068*33338Sdonn if (nbytes > sizeof(n)) { 1069*33338Sdonn printf("[bad size in extractField -- word assumed]\n"); 1070*33338Sdonn nbytes = sizeof(n); 1071*33338Sdonn } 1072*33338Sdonn popn(nbytes, ((char *) &n) + (sizeof(Word) - nbytes)); 1073*33338Sdonn nbits = nbytes * BITSPERBYTE; 1074*33338Sdonn r = n >> (nbits - ((off mod nbits) + len)); 1075*33338Sdonn r &= ((1 << len) - 1); 1076*33338Sdonn return r; 1077*33338Sdonn } 1078*33338Sdonn 1079*33338Sdonn /* 1080*33338Sdonn * Change the length of a value in memory according to a given difference 1081*33338Sdonn * in the lengths of its new and old types. 1082*33338Sdonn */ 1083*33338Sdonn 1084*33338Sdonn public loophole (oldlen, newlen) 1085*33338Sdonn integer oldlen, newlen; 1086*33338Sdonn { 1087*33338Sdonn integer i, n; 1088*33338Sdonn Stack *oldsp; 1089*33338Sdonn 1090*33338Sdonn n = newlen - oldlen; 1091*33338Sdonn oldsp = sp - oldlen; 1092*33338Sdonn if (n > 0) { 1093*33338Sdonn for (i = oldlen - 1; i >= 0; i--) { 1094*33338Sdonn oldsp[n + i] = oldsp[i]; 1095*33338Sdonn } 1096*33338Sdonn for (i = 0; i < n; i++) { 1097*33338Sdonn oldsp[i] = '\0'; 1098*33338Sdonn } 1099*33338Sdonn } else { 1100*33338Sdonn for (i = 0; i < newlen; i++) { 1101*33338Sdonn oldsp[i] = oldsp[i - n]; 1102*33338Sdonn } 1103*33338Sdonn } 1104*33338Sdonn sp += n; 1105*33338Sdonn } 1106