1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)vax.c 1.3 12/15/82"; 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 264 switch (nbytes) { 265 case 1: 266 iread(&byte, addr, sizeof(byte)); 267 argval = byte; 268 break; 269 270 case 2: 271 iread(&hword, addr, sizeof(hword)); 272 argval = hword; 273 break; 274 275 case 4: 276 iread(&argval, addr, sizeof(argval)); 277 break; 278 } 279 if (reg == regname[PROGCTR] && mode >= BYTEDISP) { 280 argval += addr + nbytes; 281 } 282 if (reg == regname[PROGCTR]) { 283 printf("%x", argval); 284 } else { 285 printf("%d(%s)", argval, reg); 286 } 287 return argval; 288 } 289 290 /* 291 * Print the contents of the addresses within the given range 292 * according to the given format. 293 */ 294 295 typedef struct { 296 String name; 297 String printfstring; 298 int length; 299 } Format; 300 301 private Format fmt[] = { 302 { "d", " %d", sizeof(short) }, 303 { "D", " %ld", sizeof(long) }, 304 { "o", " %o", sizeof(short) }, 305 { "O", " %lo", sizeof(long) }, 306 { "x", " %04x", sizeof(short) }, 307 { "X", " %08x", sizeof(long) }, 308 { "b", " \\%o", sizeof(char) }, 309 { "c", " '%c'", sizeof(char) }, 310 { "s", "%c", sizeof(char) }, 311 { "f", " %f", sizeof(double) }, 312 { "g", " %g", sizeof(double) }, 313 { nil, nil, 0 } 314 }; 315 316 public Address printdata(lowaddr, highaddr, format) 317 Address lowaddr; 318 Address highaddr; 319 String format; 320 { 321 register int n; 322 register Address addr; 323 register Format *f; 324 int value; 325 326 if (lowaddr > highaddr) { 327 error("first address larger than second"); 328 } 329 f = &fmt[0]; 330 while (f->name != nil and not streq(f->name, format)) { 331 ++f; 332 } 333 if (f->name == nil) { 334 error("bad print format \"%s\"", format); 335 } 336 n = 0; 337 value = 0; 338 for (addr = lowaddr; addr <= highaddr; addr += f->length) { 339 if (n == 0) { 340 printf("%08x: ", addr); 341 } 342 dread(&value, addr, f->length); 343 printf(f->printfstring, value); 344 ++n; 345 if (n >= (16 div f->length)) { 346 putchar('\n'); 347 n = 0; 348 } 349 } 350 if (n != 0) { 351 putchar('\n'); 352 } 353 prtaddr = addr; 354 return addr; 355 } 356 357 /* 358 * The other approach is to print n items starting with a given address. 359 */ 360 361 public printndata(count, startaddr, format) 362 int count; 363 Address startaddr; 364 String format; 365 { 366 register int i, n; 367 register Address addr; 368 register Format *f; 369 register Boolean isstring; 370 int value; 371 372 if (count <= 0) { 373 error("non-positive repetition count"); 374 } 375 f = &fmt[0]; 376 while (f->name != nil and not streq(f->name, format)) { 377 ++f; 378 } 379 if (f->name == nil) { 380 error("bad print format \"%s\"", format); 381 } 382 isstring = (Boolean) streq(f->name, "s"); 383 n = 0; 384 addr = startaddr; 385 value = 0; 386 for (i = 0; i < count; i++) { 387 if (n == 0) { 388 printf("%08x: ", addr); 389 } 390 if (isstring) { 391 putchar('"'); 392 dread(&value, addr, sizeof(char)); 393 while (value != '\0') { 394 printchar((char) value); 395 ++addr; 396 dread(&value, addr, sizeof(char)); 397 } 398 putchar('"'); 399 putchar('\n'); 400 n = 0; 401 addr += sizeof(String); 402 } else { 403 dread(&value, addr, f->length); 404 printf(f->printfstring, value); 405 ++n; 406 if (n >= (16 div f->length)) { 407 putchar('\n'); 408 n = 0; 409 } 410 addr += f->length; 411 } 412 } 413 if (n != 0) { 414 putchar('\n'); 415 } 416 prtaddr = addr; 417 } 418 419 /* 420 * Print out an execution time error. 421 * 422 * Have to check if the -r option was specified; if so then 423 * the object file information hasn't been read in yet. 424 */ 425 426 public printerror() 427 { 428 extern Integer sys_nsig; 429 extern String sys_siglist[]; 430 String filename; 431 Integer err; 432 433 if (isfinished(process)) { 434 printf("\"%s\" exits with code %d\n", objname, exitcode(process)); 435 erecover(); 436 } 437 if (runfirst) { 438 fprintf(stderr, "Entering debugger ..."); 439 init(); 440 fprintf(stderr, " type 'help' for help\n"); 441 } 442 curline = srcline(pc); 443 curfunc = whatblock(pc); 444 filename = srcfilename(pc); 445 setsource(filename); 446 err = errnum(process); 447 if (err == SIGINT) { 448 printf("\n\ninterrupt "); 449 printloc(); 450 } else if (err == SIGTRAP) { 451 printf("\nerror "); 452 printloc(); 453 } else { 454 if (err < 0 or err > sys_nsig) { 455 printf("\nsignal %d ", err); 456 } else { 457 printf("\n%s ", sys_siglist[err]); 458 } 459 printloc(); 460 } 461 putchar('\n'); 462 if (curline > 0) { 463 printlines(curline, curline); 464 } else { 465 printinst(pc, pc); 466 } 467 erecover(); 468 } 469 470 private printloc() 471 { 472 if (curline > 0) { 473 if (nlhdr.nfiles > 1) { 474 printf("at line %d in file %s", curline, cursource); 475 } else { 476 printf("at line %d", curline); 477 } 478 } else { 479 printf("in "); 480 printname(stdout, curfunc); 481 printf(" at 0x%x", pc); 482 } 483 } 484 485 /* 486 * Note the termination of the program. We do this so as to avoid 487 * having the process exit, which would make the values of variables 488 * inaccessible. We do want to flush all output buffers here, 489 * otherwise it'll never get done. 490 */ 491 492 public endprogram() 493 { 494 Integer exitcode; 495 496 stepto(nextaddr(pc, true)); 497 printnews(); 498 exitcode = argn(1, nil); 499 printf("\nexecution completed, exit code is %d\n", exitcode); 500 getsrcpos(); 501 erecover(); 502 } 503 504 /* 505 * Single step the machine a source line (or instruction if "inst_tracing" 506 * is true. If "isnext" is true, skip over procedure calls. 507 */ 508 509 private Address getcall(); 510 511 public dostep(isnext) 512 Boolean isnext; 513 { 514 register Address addr; 515 register Lineno line; 516 String filename; 517 518 addr = nextaddr(pc, isnext); 519 if (not inst_tracing) { 520 line = linelookup(addr); 521 while (line == 0) { 522 addr = nextaddr(addr, isnext); 523 line = linelookup(addr); 524 } 525 } 526 stepto(addr); 527 curline = line; 528 filename = srcfilename(addr); 529 setsource(filename); 530 } 531 532 /* 533 * Compute the next address that will be executed from the given one. 534 * If "isnext" is true then consider a procedure call as straight line code. 535 * 536 * We must unfortunately do much of the same work that is necessary 537 * to print instructions. In addition we have to deal with branches. 538 * Unconditional branches we just follow, for conditional branches 539 * we continue execution to the current location and then single step 540 * the machine. We assume that the last argument in an instruction 541 * that branches is the branch address (or relative offset). 542 */ 543 544 public Address nextaddr(startaddr, isnext) 545 Address startaddr; 546 Boolean isnext; 547 { 548 register Address addr; 549 Optab op; 550 VaxOpcode ins; 551 unsigned char mode; 552 int argtype, amode, argno, argval; 553 String r; 554 Boolean indexf; 555 enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus; 556 557 argval = 0; 558 indexf = false; 559 addr = startaddr; 560 iread(&ins, addr, sizeof(ins)); 561 switch (ins) { 562 case O_BRB: 563 case O_BRW: 564 case O_JMP: 565 addrstatus = BRANCH; 566 break; 567 568 case O_BSBB: 569 case O_BSBW: 570 case O_JSB: 571 case O_CALLG: 572 case O_CALLS: 573 if (isnext) { 574 addrstatus = SEQUENTIAL; 575 } else { 576 addrstatus = KNOWN; 577 stepto(addr); 578 pstep(process); 579 addr = reg(PROGCTR); 580 pc = addr; 581 callnews(/* iscall = */ true); 582 if (not isbperr()) { 583 printstatus(); 584 } else { 585 bpact(); 586 } 587 } 588 break; 589 590 case O_RSB: 591 case O_RET: 592 addrstatus = KNOWN; 593 callnews(/* iscall = */ false); 594 addr = return_addr(); 595 stepto(addr); 596 break; 597 598 case O_BNEQ: case O_BEQL: case O_BGTR: 599 case O_BLEQ: case O_BGEQ: case O_BLSS: 600 case O_BGTRU: case O_BLEQU: case O_BVC: 601 case O_BVS: case O_BCC: case O_BCS: 602 case O_CASEB: case O_CASEW: case O_CASEL: 603 case O_BBS: case O_BBC: case O_BBSS: case O_BBCS: 604 case O_BBSC: case O_BBCC: case O_BBSSI: 605 case O_BBCCI: case O_BLBS: case O_BLBC: 606 case O_ACBL: case O_AOBLSS: case O_AOBLEQ: 607 case O_SOBGEQ: case O_SOBGTR: 608 addrstatus = KNOWN; 609 stepto(addr); 610 pstep(process); 611 addr = reg(PROGCTR); 612 pc = addr; 613 if (not isbperr()) { 614 printstatus(); 615 } 616 break; 617 618 default: 619 addrstatus = SEQUENTIAL; 620 break; 621 } 622 if (addrstatus != KNOWN) { 623 addr += 1; 624 op = optab[ins]; 625 for (argno = 0; argno < op.numargs; argno++) { 626 if (indexf == true) { 627 indexf = false; 628 } 629 argtype = op.argtype[argno]; 630 if (is_branch_disp(argtype)) { 631 mode = 0xAF + (typelen(argtype) << 5); 632 } else { 633 iread(&mode, addr, sizeof(mode)); 634 addr += 1; 635 } 636 r = regname[regnm(mode)]; 637 amode = addrmode(mode); 638 switch (amode) { 639 case LITSHORT: 640 case LITUPTO31: 641 case LITUPTO47: 642 case LITUPTO63: 643 argval = mode; 644 break; 645 646 case INDEX: 647 indexf = true; 648 --argno; 649 break; 650 651 case REG: 652 case REGDEF: 653 case AUTODEC: 654 break; 655 656 case AUTOINC: 657 if (r == regname[PROGCTR]) { 658 switch (typelen(argtype)) { 659 case TYPB: 660 argval = getdisp(addr, 1, r, amode); 661 addr += 1; 662 break; 663 664 case TYPW: 665 argval = getdisp(addr, 2, r, amode); 666 addr += 2; 667 break; 668 669 case TYPL: 670 argval = getdisp(addr, 4, r, amode); 671 addr += 4; 672 break; 673 674 case TYPF: 675 iread(&argval, addr, sizeof(argval)); 676 addr += 4; 677 break; 678 679 case TYPQ: 680 case TYPD: 681 iread(&argval, addr+4, sizeof(argval)); 682 addr += 8; 683 break; 684 } 685 } 686 break; 687 688 case AUTOINCDEF: 689 if (r == regname[PROGCTR]) { 690 argval = getdisp(addr, 4, r, amode); 691 addr += 4; 692 } 693 break; 694 695 case BYTEDISP: 696 case BYTEDISPDEF: 697 argval = getdisp(addr, 1, r, amode); 698 addr += 1; 699 break; 700 701 case WORDDISP: 702 case WORDDISPDEF: 703 argval = getdisp(addr, 2, r, amode); 704 addr += 2; 705 break; 706 707 case LONGDISP: 708 case LONGDISPDEF: 709 argval = getdisp(addr, 4, r, amode); 710 addr += 4; 711 break; 712 } 713 } 714 if (ins == O_CALLS or ins == O_CALLG) { 715 argval += 2; 716 } 717 if (addrstatus == BRANCH) { 718 addr = argval; 719 } 720 } 721 return addr; 722 } 723 724 /* 725 * Get the displacement of an instruction that uses displacement addressing. 726 */ 727 728 private int getdisp(addr, nbytes, reg, mode) 729 Address addr; 730 int nbytes; 731 String reg; 732 int mode; 733 { 734 char byte; 735 short hword; 736 int argval; 737 738 switch (nbytes) { 739 case 1: 740 iread(&byte, addr, sizeof(byte)); 741 argval = byte; 742 break; 743 744 case 2: 745 iread(&hword, addr, sizeof(hword)); 746 argval = hword; 747 break; 748 749 case 4: 750 iread(&argval, addr, sizeof(argval)); 751 break; 752 } 753 if (reg == regname[PROGCTR] && mode >= BYTEDISP) { 754 argval += addr + nbytes; 755 } 756 return argval; 757 } 758 759 #define BP_OP O_BPT /* breakpoint trap */ 760 #define BP_ERRNO SIGTRAP /* signal received at a breakpoint */ 761 762 /* 763 * Setting a breakpoint at a location consists of saving 764 * the word at the location and poking a BP_OP there. 765 * 766 * We save the locations and words on a list for use in unsetting. 767 */ 768 769 typedef struct Savelist *Savelist; 770 771 struct Savelist { 772 Address location; 773 Byte save; 774 Byte refcount; 775 Savelist link; 776 }; 777 778 private Savelist savelist; 779 780 /* 781 * Set a breakpoint at the given address. Only save the word there 782 * if it's not already a breakpoint. 783 */ 784 785 public setbp(addr) 786 Address addr; 787 { 788 Byte w; 789 Byte save; 790 register Savelist newsave, s; 791 792 for (s = savelist; s != nil; s = s->link) { 793 if (s->location == addr) { 794 s->refcount++; 795 return; 796 } 797 } 798 iread(&save, addr, sizeof(addr)); 799 newsave = new(Savelist); 800 newsave->location = addr; 801 newsave->save = save; 802 newsave->refcount = 1; 803 newsave->link = savelist; 804 savelist = newsave; 805 w = BP_OP; 806 iwrite(&w, addr, sizeof(w)); 807 } 808 809 /* 810 * Unset a breakpoint; unfortunately we have to search the SAVELIST 811 * to find the saved value. The assumption is that the SAVELIST will 812 * usually be quite small. 813 */ 814 815 public unsetbp(addr) 816 Address addr; 817 { 818 register Savelist s, prev; 819 820 prev = nil; 821 for (s = savelist; s != nil; s = s->link) { 822 if (s->location == addr) { 823 iwrite(&s->save, addr, sizeof(s->save)); 824 s->refcount--; 825 if (s->refcount == 0) { 826 if (prev == nil) { 827 savelist = s->link; 828 } else { 829 prev->link = s->link; 830 } 831 dispose(s); 832 } 833 return; 834 } 835 prev = s; 836 } 837 panic("unsetbp: couldn't find address %d", addr); 838 } 839 840 /* 841 * Predicate to test if the reason the process stopped was because 842 * of a breakpoint. 843 */ 844 845 public Boolean isbperr() 846 { 847 return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP); 848 } 849 850 /* 851 * Enter a procedure by creating and executing a call instruction. 852 */ 853 854 #define CALLSIZE 7 /* size of call instruction */ 855 856 public beginproc(p, argc) 857 Symbol p; 858 Integer argc; 859 { 860 char save[CALLSIZE]; 861 struct { 862 VaxOpcode op; 863 unsigned char numargs; 864 unsigned char mode; 865 char addr[sizeof(long)]; /* unaligned long */ 866 } call; 867 long dest; 868 869 pc = 2; 870 iread(save, pc, sizeof(save)); 871 call.op = O_CALLS; 872 call.numargs = argc; 873 call.mode = 0xef; 874 dest = codeloc(p) - 2 - (pc + 7); 875 mov(&dest, call.addr, sizeof(call.addr)); 876 iwrite(&call, pc, sizeof(call)); 877 setreg(PROGCTR, pc); 878 pstep(process); 879 iwrite(save, pc, sizeof(save)); 880 pc = reg(PROGCTR); 881 if (not isbperr()) { 882 printstatus(); 883 } 884 } 885