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*26337Ssam static char sccsid[] = "@(#)tahoe.c 5.2 (Berkeley) 02/23/86"; 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" 2726326Ssam #include <signal.h> 2826326Ssam 2926326Ssam #ifndef public 3026326Ssam typedef unsigned int Address; 3126326Ssam typedef unsigned char Byte; 3226326Ssam typedef unsigned int Word; 3326326Ssam 3426326Ssam #define NREG 16 3526326Ssam 3626326Ssam #define FRP 13 3726326Ssam #define STKP 14 3826326Ssam #define PROGCTR 15 3926326Ssam 4026326Ssam #define BITSPERBYTE 8 4126326Ssam #define BITSPERWORD (BITSPERBYTE * sizeof(Word)) 4226326Ssam 4326326Ssam #define nargspassed(frame) ((frame->removed-4)/4) 44*26337Ssam /* 45*26337Ssam * Extract a field's value from the integer i. The value 46*26337Ssam * is placed in i in such as way as the first bit of the 47*26337Ssam * field is contained in the first byte of the integer. 48*26337Ssam */ 49*26337Ssam #define extractfield(i, s) \ 50*26337Ssam ((i >> BITSPERWORD - ((s)->symvalue.field.offset mod BITSPERBYTE + \ 51*26337Ssam (s)->symvalue.field.length)) & \ 52*26337Ssam ((1 << (s)->symvalue.field.length) - 1)) 53*26337Ssam /* 54*26337Ssam * Rearrange the stack so that the top of stack has 55*26337Ssam * something corresponding to newsize, whereas before it had 56*26337Ssam * something corresponding to oldsize. If we are expanding 57*26337Ssam * then the stack is padded at the front of the data with nulls. 58*26337Ssam * If we are contracting, the appropriate amount is shaved off the 59*26337Ssam * front by copying up the stack. 60*26337Ssam */ 61*26337Ssam #define typerename(oldsize, newsize) { \ 62*26337Ssam int osize = oldsize; \ 63*26337Ssam Stack *osp; \ 64*26337Ssam \ 65*26337Ssam len = newsize - osize; \ 66*26337Ssam osp = sp - osize; \ 67*26337Ssam if (len > 0) { \ 68*26337Ssam mov(osp, osp+len, osize); /* copy old up and pad */ \ 69*26337Ssam bzero(osp, len); \ 70*26337Ssam } else if (len < 0) \ 71*26337Ssam mov(osp-len, osp, osize+len); /* copy new size down */ \ 72*26337Ssam sp += len; \ 73*26337Ssam } 7426326Ssam 75*26337Ssam #define SYSBASE 0xc0000000 /* base of system address space */ 76*26337Ssam #define physaddr(a) ((a) &~ 0xc0000000) 77*26337Ssam 7826326Ssam #include "source.h" 7926326Ssam #include "symbols.h" 80*26337Ssam #include <sys/param.h> 81*26337Ssam #include <sys/dir.h> 82*26337Ssam #include <machine/psl.h> 83*26337Ssam #include <sys/user.h> 84*26337Ssam #include <sys/vm.h> 85*26337Ssam #include <machine/reg.h> 86*26337Ssam #include <machine/pte.h> 8726326Ssam 8826326Ssam Address pc; 8926326Ssam Address prtaddr; 9026326Ssam 9126326Ssam #endif 9226326Ssam 93*26337Ssam /* 94*26337Ssam * Indices into u. for use in collecting registers values. 95*26337Ssam */ 96*26337Ssam public int rloc[] = 97*26337Ssam { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, FP, SP, PC }; 98*26337Ssam 9926326Ssam private Address printop(); 10026326Ssam 10126326Ssam Optab *ioptab[256]; /* index by opcode to optab */ 10226326Ssam /* 10326326Ssam * Initialize the opcode lookup table. 10426326Ssam */ 10526326Ssam public optab_init() 10626326Ssam { 10726326Ssam register Optab *p; 10826326Ssam 10926326Ssam for (p = optab; p->iname; p++) 11026326Ssam ioptab[p->val & 0xff] = p; 11126326Ssam } 11226326Ssam 11326326Ssam /* 11426326Ssam * Decode and print the instructions within the given address range. 11526326Ssam */ 11626326Ssam public printinst(lowaddr, highaddr) 11726326Ssam Address lowaddr, highaddr; 11826326Ssam { 11926326Ssam register Address addr; 12026326Ssam 12126326Ssam for (addr = lowaddr; addr <= highaddr; ) 12226326Ssam addr = printop(addr); 12326326Ssam prtaddr = addr; 12426326Ssam } 12526326Ssam 12626326Ssam /* 12726326Ssam * Another approach: print n instructions starting at the given address. 12826326Ssam */ 12926326Ssam public printninst(count, addr) 13026326Ssam int count; 13126326Ssam Address addr; 13226326Ssam { 13326326Ssam register Integer i; 13426326Ssam register Address newaddr; 13526326Ssam 13626326Ssam if (count <= 0) 13726326Ssam error("non-positive repetition count"); 13826326Ssam for (newaddr = addr, i = 0; i < count; i++) 13926326Ssam newaddr = printop(newaddr); 14026326Ssam prtaddr = newaddr; 14126326Ssam } 14226326Ssam 14326326Ssam /* 14426326Ssam * Hacked version of adb's instruction decoder. 14526326Ssam */ 14626326Ssam private Address printop(addr) 14726326Ssam Address addr; 14826326Ssam { 14926326Ssam register Optab *op; 15026326Ssam Opcode ins; 15126326Ssam unsigned char mode; 15226326Ssam int argtype, amode, argno, argval, r; 15326326Ssam String reg; 15426326Ssam Boolean indexf; 15526326Ssam short offset; 15626326Ssam 15726326Ssam argval = 0; 15826326Ssam indexf = false; 15926326Ssam printf("%08x ", addr); 16026326Ssam iread(&ins, addr, sizeof(ins)); 16126326Ssam addr += 1; 16226326Ssam op = ioptab[ins]; 16326326Ssam printf("%s", op->iname); 16426326Ssam for (argno = 0; argno < op->numargs; argno++) { 16526326Ssam if (indexf == true) 16626326Ssam indexf = false; 16726326Ssam else 16826326Ssam printf(argno == 0 ? "\t" : ","); 16926326Ssam argtype = op->argtype[argno]; 17026326Ssam if (is_branch_disp(argtype)) 17126326Ssam mode = 0xAF + (typelen(argtype) << 5); 17226326Ssam else 17326326Ssam iread(&mode, addr, sizeof(mode)), addr += 1; 17426326Ssam reg = regname[regnm(mode)]; 17526326Ssam amode = addrmode(mode); 17626326Ssam switch (amode) { 17726326Ssam 17826326Ssam case LITSHORT: case LITUPTO31: 17926326Ssam case LITUPTO47: case LITUPTO63: 18026326Ssam if (ins == O_KCALL && mode >= 0 && mode < SYSSIZE && 18126326Ssam systab[mode]) 18226326Ssam printf("$%s", systab[mode]); 18326326Ssam else 18426326Ssam printf("$%x", mode); 18526326Ssam argval = mode; 18626326Ssam break; 18726326Ssam 18826326Ssam case INDEX: 18926326Ssam printf("[%s]", reg); 19026326Ssam indexf = true; 19126326Ssam argno--; 19226326Ssam break; 19326326Ssam 19426326Ssam case REG: 19526326Ssam printf("%s", reg); 19626326Ssam break; 19726326Ssam 19826326Ssam case REGDEF: 19926326Ssam printf("(%s)", reg); 20026326Ssam break; 20126326Ssam 20226326Ssam case AUTODEC: 20326326Ssam printf("-(%s)", reg); 20426326Ssam break; 20526326Ssam 20626326Ssam case AUTOINC: 20726326Ssam r = mode & 0xf; 20826326Ssam if (r == 0xf || r == 8 || r == 9) { 20926326Ssam int size = (mode&03) + 1; 21026326Ssam 21126326Ssam /* immediate mode */ 21226326Ssam printf("$"); 21326326Ssam argval = printdisp(addr, size, 21426326Ssam regname[PROGCTR], amode); 21526326Ssam addr += size; 21626326Ssam } else 21726326Ssam printf("(%s)+", reg); 21826326Ssam break; 21926326Ssam 22026326Ssam case AUTOINCDEF: 22126326Ssam if ((mode&0xf) == 0xf) { 22226326Ssam printf("*$"); 22326326Ssam argval = printdisp(addr, 4, reg, amode); 22426326Ssam addr += 4; 22526326Ssam } else 22626326Ssam printf("*(%s)+", reg); 22726326Ssam break; 22826326Ssam 22926326Ssam case BYTEDISP: 23026326Ssam argval = printdisp(addr, 1, reg, amode); 23126326Ssam addr += 1; 23226326Ssam break; 23326326Ssam 23426326Ssam case BYTEDISPDEF: 23526326Ssam printf("*"); 23626326Ssam argval = printdisp(addr, 1, reg, amode); 23726326Ssam addr += 1; 23826326Ssam break; 23926326Ssam 24026326Ssam case WORDDISP: 24126326Ssam argval = printdisp(addr, 2, reg, amode); 24226326Ssam addr += 2; 24326326Ssam break; 24426326Ssam 24526326Ssam case WORDDISPDEF: 24626326Ssam printf("*"); 24726326Ssam argval = printdisp(addr, 2, reg, amode); 24826326Ssam addr += 2; 24926326Ssam break; 25026326Ssam 25126326Ssam case LONGDISP: 25226326Ssam argval = printdisp(addr, 4, reg, amode); 25326326Ssam addr += 4; 25426326Ssam break; 25526326Ssam 25626326Ssam case LONGDISPDEF: 25726326Ssam printf("*"); 25826326Ssam argval = printdisp(addr, 4, reg, amode); 25926326Ssam addr += 4; 26026326Ssam break; 26126326Ssam } 26226326Ssam } 26326326Ssam if (ins == O_CASEL) 26426326Ssam for (argno = 0; argno <= argval; argno++) { 26526326Ssam iread(&offset, addr, sizeof(offset)); 26626326Ssam printf("\n\t\t%d", offset); 26726326Ssam addr += 2; 26826326Ssam } 26926326Ssam printf("\n"); 27026326Ssam return (addr); 27126326Ssam } 27226326Ssam 27326326Ssam /* 27426326Ssam * Print the displacement of an instruction that uses displacement 27526326Ssam * addressing. 27626326Ssam */ 27726326Ssam private int printdisp(addr, nbytes, reg, mode) 27826326Ssam Address addr; 27926326Ssam int nbytes; 28026326Ssam char *reg; 28126326Ssam int mode; 28226326Ssam { 28326326Ssam char byte; 28426326Ssam short hword; 28526326Ssam int argval; 28626326Ssam Symbol f; 28726326Ssam 28826326Ssam switch (nbytes) { 28926326Ssam 29026326Ssam case 1: 29126326Ssam iread(&byte, addr, sizeof(byte)); 29226326Ssam argval = byte; 29326326Ssam break; 29426326Ssam 29526326Ssam case 2: 29626326Ssam iread(&hword, addr, sizeof(hword)); 29726326Ssam argval = hword; 29826326Ssam break; 29926326Ssam 30026326Ssam case 4: 30126326Ssam iread(&argval, addr, sizeof(argval)); 30226326Ssam break; 30326326Ssam } 30426326Ssam if (reg == regname[PROGCTR] && mode >= BYTEDISP) 30526326Ssam argval += addr + nbytes; 30626326Ssam if (reg == regname[PROGCTR]) { 30726326Ssam f = whatblock((Address) argval + 2); 30826326Ssam if (codeloc(f) == argval + 2) 30926326Ssam printf("%s", symname(f)); 31026326Ssam else 31126326Ssam printf("%x", argval); 31226326Ssam } else { 31326326Ssam if (varIsSet("$hexoffsets")) { 31426326Ssam if (argval < 0) 31526326Ssam printf("-%x(%s)", -(argval), reg); 31626326Ssam else 31726326Ssam printf("%x(%s)", argval, reg); 31826326Ssam } else 31926326Ssam printf("%d(%s)", argval, reg); 32026326Ssam } 32126326Ssam return (argval); 32226326Ssam } 32326326Ssam 32426326Ssam /* 32526326Ssam * Print the contents of the addresses within the given range 32626326Ssam * according to the given format. 32726326Ssam */ 32826326Ssam typedef struct { 32926326Ssam String name; 33026326Ssam String printfstring; 33126326Ssam int length; 33226326Ssam } Format; 33326326Ssam 33426326Ssam private Format fmt[] = { 33526326Ssam { "d", " %d", sizeof(short) }, 33626326Ssam { "D", " %ld", sizeof(long) }, 33726326Ssam { "o", " %o", sizeof(short) }, 33826326Ssam { "O", " %lo", sizeof(long) }, 33926326Ssam { "x", " %04x", sizeof(short) }, 34026326Ssam { "X", " %08x", sizeof(long) }, 34126326Ssam { "b", " \\%o", sizeof(char) }, 34226326Ssam { "c", " '%c'", sizeof(char) }, 34326326Ssam { "s", "%c", sizeof(char) }, 34426326Ssam { "f", " %f", sizeof(float) }, 34526326Ssam { "g", " %g", sizeof(double) }, 34626326Ssam { nil, nil, 0 } 34726326Ssam }; 34826326Ssam 34926326Ssam private Format *findformat(s) 35026326Ssam String s; 35126326Ssam { 35226326Ssam register Format *f; 35326326Ssam 35426326Ssam for (f = &fmt[0]; f->name != nil && !streq(f->name, s); f++) 35526326Ssam ; 35626326Ssam if (f->name == nil) 35726326Ssam error("bad print format \"%s\"", s); 35826326Ssam return (f); 35926326Ssam } 36026326Ssam 36126326Ssam public Address printdata(lowaddr, highaddr, format) 36226326Ssam Address lowaddr; 36326326Ssam Address highaddr; 36426326Ssam String format; 36526326Ssam { 36626326Ssam register int n; 36726326Ssam register Address addr; 36826326Ssam register Format *f; 36926326Ssam int value; 37026326Ssam 37126326Ssam if (lowaddr > highaddr) 37226326Ssam error("first address larger than second"); 37326326Ssam f = findformat(format); 37426326Ssam n = 0; 37526326Ssam value = 0; 37626326Ssam for (addr = lowaddr; addr <= highaddr; addr += f->length) { 37726326Ssam if (n == 0) 37826326Ssam printf("%08x: ", addr); 37926326Ssam dread(&value, addr, f->length); 38026326Ssam printf(f->printfstring, value); 38126326Ssam ++n; 38226326Ssam if (n >= (16 div f->length)) { 38326326Ssam putchar('\n'); 38426326Ssam n = 0; 38526326Ssam } 38626326Ssam } 38726326Ssam if (n != 0) 38826326Ssam putchar('\n'); 38926326Ssam prtaddr = addr; 39026326Ssam return (addr); 39126326Ssam } 39226326Ssam 39326326Ssam /* 39426326Ssam * The other approach is to print n items starting with a given address. 39526326Ssam */ 39626326Ssam 39726326Ssam public printndata(count, startaddr, format) 39826326Ssam int count; 39926326Ssam Address startaddr; 40026326Ssam String format; 40126326Ssam { 40226326Ssam register int i, n; 40326326Ssam register Address addr; 40426326Ssam register Format *f; 40526326Ssam register Boolean isstring; 40626326Ssam char c; 40726326Ssam union { 40826326Ssam char charv; 40926326Ssam short shortv; 41026326Ssam int intv; 41126326Ssam float floatv; 41226326Ssam double doublev; 41326326Ssam } value; 41426326Ssam 41526326Ssam if (count <= 0) 41626326Ssam error("non-positive repetition count"); 41726326Ssam f = findformat(format); 41826326Ssam isstring = (Boolean) streq(f->name, "s"); 41926326Ssam n = 0; 42026326Ssam addr = startaddr; 42126326Ssam value.intv = 0; 42226326Ssam for (i = 0; i < count; i++) { 42326326Ssam if (n == 0) 42426326Ssam printf("%08x: ", addr); 42526326Ssam if (isstring) { 42626326Ssam putchar('"'); 42726326Ssam dread(&c, addr, sizeof(char)); 42826326Ssam while (c != '\0') { 42926326Ssam printchar(c); 43026326Ssam ++addr; 43126326Ssam dread(&c, addr, sizeof(char)); 43226326Ssam } 43326326Ssam putchar('"'); 43426326Ssam putchar('\n'); 43526326Ssam n = 0; 43626326Ssam addr += sizeof(String); 43726326Ssam continue; 43826326Ssam } 43926326Ssam dread(&value, addr, f->length); 44026326Ssam printf(f->printfstring, value); 44126326Ssam ++n; 44226326Ssam if (n >= (16 div f->length)) { 44326326Ssam putchar('\n'); 44426326Ssam n = 0; 44526326Ssam } 44626326Ssam addr += f->length; 44726326Ssam } 44826326Ssam if (n != 0) 44926326Ssam putchar('\n'); 45026326Ssam prtaddr = addr; 45126326Ssam } 45226326Ssam 45326326Ssam /* 45426326Ssam * Print out a value according to the given format. 45526326Ssam */ 45626326Ssam public printvalue(v, format) 45726326Ssam long v; 45826326Ssam String format; 45926326Ssam { 46026326Ssam Format *f; 46126326Ssam char *p, *q; 46226326Ssam 46326326Ssam f = findformat(format); 46426326Ssam if (streq(f->name, "s")) { 46526326Ssam putchar('"'); 46626326Ssam for (p = (char *) &v, q = p + sizeof(v); p < q; ++p) 46726326Ssam printchar(*p); 46826326Ssam putchar('"'); 46926326Ssam } else 47026326Ssam printf(f->printfstring, v); 47126326Ssam putchar('\n'); 47226326Ssam } 47326326Ssam 47426326Ssam /* 47526326Ssam * Print out an execution time error. 47626326Ssam * Assumes the source position of the error has been calculated. 47726326Ssam * 47826326Ssam * Have to check if the -r option was specified; if so then 47926326Ssam * the object file information hasn't been read in yet. 48026326Ssam */ 48126326Ssam public printerror() 48226326Ssam { 48326326Ssam extern Integer sys_nsig; 48426326Ssam extern String sys_siglist[]; 48526326Ssam integer err; 48626326Ssam 48726326Ssam if (isfinished(process)) { 48826326Ssam err = exitcode(process); 48926326Ssam if (err) { 49026326Ssam printf("\"%s\" terminated abnormally (exit code %d)\n", 49126326Ssam objname, err); 49226326Ssam erecover(); 49326326Ssam } else 49426326Ssam printf("\"%s\" terminated normally\n", objname); 49526326Ssam } 49626326Ssam if (runfirst) { 49726326Ssam fprintf(stderr, "Entering debugger ...\n"); 49826326Ssam init(); 49926326Ssam } 50026326Ssam err = errnum(process); 50126326Ssam putchar('\n'); 50226326Ssam printsig(err); 50326326Ssam putchar(' '); 50426326Ssam printloc(); 50526326Ssam putchar('\n'); 50626326Ssam if (curline > 0) 50726326Ssam printlines(curline, curline); 50826326Ssam else 50926326Ssam printinst(pc, pc); 51026326Ssam erecover(); 51126326Ssam } 51226326Ssam 51326326Ssam /* 51426326Ssam * Print out a signal. 51526326Ssam */ 51626326Ssam private String illinames[] = { 51726326Ssam "reserved addressing fault", 51826326Ssam "priviliged instruction fault", 51926326Ssam "reserved operand fault" 52026326Ssam }; 52126326Ssam #define NILLINAMES (sizeof (illinames) / sizeof (illinames[0])) 52226326Ssam 52326326Ssam private String fpenames[] = { 52426326Ssam nil, 52526326Ssam "integer overflow trap", 52626326Ssam "integer divide by zero trap", 52726326Ssam "floating point divide by zero trap", 52826326Ssam "floating point overflow trap", 52926326Ssam "floating point underflow trap", 53026326Ssam }; 53126326Ssam #define NFPENAMES (sizeof (fpenames) / sizeof (fpenames[0])) 53226326Ssam 53326326Ssam public printsig(signo) 53426326Ssam integer signo; 53526326Ssam { 53626326Ssam integer code; 53726326Ssam 53826326Ssam if (signo < 0 or signo > sys_nsig) 53926326Ssam printf("[signal %d]", signo); 54026326Ssam else 54126326Ssam printf("%s", sys_siglist[signo]); 54226326Ssam code = errcode(process); 54326326Ssam if (signo == SIGILL) 54426326Ssam if (code >= 0 && code < NILLINAMES) 54526326Ssam printf(" (%s)", illinames[code]); 54626326Ssam if (signo == SIGFPE) 54726326Ssam if (code > 0 and code < NFPENAMES) 54826326Ssam printf(" (%s)", fpenames[code]); 54926326Ssam } 55026326Ssam 55126326Ssam /* 55226326Ssam * Note the termination of the program. We do this so as to avoid 55326326Ssam * having the process exit, which would make the values of variables 55426326Ssam * inaccessible. We do want to flush all output buffers here, 55526326Ssam * otherwise it'll never get done. 55626326Ssam */ 55726326Ssam public endprogram() 55826326Ssam { 55926326Ssam Integer exitcode; 56026326Ssam 56126326Ssam stepto(nextaddr(pc, true)); 56226326Ssam printnews(); 56326326Ssam exitcode = argn(1, nil); 56426326Ssam if (exitcode != 0) 56526326Ssam printf("\nexecution completed (exit code %d)\n", exitcode); 56626326Ssam else 56726326Ssam printf("\nexecution completed\n"); 56826326Ssam getsrcpos(); 56926326Ssam erecover(); 57026326Ssam } 57126326Ssam 57226326Ssam private Address getcall(); 57326326Ssam /* 57426326Ssam * Single step the machine a source line (or instruction if "inst_tracing" 57526326Ssam * is true). If "isnext" is true, skip over procedure calls. 57626326Ssam */ 57726326Ssam public dostep(isnext) 57826326Ssam Boolean isnext; 57926326Ssam { 58026326Ssam register Address addr; 58126326Ssam register Lineno line; 58226326Ssam String filename; 58326326Ssam Address startaddr; 58426326Ssam 58526326Ssam startaddr = pc; 58626326Ssam addr = nextaddr(pc, isnext); 58726326Ssam if (!inst_tracing && nlhdr.nlines != 0) { 58826326Ssam line = linelookup(addr); 58926326Ssam for (; line == 0; line = linelookup(addr)) 59026326Ssam addr = nextaddr(addr, isnext); 59126326Ssam curline = line; 59226326Ssam } else 59326326Ssam curline = 0; 59426326Ssam stepto(addr); 59526326Ssam filename = srcfilename(addr); 59626326Ssam setsource(filename); 59726326Ssam } 59826326Ssam 59926326Ssam private Address findnextaddr(); 60026326Ssam /* 60126326Ssam * Compute the next address that will be executed from the given one. 60226326Ssam * If "isnext" is true then consider a procedure call as straight line code. 60326326Ssam * 60426326Ssam * We must unfortunately do much of the same work that is necessary 60526326Ssam * to print instructions. In addition we have to deal with branches. 60626326Ssam * Unconditional branches we just follow, for conditional branches 60726326Ssam * we continue execution to the current location and then single step 60826326Ssam * the machine. We assume that the last argument in an instruction 60926326Ssam * that branches is the branch address (or relative offset). 61026326Ssam */ 61126326Ssam public Address nextaddr(startaddr, isnext) 61226326Ssam Address startaddr; 61326326Ssam boolean isnext; 61426326Ssam { 61526326Ssam Address addr; 61626326Ssam 61726326Ssam addr = usignal(process); 61826326Ssam if (addr == 0 or addr == 1) 61926326Ssam addr = findnextaddr(startaddr, isnext); 62026326Ssam return (addr); 62126326Ssam } 62226326Ssam 62326326Ssam /* 62426326Ssam * Determine if it's ok to skip function f entered by instruction ins. 62526326Ssam * If so, we're going to compute the return address and step to it. 62626326Ssam */ 62726326Ssam private boolean skipfunc(ins, f) 62826326Ssam Opcode ins; 62926326Ssam Symbol f; 63026326Ssam { 63126326Ssam 63226326Ssam return ((boolean) (!inst_tracing && nlhdr.nlines != 0 && 63326326Ssam nosource(curfunc) && canskip(curfunc))); 63426326Ssam } 63526326Ssam 63626326Ssam private Address findnextaddr(startaddr, isnext) 63726326Ssam Address startaddr; 63826326Ssam Boolean isnext; 63926326Ssam { 64026326Ssam register Address addr; 64126326Ssam Optab *op; 64226326Ssam Opcode ins; 64326326Ssam unsigned char mode; 64426326Ssam int argtype, amode, argno, argval, nib; 64526326Ssam String r; 64626326Ssam Boolean indexf; 64726326Ssam enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus; 64826326Ssam 64926326Ssam argval = 0; 65026326Ssam indexf = false; 65126326Ssam addr = startaddr; 65226326Ssam iread(&ins, addr, sizeof(ins)); 65326326Ssam switch (ins) { 65426326Ssam 65526326Ssam case O_CALLF: 65626326Ssam case O_CALLS: 65726326Ssam addrstatus = KNOWN; 65826326Ssam stepto(addr); 65926326Ssam pstep(process, DEFSIG); 66026326Ssam addr = reg(PROGCTR); 66126326Ssam pc = addr; 66226326Ssam setcurfunc(whatblock(pc)); 66326326Ssam if (not isbperr()) { 66426326Ssam printstatus(); 66526326Ssam /* NOTREACHED */ 66626326Ssam } 66726326Ssam bpact(); 66826326Ssam if (isnext or skipfunc(ins, curfunc)) { 66926326Ssam addrstatus = KNOWN; 67026326Ssam addr = return_addr(); 67126326Ssam stepto(addr); 67226326Ssam bpact(); 67326326Ssam } else 67426326Ssam callnews(/* iscall = */ true); 67526326Ssam break; 67626326Ssam 67726326Ssam case O_RET: 67826326Ssam addrstatus = KNOWN; 67926326Ssam stepto(addr); 68026326Ssam callnews(/* iscall = */ false); 68126326Ssam pstep(process, DEFSIG); 68226326Ssam addr = reg(PROGCTR); 68326326Ssam pc = addr; 68426326Ssam if (not isbperr()) 68526326Ssam printstatus(); 68626326Ssam bpact(); 68726326Ssam break; 68826326Ssam 68926326Ssam case O_BRB: 69026326Ssam case O_BRW: 69126326Ssam case O_JMP: 69226326Ssam case O_BBSSI: 69326326Ssam case O_BCC: 69426326Ssam case O_BCS: 69526326Ssam case O_BEQL: 69626326Ssam case O_BGEQ: 69726326Ssam case O_BGTR: 69826326Ssam case O_BGTRU: 69926326Ssam case O_BLEQ: 70026326Ssam case O_BLEQU: 70126326Ssam case O_BLSS: 70226326Ssam case O_BNEQ: 70326326Ssam case O_BVC: 70426326Ssam case O_BVS: 70526326Ssam case O_CASEL: 70626326Ssam case O_AOBLSS: 70726326Ssam case O_AOBLEQ: 70826326Ssam addrstatus = KNOWN; 70926326Ssam stepto(addr); 71026326Ssam pstep(process, DEFSIG); 71126326Ssam addr = reg(PROGCTR); 71226326Ssam pc = addr; 71326326Ssam if (not isbperr()) 71426326Ssam printstatus(); 71526326Ssam break; 71626326Ssam 71726326Ssam default: 71826326Ssam addrstatus = SEQUENTIAL; 71926326Ssam break; 72026326Ssam } 72126326Ssam if (addrstatus == KNOWN) 72226326Ssam return (addr); 72326326Ssam addr += 1; 72426326Ssam op = ioptab[ins]; 72526326Ssam for (argno = 0; argno < op->numargs; argno++) { 72626326Ssam if (indexf == true) 72726326Ssam indexf = false; 72826326Ssam argtype = op->argtype[argno]; 72926326Ssam if (is_branch_disp(argtype)) 73026326Ssam mode = 0xAF + (typelen(argtype) << 5); 73126326Ssam else 73226326Ssam iread(&mode, addr, sizeof(mode)), addr += 1; 73326326Ssam r = regname[regnm(mode)]; 73426326Ssam amode = addrmode(mode); 73526326Ssam switch (amode) { 73626326Ssam 73726326Ssam case LITSHORT: 73826326Ssam case LITUPTO31: 73926326Ssam case LITUPTO47: 74026326Ssam case LITUPTO63: 74126326Ssam argval = mode; 74226326Ssam break; 74326326Ssam 74426326Ssam case INDEX: 74526326Ssam indexf = true; 74626326Ssam --argno; 74726326Ssam break; 74826326Ssam 74926326Ssam case REG: 75026326Ssam case REGDEF: 75126326Ssam case AUTODEC: 75226326Ssam break; 75326326Ssam 75426326Ssam case AUTOINC: 75526326Ssam nib = mode & 0xf; 75626326Ssam if (nib == 0xf || nib == 8 || nib == 9) { 75726326Ssam int size = (mode&03)+1; 75826326Ssam 75926326Ssam argval = getdisp(addr, size, 76026326Ssam regname[PROGCTR], amode); 76126326Ssam addr += size; 76226326Ssam } 76326326Ssam break; 76426326Ssam 76526326Ssam case AUTOINCDEF: 76626326Ssam if ((mode&0xf) != 0xf) 76726326Ssam break; 76826326Ssam argval = getdisp(addr, 4, r, amode); 76926326Ssam addr += 4; 77026326Ssam break; 77126326Ssam 77226326Ssam case BYTEDISP: 77326326Ssam case BYTEDISPDEF: 77426326Ssam argval = getdisp(addr, 1, r, amode); 77526326Ssam addr += 1; 77626326Ssam break; 77726326Ssam 77826326Ssam case WORDDISP: 77926326Ssam case WORDDISPDEF: 78026326Ssam argval = getdisp(addr, 2, r, amode); 78126326Ssam addr += 2; 78226326Ssam break; 78326326Ssam 78426326Ssam case LONGDISP: 78526326Ssam case LONGDISPDEF: 78626326Ssam argval = getdisp(addr, 4, r, amode); 78726326Ssam addr += 4; 78826326Ssam break; 78926326Ssam } 79026326Ssam } 79126326Ssam if (ins == O_CALLF or ins == O_CALLS) 79226326Ssam argval += 2; 79326326Ssam if (addrstatus == BRANCH) 79426326Ssam addr = argval; 79526326Ssam return (addr); 79626326Ssam } 79726326Ssam 79826326Ssam /* 79926326Ssam * Get the displacement of an instruction that uses displacement addressing. 80026326Ssam */ 80126326Ssam private int getdisp(addr, nbytes, reg, mode) 80226326Ssam Address addr; 80326326Ssam int nbytes; 80426326Ssam String reg; 80526326Ssam int mode; 80626326Ssam { 80726326Ssam char byte; 80826326Ssam short hword; 80926326Ssam int argval; 81026326Ssam 81126326Ssam switch (nbytes) { 81226326Ssam 81326326Ssam case 1: 81426326Ssam iread(&byte, addr, sizeof(byte)); 81526326Ssam argval = byte; 81626326Ssam break; 81726326Ssam 81826326Ssam case 2: 81926326Ssam iread(&hword, addr, sizeof(hword)); 82026326Ssam argval = hword; 82126326Ssam break; 82226326Ssam 82326326Ssam case 4: 82426326Ssam iread(&argval, addr, sizeof(argval)); 82526326Ssam break; 82626326Ssam } 82726326Ssam if (reg == regname[PROGCTR] && mode >= BYTEDISP) 82826326Ssam argval += addr + nbytes; 82926326Ssam return (argval); 83026326Ssam } 83126326Ssam 83226326Ssam #define BP_OP O_BPT /* breakpoint trap */ 83326326Ssam #define BP_ERRNO SIGTRAP /* signal received at a breakpoint */ 83426326Ssam 83526326Ssam /* 83626326Ssam * Setting a breakpoint at a location consists of saving 83726326Ssam * the word at the location and poking a BP_OP there. 83826326Ssam * 83926326Ssam * We save the locations and words on a list for use in unsetting. 84026326Ssam */ 84126326Ssam typedef struct Savelist *Savelist; 84226326Ssam 84326326Ssam struct Savelist { 84426326Ssam Address location; 84526326Ssam Byte save; 84626326Ssam Byte refcount; 84726326Ssam Savelist link; 84826326Ssam }; 84926326Ssam 85026326Ssam private Savelist savelist; 85126326Ssam 85226326Ssam /* 85326326Ssam * Set a breakpoint at the given address. Only save the word there 85426326Ssam * if it's not already a breakpoint. 85526326Ssam */ 85626326Ssam public setbp(addr) 85726326Ssam Address addr; 85826326Ssam { 85926326Ssam Byte w, save; 86026326Ssam register Savelist newsave, s; 86126326Ssam 86226326Ssam for (s = savelist; s != nil; s = s->link) 86326326Ssam if (s->location == addr) { 86426326Ssam s->refcount++; 86526326Ssam return; 86626326Ssam } 86726326Ssam iread(&save, addr, sizeof(save)); 86826326Ssam newsave = new(Savelist); 86926326Ssam newsave->location = addr; 87026326Ssam newsave->save = save; 87126326Ssam newsave->refcount = 1; 87226326Ssam newsave->link = savelist; 87326326Ssam savelist = newsave; 87426326Ssam w = BP_OP; 87526326Ssam iwrite(&w, addr, sizeof(w)); 87626326Ssam } 87726326Ssam 87826326Ssam /* 87926326Ssam * Unset a breakpoint; unfortunately we have to search the SAVELIST 88026326Ssam * to find the saved value. The assumption is that the SAVELIST will 88126326Ssam * usually be quite small. 88226326Ssam */ 88326326Ssam public unsetbp(addr) 88426326Ssam Address addr; 88526326Ssam { 88626326Ssam register Savelist s, prev; 88726326Ssam 88826326Ssam prev = nil; 88926326Ssam for (s = savelist; s != nil; s = s->link) { 89026326Ssam if (s->location == addr) { 89126326Ssam iwrite(&s->save, addr, sizeof(s->save)); 89226326Ssam s->refcount--; 89326326Ssam if (s->refcount == 0) { 89426326Ssam if (prev == nil) 89526326Ssam savelist = s->link; 89626326Ssam else 89726326Ssam prev->link = s->link; 89826326Ssam dispose(s); 89926326Ssam } 90026326Ssam return; 90126326Ssam } 90226326Ssam prev = s; 90326326Ssam } 90426326Ssam panic("unsetbp: couldn't find address %d", addr); 90526326Ssam } 90626326Ssam 90726326Ssam /* 90826326Ssam * Enter a procedure by creating and executing a call instruction. 90926326Ssam */ 91026326Ssam 91126326Ssam #define CALLSIZE 7 /* size of call instruction */ 91226326Ssam 91326326Ssam public beginproc(p, argc) 91426326Ssam Symbol p; 91526326Ssam Integer argc; 91626326Ssam { 91726326Ssam char save[CALLSIZE]; 91826326Ssam struct { 91926326Ssam Opcode op; 92026326Ssam unsigned char numargs; 92126326Ssam unsigned char mode; 92226326Ssam char addr[sizeof(long)]; /* unaligned long */ 92326326Ssam } call; 92426326Ssam long dest; 92526326Ssam 92626326Ssam error("Can't do a \"call\" right now...sorry"); /* XXX */ 92726326Ssam if (4*argc+4 > 256) 92826326Ssam error("too many parameters (max %d)", 256/4 - 1); 92926326Ssam pc = 2; 93026326Ssam iread(save, pc, sizeof(save)); 93126326Ssam call.op = O_CALLF; 93226326Ssam call.numargs = 4*argc+4; 93326326Ssam call.mode = 0xef; /* longword relative */ 93426326Ssam dest = codeloc(p) - 2 - (pc + CALLSIZE); 93526326Ssam mov(&dest, call.addr, sizeof(call.addr)); 93626326Ssam iwrite(&call, pc, sizeof(call)); 93726326Ssam setreg(PROGCTR, pc); 93826326Ssam pstep(process, DEFSIG); 93926326Ssam iwrite(save, pc, sizeof(save)); 94026326Ssam pc = reg(PROGCTR); 94126326Ssam if (not isbperr()) 94226326Ssam printstatus(); 94326326Ssam } 944*26337Ssam 945*26337Ssam /* 946*26337Ssam * Special variables for debugging the kernel. 947*26337Ssam */ 948*26337Ssam 949*26337Ssam public integer masterpcbb; 950*26337Ssam public integer slr; 951*26337Ssam public struct pte *sbr; 952*26337Ssam public struct pcb pcb; 953*26337Ssam 954*26337Ssam public getpcb () 955*26337Ssam { 956*26337Ssam fseek(corefile, masterpcbb & ~0xc0000000, 0); 957*26337Ssam get(corefile, pcb); 958*26337Ssam printf("p0br %lx p0lr %lx p2br %lx p2lr %lx\n", 959*26337Ssam pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p2br, pcb.pcb_p2lr 960*26337Ssam ); 961*26337Ssam setreg(0, pcb.pcb_r0); 962*26337Ssam setreg(1, pcb.pcb_r1); 963*26337Ssam setreg(2, pcb.pcb_r2); 964*26337Ssam setreg(3, pcb.pcb_r3); 965*26337Ssam setreg(4, pcb.pcb_r4); 966*26337Ssam setreg(5, pcb.pcb_r5); 967*26337Ssam setreg(6, pcb.pcb_r6); 968*26337Ssam setreg(7, pcb.pcb_r7); 969*26337Ssam setreg(8, pcb.pcb_r8); 970*26337Ssam setreg(9, pcb.pcb_r9); 971*26337Ssam setreg(10, pcb.pcb_r10); 972*26337Ssam setreg(11, pcb.pcb_r11); 973*26337Ssam setreg(12, pcb.pcb_r12); 974*26337Ssam setreg(FRP, pcb.pcb_fp); 975*26337Ssam setreg(STKP, pcb.pcb_ksp); 976*26337Ssam setreg(PROGCTR, pcb.pcb_pc); 977*26337Ssam } 978*26337Ssam 979*26337Ssam public copyregs (savreg, reg) 980*26337Ssam Word savreg[], reg[]; 981*26337Ssam { 982*26337Ssam reg[0] = savreg[R0]; 983*26337Ssam reg[1] = savreg[R1]; 984*26337Ssam reg[2] = savreg[R2]; 985*26337Ssam reg[3] = savreg[R3]; 986*26337Ssam reg[4] = savreg[R4]; 987*26337Ssam reg[5] = savreg[R5]; 988*26337Ssam reg[6] = savreg[R6]; 989*26337Ssam reg[7] = savreg[R7]; 990*26337Ssam reg[8] = savreg[R8]; 991*26337Ssam reg[9] = savreg[R9]; 992*26337Ssam reg[10] = savreg[R10]; 993*26337Ssam reg[11] = savreg[R11]; 994*26337Ssam reg[12] = savreg[R12]; 995*26337Ssam reg[FRP] = savreg[FP]; 996*26337Ssam reg[STKP] = savreg[SP]; 997*26337Ssam reg[PROGCTR] = savreg[PC]; 998*26337Ssam } 999*26337Ssam 1000*26337Ssam /* 1001*26337Ssam * Map a virtual address to a physical address. 1002*26337Ssam */ 1003*26337Ssam 1004*26337Ssam public Address vmap (addr) 1005*26337Ssam Address addr; 1006*26337Ssam { 1007*26337Ssam int oldaddr = addr, v; 1008*26337Ssam struct pte pte; 1009*26337Ssam 1010*26337Ssam addr &= ~0xc0000000; 1011*26337Ssam v = btop(addr); 1012*26337Ssam switch (oldaddr&0xc0000000) { 1013*26337Ssam 1014*26337Ssam case 0xc0000000: 1015*26337Ssam /* 1016*26337Ssam * In system space get system pte. If 1017*26337Ssam * valid or reclaimable then physical address 1018*26337Ssam * is combination of its page number and the page 1019*26337Ssam * offset of the original address. 1020*26337Ssam */ 1021*26337Ssam if (v >= slr) 1022*26337Ssam goto oor; 1023*26337Ssam addr = ((long)(sbr+v)) &~ 0xc0000000; 1024*26337Ssam goto simple; 1025*26337Ssam 1026*26337Ssam case 0x80000000: 1027*26337Ssam /* 1028*26337Ssam * In p2 spce must not be in shadow region. 1029*26337Ssam */ 1030*26337Ssam if (v < pcb.pcb_p2lr) 1031*26337Ssam goto oor; 1032*26337Ssam addr = (long)(pcb.pcb_p2br+v); 1033*26337Ssam break; 1034*26337Ssam 1035*26337Ssam case 0x40000000: 1036*26337Ssam /* 1037*26337Ssam * In p1 space everything is verboten (for now). 1038*26337Ssam */ 1039*26337Ssam goto oor; 1040*26337Ssam 1041*26337Ssam case 0x00000000: 1042*26337Ssam /* 1043*26337Ssam * In p0 space must not be off end of region. 1044*26337Ssam */ 1045*26337Ssam if (v >= pcb.pcb_p0lr) 1046*26337Ssam goto oor; 1047*26337Ssam addr = (long)(pcb.pcb_p0br+v); 1048*26337Ssam break; 1049*26337Ssam oor: 1050*26337Ssam error("address out of segment"); 1051*26337Ssam } 1052*26337Ssam /* 1053*26337Ssam * For p0/p1/p2 address, user-level page table should 1054*26337Ssam * be in kernel vm. Do second-level indirect by recursing. 1055*26337Ssam */ 1056*26337Ssam if ((addr & 0xc0000000) != 0xc0000000) 1057*26337Ssam error("bad p0br, p1br, or p2br in pcb"); 1058*26337Ssam addr = vmap(addr); 1059*26337Ssam simple: 1060*26337Ssam /* 1061*26337Ssam * Addr is now address of the pte of the page we 1062*26337Ssam * are interested in; get the pte and paste up the 1063*26337Ssam * physical address. 1064*26337Ssam */ 1065*26337Ssam fseek(corefile, addr, 0); 1066*26337Ssam if (fread(&pte, sizeof (pte), 1, corefile) != 1) 1067*26337Ssam error("page table botch"); 1068*26337Ssam /* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */ 1069*26337Ssam if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) 1070*26337Ssam error("page not valid/reclaimable"); 1071*26337Ssam return ((long)(ptob(pte.pg_pfnum) + (oldaddr & PGOFSET))); 1072*26337Ssam } 1073