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