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