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