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