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