1*26326Ssam /* 2*26326Ssam * Copyright (c) 1985 Regents of the University of California. 3*26326Ssam * All rights reserved. The Berkeley software License Agreement 4*26326Ssam * specifies the terms and conditions for redistribution. 5*26326Ssam */ 6*26326Ssam 7*26326Ssam #ifndef lint 8*26326Ssam static char sccsid[] = "@(#)tahoe.c 1.1 (Berkeley) 02/22/86"; 9*26326Ssam #endif not lint 10*26326Ssam 11*26326Ssam /* 12*26326Ssam * Target machine dependent stuff. 13*26326Ssam */ 14*26326Ssam 15*26326Ssam #include "defs.h" 16*26326Ssam #include "machine.h" 17*26326Ssam #include "process.h" 18*26326Ssam #include "runtime.h" 19*26326Ssam #include "events.h" 20*26326Ssam #include "main.h" 21*26326Ssam #include "symbols.h" 22*26326Ssam #include "source.h" 23*26326Ssam #include "mappings.h" 24*26326Ssam #include "object.h" 25*26326Ssam #include "keywords.h" 26*26326Ssam #include "ops.h" 27*26326Ssam #include <signal.h> 28*26326Ssam 29*26326Ssam #ifndef public 30*26326Ssam typedef unsigned int Address; 31*26326Ssam typedef unsigned char Byte; 32*26326Ssam typedef unsigned int Word; 33*26326Ssam 34*26326Ssam #define NREG 16 35*26326Ssam 36*26326Ssam #define FRP 13 37*26326Ssam #define STKP 14 38*26326Ssam #define PROGCTR 15 39*26326Ssam 40*26326Ssam #define BITSPERBYTE 8 41*26326Ssam #define BITSPERWORD (BITSPERBYTE * sizeof(Word)) 42*26326Ssam 43*26326Ssam #define nargspassed(frame) ((frame->removed-4)/4) 44*26326Ssam 45*26326Ssam #include "source.h" 46*26326Ssam #include "symbols.h" 47*26326Ssam 48*26326Ssam Address pc; 49*26326Ssam Address prtaddr; 50*26326Ssam 51*26326Ssam #endif 52*26326Ssam 53*26326Ssam private Address printop(); 54*26326Ssam 55*26326Ssam Optab *ioptab[256]; /* index by opcode to optab */ 56*26326Ssam /* 57*26326Ssam * Initialize the opcode lookup table. 58*26326Ssam */ 59*26326Ssam public optab_init() 60*26326Ssam { 61*26326Ssam register Optab *p; 62*26326Ssam 63*26326Ssam for (p = optab; p->iname; p++) 64*26326Ssam ioptab[p->val & 0xff] = p; 65*26326Ssam } 66*26326Ssam 67*26326Ssam /* 68*26326Ssam * Decode and print the instructions within the given address range. 69*26326Ssam */ 70*26326Ssam public printinst(lowaddr, highaddr) 71*26326Ssam Address lowaddr, highaddr; 72*26326Ssam { 73*26326Ssam register Address addr; 74*26326Ssam 75*26326Ssam for (addr = lowaddr; addr <= highaddr; ) 76*26326Ssam addr = printop(addr); 77*26326Ssam prtaddr = addr; 78*26326Ssam } 79*26326Ssam 80*26326Ssam /* 81*26326Ssam * Another approach: print n instructions starting at the given address. 82*26326Ssam */ 83*26326Ssam public printninst(count, addr) 84*26326Ssam int count; 85*26326Ssam Address addr; 86*26326Ssam { 87*26326Ssam register Integer i; 88*26326Ssam register Address newaddr; 89*26326Ssam 90*26326Ssam if (count <= 0) 91*26326Ssam error("non-positive repetition count"); 92*26326Ssam for (newaddr = addr, i = 0; i < count; i++) 93*26326Ssam newaddr = printop(newaddr); 94*26326Ssam prtaddr = newaddr; 95*26326Ssam } 96*26326Ssam 97*26326Ssam /* 98*26326Ssam * Hacked version of adb's instruction decoder. 99*26326Ssam */ 100*26326Ssam private Address printop(addr) 101*26326Ssam Address addr; 102*26326Ssam { 103*26326Ssam register Optab *op; 104*26326Ssam Opcode ins; 105*26326Ssam unsigned char mode; 106*26326Ssam int argtype, amode, argno, argval, r; 107*26326Ssam String reg; 108*26326Ssam Boolean indexf; 109*26326Ssam short offset; 110*26326Ssam 111*26326Ssam argval = 0; 112*26326Ssam indexf = false; 113*26326Ssam printf("%08x ", addr); 114*26326Ssam iread(&ins, addr, sizeof(ins)); 115*26326Ssam addr += 1; 116*26326Ssam op = ioptab[ins]; 117*26326Ssam printf("%s", op->iname); 118*26326Ssam for (argno = 0; argno < op->numargs; argno++) { 119*26326Ssam if (indexf == true) 120*26326Ssam indexf = false; 121*26326Ssam else 122*26326Ssam printf(argno == 0 ? "\t" : ","); 123*26326Ssam argtype = op->argtype[argno]; 124*26326Ssam if (is_branch_disp(argtype)) 125*26326Ssam mode = 0xAF + (typelen(argtype) << 5); 126*26326Ssam else 127*26326Ssam iread(&mode, addr, sizeof(mode)), addr += 1; 128*26326Ssam reg = regname[regnm(mode)]; 129*26326Ssam amode = addrmode(mode); 130*26326Ssam switch (amode) { 131*26326Ssam 132*26326Ssam case LITSHORT: case LITUPTO31: 133*26326Ssam case LITUPTO47: case LITUPTO63: 134*26326Ssam if (ins == O_KCALL && mode >= 0 && mode < SYSSIZE && 135*26326Ssam systab[mode]) 136*26326Ssam printf("$%s", systab[mode]); 137*26326Ssam else 138*26326Ssam printf("$%x", mode); 139*26326Ssam argval = mode; 140*26326Ssam break; 141*26326Ssam 142*26326Ssam case INDEX: 143*26326Ssam printf("[%s]", reg); 144*26326Ssam indexf = true; 145*26326Ssam argno--; 146*26326Ssam break; 147*26326Ssam 148*26326Ssam case REG: 149*26326Ssam printf("%s", reg); 150*26326Ssam break; 151*26326Ssam 152*26326Ssam case REGDEF: 153*26326Ssam printf("(%s)", reg); 154*26326Ssam break; 155*26326Ssam 156*26326Ssam case AUTODEC: 157*26326Ssam printf("-(%s)", reg); 158*26326Ssam break; 159*26326Ssam 160*26326Ssam case AUTOINC: 161*26326Ssam r = mode & 0xf; 162*26326Ssam if (r == 0xf || r == 8 || r == 9) { 163*26326Ssam int size = (mode&03) + 1; 164*26326Ssam 165*26326Ssam /* immediate mode */ 166*26326Ssam printf("$"); 167*26326Ssam argval = printdisp(addr, size, 168*26326Ssam regname[PROGCTR], amode); 169*26326Ssam addr += size; 170*26326Ssam } else 171*26326Ssam printf("(%s)+", reg); 172*26326Ssam break; 173*26326Ssam 174*26326Ssam case AUTOINCDEF: 175*26326Ssam if ((mode&0xf) == 0xf) { 176*26326Ssam printf("*$"); 177*26326Ssam argval = printdisp(addr, 4, reg, amode); 178*26326Ssam addr += 4; 179*26326Ssam } else 180*26326Ssam printf("*(%s)+", reg); 181*26326Ssam break; 182*26326Ssam 183*26326Ssam case BYTEDISP: 184*26326Ssam argval = printdisp(addr, 1, reg, amode); 185*26326Ssam addr += 1; 186*26326Ssam break; 187*26326Ssam 188*26326Ssam case BYTEDISPDEF: 189*26326Ssam printf("*"); 190*26326Ssam argval = printdisp(addr, 1, reg, amode); 191*26326Ssam addr += 1; 192*26326Ssam break; 193*26326Ssam 194*26326Ssam case WORDDISP: 195*26326Ssam argval = printdisp(addr, 2, reg, amode); 196*26326Ssam addr += 2; 197*26326Ssam break; 198*26326Ssam 199*26326Ssam case WORDDISPDEF: 200*26326Ssam printf("*"); 201*26326Ssam argval = printdisp(addr, 2, reg, amode); 202*26326Ssam addr += 2; 203*26326Ssam break; 204*26326Ssam 205*26326Ssam case LONGDISP: 206*26326Ssam argval = printdisp(addr, 4, reg, amode); 207*26326Ssam addr += 4; 208*26326Ssam break; 209*26326Ssam 210*26326Ssam case LONGDISPDEF: 211*26326Ssam printf("*"); 212*26326Ssam argval = printdisp(addr, 4, reg, amode); 213*26326Ssam addr += 4; 214*26326Ssam break; 215*26326Ssam } 216*26326Ssam } 217*26326Ssam if (ins == O_CASEL) 218*26326Ssam for (argno = 0; argno <= argval; argno++) { 219*26326Ssam iread(&offset, addr, sizeof(offset)); 220*26326Ssam printf("\n\t\t%d", offset); 221*26326Ssam addr += 2; 222*26326Ssam } 223*26326Ssam printf("\n"); 224*26326Ssam return (addr); 225*26326Ssam } 226*26326Ssam 227*26326Ssam /* 228*26326Ssam * Print the displacement of an instruction that uses displacement 229*26326Ssam * addressing. 230*26326Ssam */ 231*26326Ssam private int printdisp(addr, nbytes, reg, mode) 232*26326Ssam Address addr; 233*26326Ssam int nbytes; 234*26326Ssam char *reg; 235*26326Ssam int mode; 236*26326Ssam { 237*26326Ssam char byte; 238*26326Ssam short hword; 239*26326Ssam int argval; 240*26326Ssam Symbol f; 241*26326Ssam 242*26326Ssam switch (nbytes) { 243*26326Ssam 244*26326Ssam case 1: 245*26326Ssam iread(&byte, addr, sizeof(byte)); 246*26326Ssam argval = byte; 247*26326Ssam break; 248*26326Ssam 249*26326Ssam case 2: 250*26326Ssam iread(&hword, addr, sizeof(hword)); 251*26326Ssam argval = hword; 252*26326Ssam break; 253*26326Ssam 254*26326Ssam case 4: 255*26326Ssam iread(&argval, addr, sizeof(argval)); 256*26326Ssam break; 257*26326Ssam } 258*26326Ssam if (reg == regname[PROGCTR] && mode >= BYTEDISP) 259*26326Ssam argval += addr + nbytes; 260*26326Ssam if (reg == regname[PROGCTR]) { 261*26326Ssam f = whatblock((Address) argval + 2); 262*26326Ssam if (codeloc(f) == argval + 2) 263*26326Ssam printf("%s", symname(f)); 264*26326Ssam else 265*26326Ssam printf("%x", argval); 266*26326Ssam } else { 267*26326Ssam if (varIsSet("$hexoffsets")) { 268*26326Ssam if (argval < 0) 269*26326Ssam printf("-%x(%s)", -(argval), reg); 270*26326Ssam else 271*26326Ssam printf("%x(%s)", argval, reg); 272*26326Ssam } else 273*26326Ssam printf("%d(%s)", argval, reg); 274*26326Ssam } 275*26326Ssam return (argval); 276*26326Ssam } 277*26326Ssam 278*26326Ssam /* 279*26326Ssam * Print the contents of the addresses within the given range 280*26326Ssam * according to the given format. 281*26326Ssam */ 282*26326Ssam typedef struct { 283*26326Ssam String name; 284*26326Ssam String printfstring; 285*26326Ssam int length; 286*26326Ssam } Format; 287*26326Ssam 288*26326Ssam private Format fmt[] = { 289*26326Ssam { "d", " %d", sizeof(short) }, 290*26326Ssam { "D", " %ld", sizeof(long) }, 291*26326Ssam { "o", " %o", sizeof(short) }, 292*26326Ssam { "O", " %lo", sizeof(long) }, 293*26326Ssam { "x", " %04x", sizeof(short) }, 294*26326Ssam { "X", " %08x", sizeof(long) }, 295*26326Ssam { "b", " \\%o", sizeof(char) }, 296*26326Ssam { "c", " '%c'", sizeof(char) }, 297*26326Ssam { "s", "%c", sizeof(char) }, 298*26326Ssam { "f", " %f", sizeof(float) }, 299*26326Ssam { "g", " %g", sizeof(double) }, 300*26326Ssam { nil, nil, 0 } 301*26326Ssam }; 302*26326Ssam 303*26326Ssam private Format *findformat(s) 304*26326Ssam String s; 305*26326Ssam { 306*26326Ssam register Format *f; 307*26326Ssam 308*26326Ssam for (f = &fmt[0]; f->name != nil && !streq(f->name, s); f++) 309*26326Ssam ; 310*26326Ssam if (f->name == nil) 311*26326Ssam error("bad print format \"%s\"", s); 312*26326Ssam return (f); 313*26326Ssam } 314*26326Ssam 315*26326Ssam public Address printdata(lowaddr, highaddr, format) 316*26326Ssam Address lowaddr; 317*26326Ssam Address highaddr; 318*26326Ssam String format; 319*26326Ssam { 320*26326Ssam register int n; 321*26326Ssam register Address addr; 322*26326Ssam register Format *f; 323*26326Ssam int value; 324*26326Ssam 325*26326Ssam if (lowaddr > highaddr) 326*26326Ssam error("first address larger than second"); 327*26326Ssam f = findformat(format); 328*26326Ssam n = 0; 329*26326Ssam value = 0; 330*26326Ssam for (addr = lowaddr; addr <= highaddr; addr += f->length) { 331*26326Ssam if (n == 0) 332*26326Ssam printf("%08x: ", addr); 333*26326Ssam dread(&value, addr, f->length); 334*26326Ssam printf(f->printfstring, value); 335*26326Ssam ++n; 336*26326Ssam if (n >= (16 div f->length)) { 337*26326Ssam putchar('\n'); 338*26326Ssam n = 0; 339*26326Ssam } 340*26326Ssam } 341*26326Ssam if (n != 0) 342*26326Ssam putchar('\n'); 343*26326Ssam prtaddr = addr; 344*26326Ssam return (addr); 345*26326Ssam } 346*26326Ssam 347*26326Ssam /* 348*26326Ssam * The other approach is to print n items starting with a given address. 349*26326Ssam */ 350*26326Ssam 351*26326Ssam public printndata(count, startaddr, format) 352*26326Ssam int count; 353*26326Ssam Address startaddr; 354*26326Ssam String format; 355*26326Ssam { 356*26326Ssam register int i, n; 357*26326Ssam register Address addr; 358*26326Ssam register Format *f; 359*26326Ssam register Boolean isstring; 360*26326Ssam char c; 361*26326Ssam union { 362*26326Ssam char charv; 363*26326Ssam short shortv; 364*26326Ssam int intv; 365*26326Ssam float floatv; 366*26326Ssam double doublev; 367*26326Ssam } value; 368*26326Ssam 369*26326Ssam if (count <= 0) 370*26326Ssam error("non-positive repetition count"); 371*26326Ssam f = findformat(format); 372*26326Ssam isstring = (Boolean) streq(f->name, "s"); 373*26326Ssam n = 0; 374*26326Ssam addr = startaddr; 375*26326Ssam value.intv = 0; 376*26326Ssam for (i = 0; i < count; i++) { 377*26326Ssam if (n == 0) 378*26326Ssam printf("%08x: ", addr); 379*26326Ssam if (isstring) { 380*26326Ssam putchar('"'); 381*26326Ssam dread(&c, addr, sizeof(char)); 382*26326Ssam while (c != '\0') { 383*26326Ssam printchar(c); 384*26326Ssam ++addr; 385*26326Ssam dread(&c, addr, sizeof(char)); 386*26326Ssam } 387*26326Ssam putchar('"'); 388*26326Ssam putchar('\n'); 389*26326Ssam n = 0; 390*26326Ssam addr += sizeof(String); 391*26326Ssam continue; 392*26326Ssam } 393*26326Ssam dread(&value, addr, f->length); 394*26326Ssam printf(f->printfstring, value); 395*26326Ssam ++n; 396*26326Ssam if (n >= (16 div f->length)) { 397*26326Ssam putchar('\n'); 398*26326Ssam n = 0; 399*26326Ssam } 400*26326Ssam addr += f->length; 401*26326Ssam } 402*26326Ssam if (n != 0) 403*26326Ssam putchar('\n'); 404*26326Ssam prtaddr = addr; 405*26326Ssam } 406*26326Ssam 407*26326Ssam /* 408*26326Ssam * Print out a value according to the given format. 409*26326Ssam */ 410*26326Ssam public printvalue(v, format) 411*26326Ssam long v; 412*26326Ssam String format; 413*26326Ssam { 414*26326Ssam Format *f; 415*26326Ssam char *p, *q; 416*26326Ssam 417*26326Ssam f = findformat(format); 418*26326Ssam if (streq(f->name, "s")) { 419*26326Ssam putchar('"'); 420*26326Ssam for (p = (char *) &v, q = p + sizeof(v); p < q; ++p) 421*26326Ssam printchar(*p); 422*26326Ssam putchar('"'); 423*26326Ssam } else 424*26326Ssam printf(f->printfstring, v); 425*26326Ssam putchar('\n'); 426*26326Ssam } 427*26326Ssam 428*26326Ssam /* 429*26326Ssam * Print out an execution time error. 430*26326Ssam * Assumes the source position of the error has been calculated. 431*26326Ssam * 432*26326Ssam * Have to check if the -r option was specified; if so then 433*26326Ssam * the object file information hasn't been read in yet. 434*26326Ssam */ 435*26326Ssam public printerror() 436*26326Ssam { 437*26326Ssam extern Integer sys_nsig; 438*26326Ssam extern String sys_siglist[]; 439*26326Ssam integer err; 440*26326Ssam 441*26326Ssam if (isfinished(process)) { 442*26326Ssam err = exitcode(process); 443*26326Ssam if (err) { 444*26326Ssam printf("\"%s\" terminated abnormally (exit code %d)\n", 445*26326Ssam objname, err); 446*26326Ssam erecover(); 447*26326Ssam } else 448*26326Ssam printf("\"%s\" terminated normally\n", objname); 449*26326Ssam } 450*26326Ssam if (runfirst) { 451*26326Ssam fprintf(stderr, "Entering debugger ...\n"); 452*26326Ssam init(); 453*26326Ssam } 454*26326Ssam err = errnum(process); 455*26326Ssam putchar('\n'); 456*26326Ssam printsig(err); 457*26326Ssam putchar(' '); 458*26326Ssam printloc(); 459*26326Ssam putchar('\n'); 460*26326Ssam if (curline > 0) 461*26326Ssam printlines(curline, curline); 462*26326Ssam else 463*26326Ssam printinst(pc, pc); 464*26326Ssam erecover(); 465*26326Ssam } 466*26326Ssam 467*26326Ssam /* 468*26326Ssam * Print out a signal. 469*26326Ssam */ 470*26326Ssam private String illinames[] = { 471*26326Ssam "reserved addressing fault", 472*26326Ssam "priviliged instruction fault", 473*26326Ssam "reserved operand fault" 474*26326Ssam }; 475*26326Ssam #define NILLINAMES (sizeof (illinames) / sizeof (illinames[0])) 476*26326Ssam 477*26326Ssam private String fpenames[] = { 478*26326Ssam nil, 479*26326Ssam "integer overflow trap", 480*26326Ssam "integer divide by zero trap", 481*26326Ssam "floating point divide by zero trap", 482*26326Ssam "floating point overflow trap", 483*26326Ssam "floating point underflow trap", 484*26326Ssam }; 485*26326Ssam #define NFPENAMES (sizeof (fpenames) / sizeof (fpenames[0])) 486*26326Ssam 487*26326Ssam public printsig(signo) 488*26326Ssam integer signo; 489*26326Ssam { 490*26326Ssam integer code; 491*26326Ssam 492*26326Ssam if (signo < 0 or signo > sys_nsig) 493*26326Ssam printf("[signal %d]", signo); 494*26326Ssam else 495*26326Ssam printf("%s", sys_siglist[signo]); 496*26326Ssam code = errcode(process); 497*26326Ssam if (signo == SIGILL) 498*26326Ssam if (code >= 0 && code < NILLINAMES) 499*26326Ssam printf(" (%s)", illinames[code]); 500*26326Ssam if (signo == SIGFPE) 501*26326Ssam if (code > 0 and code < NFPENAMES) 502*26326Ssam printf(" (%s)", fpenames[code]); 503*26326Ssam } 504*26326Ssam 505*26326Ssam /* 506*26326Ssam * Note the termination of the program. We do this so as to avoid 507*26326Ssam * having the process exit, which would make the values of variables 508*26326Ssam * inaccessible. We do want to flush all output buffers here, 509*26326Ssam * otherwise it'll never get done. 510*26326Ssam */ 511*26326Ssam public endprogram() 512*26326Ssam { 513*26326Ssam Integer exitcode; 514*26326Ssam 515*26326Ssam stepto(nextaddr(pc, true)); 516*26326Ssam printnews(); 517*26326Ssam exitcode = argn(1, nil); 518*26326Ssam if (exitcode != 0) 519*26326Ssam printf("\nexecution completed (exit code %d)\n", exitcode); 520*26326Ssam else 521*26326Ssam printf("\nexecution completed\n"); 522*26326Ssam getsrcpos(); 523*26326Ssam erecover(); 524*26326Ssam } 525*26326Ssam 526*26326Ssam private Address getcall(); 527*26326Ssam /* 528*26326Ssam * Single step the machine a source line (or instruction if "inst_tracing" 529*26326Ssam * is true). If "isnext" is true, skip over procedure calls. 530*26326Ssam */ 531*26326Ssam public dostep(isnext) 532*26326Ssam Boolean isnext; 533*26326Ssam { 534*26326Ssam register Address addr; 535*26326Ssam register Lineno line; 536*26326Ssam String filename; 537*26326Ssam Address startaddr; 538*26326Ssam 539*26326Ssam startaddr = pc; 540*26326Ssam addr = nextaddr(pc, isnext); 541*26326Ssam if (!inst_tracing && nlhdr.nlines != 0) { 542*26326Ssam line = linelookup(addr); 543*26326Ssam for (; line == 0; line = linelookup(addr)) 544*26326Ssam addr = nextaddr(addr, isnext); 545*26326Ssam curline = line; 546*26326Ssam } else 547*26326Ssam curline = 0; 548*26326Ssam stepto(addr); 549*26326Ssam filename = srcfilename(addr); 550*26326Ssam setsource(filename); 551*26326Ssam } 552*26326Ssam 553*26326Ssam private Address findnextaddr(); 554*26326Ssam /* 555*26326Ssam * Compute the next address that will be executed from the given one. 556*26326Ssam * If "isnext" is true then consider a procedure call as straight line code. 557*26326Ssam * 558*26326Ssam * We must unfortunately do much of the same work that is necessary 559*26326Ssam * to print instructions. In addition we have to deal with branches. 560*26326Ssam * Unconditional branches we just follow, for conditional branches 561*26326Ssam * we continue execution to the current location and then single step 562*26326Ssam * the machine. We assume that the last argument in an instruction 563*26326Ssam * that branches is the branch address (or relative offset). 564*26326Ssam */ 565*26326Ssam public Address nextaddr(startaddr, isnext) 566*26326Ssam Address startaddr; 567*26326Ssam boolean isnext; 568*26326Ssam { 569*26326Ssam Address addr; 570*26326Ssam 571*26326Ssam addr = usignal(process); 572*26326Ssam if (addr == 0 or addr == 1) 573*26326Ssam addr = findnextaddr(startaddr, isnext); 574*26326Ssam return (addr); 575*26326Ssam } 576*26326Ssam 577*26326Ssam /* 578*26326Ssam * Determine if it's ok to skip function f entered by instruction ins. 579*26326Ssam * If so, we're going to compute the return address and step to it. 580*26326Ssam */ 581*26326Ssam private boolean skipfunc(ins, f) 582*26326Ssam Opcode ins; 583*26326Ssam Symbol f; 584*26326Ssam { 585*26326Ssam 586*26326Ssam return ((boolean) (!inst_tracing && nlhdr.nlines != 0 && 587*26326Ssam nosource(curfunc) && canskip(curfunc))); 588*26326Ssam } 589*26326Ssam 590*26326Ssam private Address findnextaddr(startaddr, isnext) 591*26326Ssam Address startaddr; 592*26326Ssam Boolean isnext; 593*26326Ssam { 594*26326Ssam register Address addr; 595*26326Ssam Optab *op; 596*26326Ssam Opcode ins; 597*26326Ssam unsigned char mode; 598*26326Ssam int argtype, amode, argno, argval, nib; 599*26326Ssam String r; 600*26326Ssam Boolean indexf; 601*26326Ssam enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus; 602*26326Ssam 603*26326Ssam argval = 0; 604*26326Ssam indexf = false; 605*26326Ssam addr = startaddr; 606*26326Ssam iread(&ins, addr, sizeof(ins)); 607*26326Ssam switch (ins) { 608*26326Ssam 609*26326Ssam case O_CALLF: 610*26326Ssam case O_CALLS: 611*26326Ssam addrstatus = KNOWN; 612*26326Ssam stepto(addr); 613*26326Ssam pstep(process, DEFSIG); 614*26326Ssam addr = reg(PROGCTR); 615*26326Ssam pc = addr; 616*26326Ssam setcurfunc(whatblock(pc)); 617*26326Ssam if (not isbperr()) { 618*26326Ssam printstatus(); 619*26326Ssam /* NOTREACHED */ 620*26326Ssam } 621*26326Ssam bpact(); 622*26326Ssam if (isnext or skipfunc(ins, curfunc)) { 623*26326Ssam addrstatus = KNOWN; 624*26326Ssam addr = return_addr(); 625*26326Ssam stepto(addr); 626*26326Ssam bpact(); 627*26326Ssam } else 628*26326Ssam callnews(/* iscall = */ true); 629*26326Ssam break; 630*26326Ssam 631*26326Ssam case O_RET: 632*26326Ssam addrstatus = KNOWN; 633*26326Ssam stepto(addr); 634*26326Ssam callnews(/* iscall = */ false); 635*26326Ssam pstep(process, DEFSIG); 636*26326Ssam addr = reg(PROGCTR); 637*26326Ssam pc = addr; 638*26326Ssam if (not isbperr()) 639*26326Ssam printstatus(); 640*26326Ssam bpact(); 641*26326Ssam break; 642*26326Ssam 643*26326Ssam case O_BRB: 644*26326Ssam case O_BRW: 645*26326Ssam case O_JMP: 646*26326Ssam case O_BBSSI: 647*26326Ssam case O_BCC: 648*26326Ssam case O_BCS: 649*26326Ssam case O_BEQL: 650*26326Ssam case O_BGEQ: 651*26326Ssam case O_BGTR: 652*26326Ssam case O_BGTRU: 653*26326Ssam case O_BLEQ: 654*26326Ssam case O_BLEQU: 655*26326Ssam case O_BLSS: 656*26326Ssam case O_BNEQ: 657*26326Ssam case O_BVC: 658*26326Ssam case O_BVS: 659*26326Ssam case O_CASEL: 660*26326Ssam case O_AOBLSS: 661*26326Ssam case O_AOBLEQ: 662*26326Ssam addrstatus = KNOWN; 663*26326Ssam stepto(addr); 664*26326Ssam pstep(process, DEFSIG); 665*26326Ssam addr = reg(PROGCTR); 666*26326Ssam pc = addr; 667*26326Ssam if (not isbperr()) 668*26326Ssam printstatus(); 669*26326Ssam break; 670*26326Ssam 671*26326Ssam default: 672*26326Ssam addrstatus = SEQUENTIAL; 673*26326Ssam break; 674*26326Ssam } 675*26326Ssam if (addrstatus == KNOWN) 676*26326Ssam return (addr); 677*26326Ssam addr += 1; 678*26326Ssam op = ioptab[ins]; 679*26326Ssam for (argno = 0; argno < op->numargs; argno++) { 680*26326Ssam if (indexf == true) 681*26326Ssam indexf = false; 682*26326Ssam argtype = op->argtype[argno]; 683*26326Ssam if (is_branch_disp(argtype)) 684*26326Ssam mode = 0xAF + (typelen(argtype) << 5); 685*26326Ssam else 686*26326Ssam iread(&mode, addr, sizeof(mode)), addr += 1; 687*26326Ssam r = regname[regnm(mode)]; 688*26326Ssam amode = addrmode(mode); 689*26326Ssam switch (amode) { 690*26326Ssam 691*26326Ssam case LITSHORT: 692*26326Ssam case LITUPTO31: 693*26326Ssam case LITUPTO47: 694*26326Ssam case LITUPTO63: 695*26326Ssam argval = mode; 696*26326Ssam break; 697*26326Ssam 698*26326Ssam case INDEX: 699*26326Ssam indexf = true; 700*26326Ssam --argno; 701*26326Ssam break; 702*26326Ssam 703*26326Ssam case REG: 704*26326Ssam case REGDEF: 705*26326Ssam case AUTODEC: 706*26326Ssam break; 707*26326Ssam 708*26326Ssam case AUTOINC: 709*26326Ssam nib = mode & 0xf; 710*26326Ssam if (nib == 0xf || nib == 8 || nib == 9) { 711*26326Ssam int size = (mode&03)+1; 712*26326Ssam 713*26326Ssam argval = getdisp(addr, size, 714*26326Ssam regname[PROGCTR], amode); 715*26326Ssam addr += size; 716*26326Ssam } 717*26326Ssam break; 718*26326Ssam 719*26326Ssam case AUTOINCDEF: 720*26326Ssam if ((mode&0xf) != 0xf) 721*26326Ssam break; 722*26326Ssam argval = getdisp(addr, 4, r, amode); 723*26326Ssam addr += 4; 724*26326Ssam break; 725*26326Ssam 726*26326Ssam case BYTEDISP: 727*26326Ssam case BYTEDISPDEF: 728*26326Ssam argval = getdisp(addr, 1, r, amode); 729*26326Ssam addr += 1; 730*26326Ssam break; 731*26326Ssam 732*26326Ssam case WORDDISP: 733*26326Ssam case WORDDISPDEF: 734*26326Ssam argval = getdisp(addr, 2, r, amode); 735*26326Ssam addr += 2; 736*26326Ssam break; 737*26326Ssam 738*26326Ssam case LONGDISP: 739*26326Ssam case LONGDISPDEF: 740*26326Ssam argval = getdisp(addr, 4, r, amode); 741*26326Ssam addr += 4; 742*26326Ssam break; 743*26326Ssam } 744*26326Ssam } 745*26326Ssam if (ins == O_CALLF or ins == O_CALLS) 746*26326Ssam argval += 2; 747*26326Ssam if (addrstatus == BRANCH) 748*26326Ssam addr = argval; 749*26326Ssam return (addr); 750*26326Ssam } 751*26326Ssam 752*26326Ssam /* 753*26326Ssam * Get the displacement of an instruction that uses displacement addressing. 754*26326Ssam */ 755*26326Ssam private int getdisp(addr, nbytes, reg, mode) 756*26326Ssam Address addr; 757*26326Ssam int nbytes; 758*26326Ssam String reg; 759*26326Ssam int mode; 760*26326Ssam { 761*26326Ssam char byte; 762*26326Ssam short hword; 763*26326Ssam int argval; 764*26326Ssam 765*26326Ssam switch (nbytes) { 766*26326Ssam 767*26326Ssam case 1: 768*26326Ssam iread(&byte, addr, sizeof(byte)); 769*26326Ssam argval = byte; 770*26326Ssam break; 771*26326Ssam 772*26326Ssam case 2: 773*26326Ssam iread(&hword, addr, sizeof(hword)); 774*26326Ssam argval = hword; 775*26326Ssam break; 776*26326Ssam 777*26326Ssam case 4: 778*26326Ssam iread(&argval, addr, sizeof(argval)); 779*26326Ssam break; 780*26326Ssam } 781*26326Ssam if (reg == regname[PROGCTR] && mode >= BYTEDISP) 782*26326Ssam argval += addr + nbytes; 783*26326Ssam return (argval); 784*26326Ssam } 785*26326Ssam 786*26326Ssam #define BP_OP O_BPT /* breakpoint trap */ 787*26326Ssam #define BP_ERRNO SIGTRAP /* signal received at a breakpoint */ 788*26326Ssam 789*26326Ssam /* 790*26326Ssam * Setting a breakpoint at a location consists of saving 791*26326Ssam * the word at the location and poking a BP_OP there. 792*26326Ssam * 793*26326Ssam * We save the locations and words on a list for use in unsetting. 794*26326Ssam */ 795*26326Ssam typedef struct Savelist *Savelist; 796*26326Ssam 797*26326Ssam struct Savelist { 798*26326Ssam Address location; 799*26326Ssam Byte save; 800*26326Ssam Byte refcount; 801*26326Ssam Savelist link; 802*26326Ssam }; 803*26326Ssam 804*26326Ssam private Savelist savelist; 805*26326Ssam 806*26326Ssam /* 807*26326Ssam * Set a breakpoint at the given address. Only save the word there 808*26326Ssam * if it's not already a breakpoint. 809*26326Ssam */ 810*26326Ssam public setbp(addr) 811*26326Ssam Address addr; 812*26326Ssam { 813*26326Ssam Byte w, save; 814*26326Ssam register Savelist newsave, s; 815*26326Ssam 816*26326Ssam for (s = savelist; s != nil; s = s->link) 817*26326Ssam if (s->location == addr) { 818*26326Ssam s->refcount++; 819*26326Ssam return; 820*26326Ssam } 821*26326Ssam iread(&save, addr, sizeof(save)); 822*26326Ssam newsave = new(Savelist); 823*26326Ssam newsave->location = addr; 824*26326Ssam newsave->save = save; 825*26326Ssam newsave->refcount = 1; 826*26326Ssam newsave->link = savelist; 827*26326Ssam savelist = newsave; 828*26326Ssam w = BP_OP; 829*26326Ssam iwrite(&w, addr, sizeof(w)); 830*26326Ssam } 831*26326Ssam 832*26326Ssam /* 833*26326Ssam * Unset a breakpoint; unfortunately we have to search the SAVELIST 834*26326Ssam * to find the saved value. The assumption is that the SAVELIST will 835*26326Ssam * usually be quite small. 836*26326Ssam */ 837*26326Ssam public unsetbp(addr) 838*26326Ssam Address addr; 839*26326Ssam { 840*26326Ssam register Savelist s, prev; 841*26326Ssam 842*26326Ssam prev = nil; 843*26326Ssam for (s = savelist; s != nil; s = s->link) { 844*26326Ssam if (s->location == addr) { 845*26326Ssam iwrite(&s->save, addr, sizeof(s->save)); 846*26326Ssam s->refcount--; 847*26326Ssam if (s->refcount == 0) { 848*26326Ssam if (prev == nil) 849*26326Ssam savelist = s->link; 850*26326Ssam else 851*26326Ssam prev->link = s->link; 852*26326Ssam dispose(s); 853*26326Ssam } 854*26326Ssam return; 855*26326Ssam } 856*26326Ssam prev = s; 857*26326Ssam } 858*26326Ssam panic("unsetbp: couldn't find address %d", addr); 859*26326Ssam } 860*26326Ssam 861*26326Ssam /* 862*26326Ssam * Enter a procedure by creating and executing a call instruction. 863*26326Ssam */ 864*26326Ssam 865*26326Ssam #define CALLSIZE 7 /* size of call instruction */ 866*26326Ssam 867*26326Ssam public beginproc(p, argc) 868*26326Ssam Symbol p; 869*26326Ssam Integer argc; 870*26326Ssam { 871*26326Ssam char save[CALLSIZE]; 872*26326Ssam struct { 873*26326Ssam Opcode op; 874*26326Ssam unsigned char numargs; 875*26326Ssam unsigned char mode; 876*26326Ssam char addr[sizeof(long)]; /* unaligned long */ 877*26326Ssam } call; 878*26326Ssam long dest; 879*26326Ssam 880*26326Ssam error("Can't do a \"call\" right now...sorry"); /* XXX */ 881*26326Ssam if (4*argc+4 > 256) 882*26326Ssam error("too many parameters (max %d)", 256/4 - 1); 883*26326Ssam pc = 2; 884*26326Ssam iread(save, pc, sizeof(save)); 885*26326Ssam call.op = O_CALLF; 886*26326Ssam call.numargs = 4*argc+4; 887*26326Ssam call.mode = 0xef; /* longword relative */ 888*26326Ssam dest = codeloc(p) - 2 - (pc + CALLSIZE); 889*26326Ssam mov(&dest, call.addr, sizeof(call.addr)); 890*26326Ssam iwrite(&call, pc, sizeof(call)); 891*26326Ssam setreg(PROGCTR, pc); 892*26326Ssam pstep(process, DEFSIG); 893*26326Ssam iwrite(save, pc, sizeof(save)); 894*26326Ssam pc = reg(PROGCTR); 895*26326Ssam if (not isbperr()) 896*26326Ssam printstatus(); 897*26326Ssam } 898