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