1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)process.c 1.12 08/19/83"; 4 5 /* 6 * Process management. 7 * 8 * This module contains the routines to manage the execution and 9 * tracing of the debuggee process. 10 */ 11 12 #include "defs.h" 13 #include "process.h" 14 #include "machine.h" 15 #include "events.h" 16 #include "tree.h" 17 #include "eval.h" 18 #include "operators.h" 19 #include "source.h" 20 #include "object.h" 21 #include "mappings.h" 22 #include "main.h" 23 #include "coredump.h" 24 #include <signal.h> 25 #include <errno.h> 26 #include <sys/param.h> 27 #include <machine/reg.h> 28 #include <sys/stat.h> 29 30 #ifndef public 31 32 typedef struct Process *Process; 33 34 Process process; 35 36 #define DEFSIG -1 37 38 #include "machine.h" 39 40 #endif 41 42 #define NOTSTARTED 1 43 #define STOPPED 0177 44 #define FINISHED 0 45 46 /* 47 * Cache-ing of instruction segment is done to reduce the number 48 * of system calls. 49 */ 50 51 #define CSIZE 1003 /* size of instruction cache */ 52 53 typedef struct { 54 Word addr; 55 Word val; 56 } CacheWord; 57 58 /* 59 * This structure holds the information we need from the user structure. 60 */ 61 62 struct Process { 63 int pid; /* process being traced */ 64 int mask; /* process status word */ 65 Word reg[NREG]; /* process' registers */ 66 Word oreg[NREG]; /* registers when process last stopped */ 67 short status; /* either STOPPED or FINISHED */ 68 short signo; /* signal that stopped process */ 69 int exitval; /* return value from exit() */ 70 long sigset; /* bit array of traced signals */ 71 CacheWord word[CSIZE]; /* text segment cache */ 72 Ttyinfo ttyinfo; /* process' terminal characteristics */ 73 }; 74 75 /* 76 * These definitions are for the arguments to "pio". 77 */ 78 79 typedef enum { PREAD, PWRITE } PioOp; 80 typedef enum { TEXTSEG, DATASEG } PioSeg; 81 82 private struct Process pbuf; 83 84 #define MAXNCMDARGS 100 /* maximum number of arguments to RUN */ 85 86 extern int errno; 87 88 private Boolean just_started; 89 private int argc; 90 private String argv[MAXNCMDARGS]; 91 private String infile, outfile; 92 93 /* 94 * Initialize process information. 95 */ 96 97 public process_init() 98 { 99 register Integer i; 100 Char buf[10]; 101 102 process = &pbuf; 103 process->status = (coredump) ? STOPPED : NOTSTARTED; 104 setsigtrace(); 105 for (i = 0; i < NREG; i++) { 106 sprintf(buf, "$r%d", i); 107 defregname(identname(buf, false), i); 108 } 109 defregname(identname("$ap", true), ARGP); 110 defregname(identname("$fp", true), FRP); 111 defregname(identname("$sp", true), STKP); 112 defregname(identname("$pc", true), PROGCTR); 113 if (coredump) { 114 coredump_readin(process->mask, process->reg, process->signo); 115 pc = process->reg[PROGCTR]; 116 getsrcpos(); 117 } 118 arginit(); 119 } 120 121 /* 122 * Routines to get at process information from outside this module. 123 */ 124 125 public Word reg(n) 126 Integer n; 127 { 128 register Word w; 129 130 if (n == NREG) { 131 w = process->mask; 132 } else { 133 w = process->reg[n]; 134 } 135 return w; 136 } 137 138 public setreg(n, w) 139 Integer n; 140 Word w; 141 { 142 process->reg[n] = w; 143 } 144 145 /* 146 * Begin execution. 147 * 148 * We set a breakpoint at the end of the code so that the 149 * process data doesn't disappear after the program terminates. 150 */ 151 152 private Boolean remade(); 153 154 public start(argv, infile, outfile) 155 String argv[]; 156 String infile, outfile; 157 { 158 String pargv[4]; 159 Node cond; 160 161 if (coredump) { 162 coredump = false; 163 fclose(corefile); 164 coredump_close(); 165 } 166 if (argv == nil) { 167 argv = pargv; 168 pargv[0] = objname; 169 pargv[1] = nil; 170 } else { 171 argv[argc] = nil; 172 } 173 if (remade(objname)) { 174 reinit(argv, infile, outfile); 175 } 176 pstart(process, argv, infile, outfile); 177 if (process->status == STOPPED) { 178 pc = 0; 179 curfunc = program; 180 if (objsize != 0) { 181 cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 182 event_once(cond, buildcmdlist(build(O_ENDX))); 183 } 184 } 185 } 186 187 /* 188 * Check to see if the object file has changed since the symbolic 189 * information last was read. 190 */ 191 192 private time_t modtime; 193 194 private Boolean remade(filename) 195 String filename; 196 { 197 struct stat s; 198 Boolean b; 199 200 stat(filename, &s); 201 b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 202 modtime = s.st_mtime; 203 return b; 204 } 205 206 /* 207 * Set up what signals we want to trace. 208 */ 209 210 private setsigtrace() 211 { 212 register Integer i; 213 register Process p; 214 215 p = process; 216 for (i = 1; i <= NSIG; i++) { 217 psigtrace(p, i, true); 218 } 219 psigtrace(p, SIGHUP, false); 220 psigtrace(p, SIGKILL, false); 221 psigtrace(p, SIGALRM, false); 222 psigtrace(p, SIGTSTP, false); 223 psigtrace(p, SIGCONT, false); 224 psigtrace(p, SIGCHLD, false); 225 } 226 227 /* 228 * Initialize the argument list. 229 */ 230 231 public arginit() 232 { 233 infile = nil; 234 outfile = nil; 235 argv[0] = objname; 236 argc = 1; 237 } 238 239 /* 240 * Add an argument to the list for the debuggee. 241 */ 242 243 public newarg(arg) 244 String arg; 245 { 246 if (argc >= MAXNCMDARGS) { 247 error("too many arguments"); 248 } 249 argv[argc++] = arg; 250 } 251 252 /* 253 * Set the standard input for the debuggee. 254 */ 255 256 public inarg(filename) 257 String filename; 258 { 259 if (infile != nil) { 260 error("multiple input redirects"); 261 } 262 infile = filename; 263 } 264 265 /* 266 * Set the standard output for the debuggee. 267 * Probably should check to avoid overwriting an existing file. 268 */ 269 270 public outarg(filename) 271 String filename; 272 { 273 if (outfile != nil) { 274 error("multiple output redirect"); 275 } 276 outfile = filename; 277 } 278 279 /* 280 * Start debuggee executing. 281 */ 282 283 public run() 284 { 285 process->status = STOPPED; 286 fixbps(); 287 curline = 0; 288 start(argv, infile, outfile); 289 just_started = true; 290 isstopped = false; 291 cont(0); 292 } 293 294 /* 295 * Continue execution wherever we left off. 296 * 297 * Note that this routine never returns. Eventually bpact() will fail 298 * and we'll call printstatus or step will call it. 299 */ 300 301 typedef int Intfunc(); 302 303 private Intfunc *dbintr; 304 private intr(); 305 306 #define succeeds == true 307 #define fails == false 308 309 public cont(signo) 310 int signo; 311 { 312 dbintr = signal(SIGINT, intr); 313 if (just_started) { 314 just_started = false; 315 } else { 316 if (not isstopped) { 317 error("can't continue execution"); 318 } 319 isstopped = false; 320 stepover(); 321 } 322 for (;;) { 323 if (single_stepping) { 324 printnews(); 325 } else { 326 setallbps(); 327 resume(signo); 328 unsetallbps(); 329 if (bpact() fails) { 330 printstatus(); 331 } 332 } 333 stepover(); 334 } 335 /* NOTREACHED */ 336 } 337 338 /* 339 * This routine is called if we get an interrupt while "running" px 340 * but actually in the debugger. Could happen, for example, while 341 * processing breakpoints. 342 * 343 * We basically just want to keep going; the assumption is 344 * that when the process resumes it will get the interrupt 345 * which will then be handled. 346 */ 347 348 private intr() 349 { 350 signal(SIGINT, intr); 351 } 352 353 public fixintr() 354 { 355 signal(SIGINT, dbintr); 356 } 357 358 /* 359 * Resume execution. 360 */ 361 362 public resume(signo) 363 int signo; 364 { 365 register Process p; 366 367 p = process; 368 if (traceexec) { 369 printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]); 370 fflush(stdout); 371 } 372 pcont(p, signo); 373 pc = process->reg[PROGCTR]; 374 if (traceexec) { 375 printf("execution stops at pc 0x%x on sig %d\n", 376 process->reg[PROGCTR], p->signo); 377 fflush(stdout); 378 } 379 if (p->status != STOPPED) { 380 if (p->signo != 0) { 381 error("program terminated by signal %d", p->signo); 382 } else if (not runfirst) { 383 error("program unexpectedly exited with %d", p->exitval); 384 } 385 } 386 } 387 388 /* 389 * Continue execution up to the next source line. 390 * 391 * There are two ways to define the next source line depending on what 392 * is desired when a procedure or function call is encountered. Step 393 * stops at the beginning of the procedure or call; next skips over it. 394 */ 395 396 /* 397 * Stepc is what is called when the step command is given. 398 * It has to play with the "isstopped" information. 399 */ 400 401 public stepc() 402 { 403 if (not isstopped) { 404 error("can't continue execution"); 405 } 406 isstopped = false; 407 dostep(false); 408 isstopped = true; 409 } 410 411 public next() 412 { 413 if (not isstopped) { 414 error("can't continue execution"); 415 } 416 isstopped = false; 417 dostep(true); 418 isstopped = true; 419 } 420 421 /* 422 * Single-step over the current machine instruction. 423 * 424 * If we're single-stepping by source line we want to step to the 425 * next source line. Otherwise we're going to continue so there's 426 * no reason to do all the work necessary to single-step to the next 427 * source line. 428 */ 429 430 private stepover() 431 { 432 Boolean b; 433 434 if (single_stepping) { 435 dostep(false); 436 } else { 437 b = inst_tracing; 438 inst_tracing = true; 439 dostep(false); 440 inst_tracing = b; 441 } 442 } 443 444 /* 445 * Resume execution up to the given address. It is assumed that 446 * no breakpoints exist between the current address and the one 447 * we're stepping to. This saves us from setting all the breakpoints. 448 */ 449 450 public stepto(addr) 451 Address addr; 452 { 453 setbp(addr); 454 resume(DEFSIG); 455 unsetbp(addr); 456 if (not isbperr()) { 457 printstatus(); 458 } 459 } 460 461 /* 462 * Print the status of the process. 463 * This routine does not return. 464 */ 465 466 public printstatus() 467 { 468 int status; 469 470 if (process->status == FINISHED) { 471 exit(0); 472 } else { 473 curfunc = whatblock(pc); 474 getsrcpos(); 475 if (process->signo == SIGINT) { 476 isstopped = true; 477 printerror(); 478 } else if (isbperr() and isstopped) { 479 printf("stopped "); 480 printloc(); 481 putchar('\n'); 482 if (curline > 0) { 483 printlines(curline, curline); 484 } else { 485 printinst(pc, pc); 486 } 487 erecover(); 488 } else { 489 fixbps(); 490 fixintr(); 491 isstopped = true; 492 printerror(); 493 } 494 } 495 } 496 497 /* 498 * Print out the current location in the debuggee. 499 */ 500 501 public printloc() 502 { 503 printf("in "); 504 printname(stdout, curfunc); 505 putchar(' '); 506 if (curline > 0 and not useInstLoc) { 507 printsrcpos(); 508 } else { 509 useInstLoc = false; 510 curline = 0; 511 printf("at 0x%x", pc); 512 } 513 } 514 515 /* 516 * Some functions for testing the state of the process. 517 */ 518 519 public Boolean notstarted(p) 520 Process p; 521 { 522 return (Boolean) (p->status == NOTSTARTED); 523 } 524 525 public Boolean isfinished(p) 526 Process p; 527 { 528 return (Boolean) (p->status == FINISHED); 529 } 530 531 /* 532 * Return the signal number which stopped the process. 533 */ 534 535 public Integer errnum(p) 536 Process p; 537 { 538 return p->signo; 539 } 540 541 /* 542 * Return the termination code of the process. 543 */ 544 545 public Integer exitcode(p) 546 Process p; 547 { 548 return p->exitval; 549 } 550 551 /* 552 * These routines are used to access the debuggee process from 553 * outside this module. 554 * 555 * They invoke "pio" which eventually leads to a call to "ptrace". 556 * The system generates an I/O error when a ptrace fails. During reads 557 * these are ignored, during writes they are reported as an error, and 558 * for anything else they cause a fatal error. 559 */ 560 561 extern Intfunc *onsyserr(); 562 563 private badaddr; 564 private read_err(), write_err(); 565 566 /* 567 * Read from the process' instruction area. 568 */ 569 570 public iread(buff, addr, nbytes) 571 char *buff; 572 Address addr; 573 int nbytes; 574 { 575 Intfunc *f; 576 577 f = onsyserr(EIO, read_err); 578 badaddr = addr; 579 if (coredump) { 580 coredump_readtext(buff, addr, nbytes); 581 } else { 582 pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 583 } 584 onsyserr(EIO, f); 585 } 586 587 /* 588 * Write to the process' instruction area, usually in order to set 589 * or unset a breakpoint. 590 */ 591 592 public iwrite(buff, addr, nbytes) 593 char *buff; 594 Address addr; 595 int nbytes; 596 { 597 Intfunc *f; 598 599 if (coredump) { 600 error("no process to write to"); 601 } 602 f = onsyserr(EIO, write_err); 603 badaddr = addr; 604 pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 605 onsyserr(EIO, f); 606 } 607 608 /* 609 * Read for the process' data area. 610 */ 611 612 public dread(buff, addr, nbytes) 613 char *buff; 614 Address addr; 615 int nbytes; 616 { 617 Intfunc *f; 618 619 f = onsyserr(EIO, read_err); 620 badaddr = addr; 621 if (coredump) { 622 coredump_readdata(buff, addr, nbytes); 623 } else { 624 pio(process, PREAD, DATASEG, buff, addr, nbytes); 625 } 626 onsyserr(EIO, f); 627 } 628 629 /* 630 * Write to the process' data area. 631 */ 632 633 public dwrite(buff, addr, nbytes) 634 char *buff; 635 Address addr; 636 int nbytes; 637 { 638 Intfunc *f; 639 640 if (coredump) { 641 error("no process to write to"); 642 } 643 f = onsyserr(EIO, write_err); 644 badaddr = addr; 645 pio(process, PWRITE, DATASEG, buff, addr, nbytes); 646 onsyserr(EIO, f); 647 } 648 649 /* 650 * Trap for errors in reading or writing to a process. 651 * The current approach is to "ignore" read errors and complain 652 * bitterly about write errors. 653 */ 654 655 private read_err() 656 { 657 /* 658 * Ignore. 659 */ 660 } 661 662 private write_err() 663 { 664 error("can't write to process (address 0x%x)", badaddr); 665 } 666 667 /* 668 * Ptrace interface. 669 */ 670 671 /* 672 * This magic macro enables us to look at the process' registers 673 * in its user structure. 674 */ 675 676 #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 677 678 #define WMASK (~(sizeof(Word) - 1)) 679 #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 680 681 #define FIRSTSIG SIGINT 682 #define LASTSIG SIGQUIT 683 #define ischild(pid) ((pid) == 0) 684 #define traceme() ptrace(0, 0, 0, 0) 685 #define setrep(n) (1 << ((n)-1)) 686 #define istraced(p) (p->sigset&setrep(p->signo)) 687 688 /* 689 * Ptrace options (specified in first argument). 690 */ 691 692 #define UREAD 3 /* read from process's user structure */ 693 #define UWRITE 6 /* write to process's user structure */ 694 #define IREAD 1 /* read from process's instruction space */ 695 #define IWRITE 4 /* write to process's instruction space */ 696 #define DREAD 2 /* read from process's data space */ 697 #define DWRITE 5 /* write to process's data space */ 698 #define CONT 7 /* continue stopped process */ 699 #define SSTEP 9 /* continue for approximately one instruction */ 700 #define PKILL 8 /* terminate the process */ 701 702 /* 703 * Start up a new process by forking and exec-ing the 704 * given argument list, returning when the process is loaded 705 * and ready to execute. The PROCESS information (pointed to 706 * by the first argument) is appropriately filled. 707 * 708 * If the given PROCESS structure is associated with an already running 709 * process, we terminate it. 710 */ 711 712 /* VARARGS2 */ 713 private pstart(p, argv, infile, outfile) 714 Process p; 715 String argv[]; 716 String infile; 717 String outfile; 718 { 719 int status; 720 Fileid in, out; 721 722 if (p->pid != 0) { /* child already running? */ 723 ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 724 pwait(p->pid, &status); /* wait for it to exit */ 725 unptraced(p->pid); 726 } 727 psigtrace(p, SIGTRAP, true); 728 p->pid = vfork(); 729 if (p->pid == -1) { 730 panic("can't fork"); 731 } 732 if (ischild(p->pid)) { 733 traceme(); 734 if (infile != nil) { 735 in = open(infile, 0); 736 if (in == -1) { 737 write(2, "can't read ", 11); 738 write(2, infile, strlen(infile)); 739 write(2, "\n", 1); 740 _exit(1); 741 } 742 fswap(0, in); 743 } 744 if (outfile != nil) { 745 out = creat(outfile, 0666); 746 if (out == -1) { 747 write(2, "can't write ", 12); 748 write(2, outfile, strlen(outfile)); 749 write(2, "\n", 1); 750 _exit(1); 751 } 752 fswap(1, out); 753 } 754 execv(argv[0], argv); 755 write(2, "can't exec ", 11); 756 write(2, argv[0], strlen(argv[0])); 757 write(2, "\n", 1); 758 _exit(1); 759 } 760 pwait(p->pid, &status); 761 getinfo(p, status); 762 if (p->status != STOPPED) { 763 error("program could not begin execution"); 764 } 765 ptraced(p->pid); 766 } 767 768 /* 769 * Continue a stopped process. The first argument points to a Process 770 * structure. Before the process is restarted it's user area is modified 771 * according to the values in the structure. When this routine finishes, 772 * the structure has the new values from the process's user area. 773 * 774 * Pcont terminates when the process stops with a signal pending that 775 * is being traced (via psigtrace), or when the process terminates. 776 */ 777 778 private pcont(p, signo) 779 Process p; 780 int signo; 781 { 782 int status; 783 784 if (p->pid == 0) { 785 error("program not active"); 786 } 787 do { 788 setinfo(p, signo); 789 sigs_off(); 790 if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 791 panic("error %d trying to continue process", errno); 792 } 793 pwait(p->pid, &status); 794 sigs_on(); 795 getinfo(p, status); 796 } while (p->status == STOPPED and not istraced(p)); 797 } 798 799 /* 800 * Single step as best ptrace can. 801 */ 802 803 public pstep(p) 804 Process p; 805 { 806 int status; 807 808 setinfo(p, DEFSIG); 809 sigs_off(); 810 ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 811 pwait(p->pid, &status); 812 sigs_on(); 813 getinfo(p, status); 814 } 815 816 /* 817 * Return from execution when the given signal is pending. 818 */ 819 820 public psigtrace(p, sig, sw) 821 Process p; 822 int sig; 823 Boolean sw; 824 { 825 if (sw) { 826 p->sigset |= setrep(sig); 827 } else { 828 p->sigset &= ~setrep(sig); 829 } 830 } 831 832 /* 833 * Don't catch any signals. 834 * Particularly useful when letting a process finish uninhibited. 835 */ 836 837 public unsetsigtraces(p) 838 Process p; 839 { 840 p->sigset = 0; 841 } 842 843 /* 844 * Turn off attention to signals not being caught. 845 */ 846 847 private Intfunc *sigfunc[NSIG]; 848 849 private sigs_off() 850 { 851 register int i; 852 853 for (i = FIRSTSIG; i < LASTSIG; i++) { 854 if (i != SIGKILL) { 855 sigfunc[i] = signal(i, SIG_IGN); 856 } 857 } 858 } 859 860 /* 861 * Turn back on attention to signals. 862 */ 863 864 private sigs_on() 865 { 866 register int i; 867 868 for (i = FIRSTSIG; i < LASTSIG; i++) { 869 if (i != SIGKILL) { 870 signal(i, sigfunc[i]); 871 } 872 } 873 } 874 875 /* 876 * Get process information from user area. 877 */ 878 879 private int rloc[] ={ 880 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 881 }; 882 883 private getinfo(p, status) 884 register Process p; 885 register int status; 886 { 887 register int i; 888 889 p->signo = (status&0177); 890 p->exitval = ((status >> 8)&0377); 891 if (p->signo != STOPPED) { 892 p->status = FINISHED; 893 p->pid = 0; 894 } else { 895 p->status = p->signo; 896 p->signo = p->exitval; 897 p->exitval = 0; 898 p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 899 for (i = 0; i < NREG; i++) { 900 p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 901 p->oreg[i] = p->reg[i]; 902 } 903 savetty(stdout, &(p->ttyinfo)); 904 } 905 } 906 907 /* 908 * Set process's user area information from given process structure. 909 */ 910 911 private setinfo(p, signo) 912 register Process p; 913 int signo; 914 { 915 register int i; 916 register int r; 917 918 if (signo == DEFSIG) { 919 if (istraced(p)) { 920 p->signo = 0; 921 } 922 } else { 923 p->signo = signo; 924 } 925 for (i = 0; i < NREG; i++) { 926 if ((r = p->reg[i]) != p->oreg[i]) { 927 ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 928 } 929 } 930 restoretty(stdout, &(p->ttyinfo)); 931 } 932 933 /* 934 * Structure for reading and writing by words, but dealing with bytes. 935 */ 936 937 typedef union { 938 Word pword; 939 Byte pbyte[sizeof(Word)]; 940 } Pword; 941 942 /* 943 * Read (write) from (to) the process' address space. 944 * We must deal with ptrace's inability to look anywhere other 945 * than at a word boundary. 946 */ 947 948 private Word fetch(); 949 private store(); 950 951 private pio(p, op, seg, buff, addr, nbytes) 952 Process p; 953 PioOp op; 954 PioSeg seg; 955 char *buff; 956 Address addr; 957 int nbytes; 958 { 959 register int i; 960 register Address newaddr; 961 register char *cp; 962 char *bufend; 963 Pword w; 964 Address wordaddr; 965 int byteoff; 966 967 if (p->status != STOPPED) { 968 error("program is not active"); 969 } 970 cp = buff; 971 newaddr = addr; 972 wordaddr = (newaddr&WMASK); 973 if (wordaddr != newaddr) { 974 w.pword = fetch(p, seg, wordaddr); 975 for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 976 if (op == PREAD) { 977 *cp++ = w.pbyte[i]; 978 } else { 979 w.pbyte[i] = *cp++; 980 } 981 nbytes--; 982 } 983 if (op == PWRITE) { 984 store(p, seg, wordaddr, w.pword); 985 } 986 newaddr = wordaddr + sizeof(Word); 987 } 988 byteoff = (nbytes&(~WMASK)); 989 nbytes -= byteoff; 990 bufend = cp + nbytes; 991 while (cp < bufend) { 992 if (op == PREAD) { 993 *((Word *) cp) = fetch(p, seg, newaddr); 994 } else { 995 store(p, seg, newaddr, *((Word *) cp)); 996 } 997 cp += sizeof(Word); 998 newaddr += sizeof(Word); 999 } 1000 if (byteoff > 0) { 1001 w.pword = fetch(p, seg, newaddr); 1002 for (i = 0; i < byteoff; i++) { 1003 if (op == PREAD) { 1004 *cp++ = w.pbyte[i]; 1005 } else { 1006 w.pbyte[i] = *cp++; 1007 } 1008 } 1009 if (op == PWRITE) { 1010 store(p, seg, newaddr, w.pword); 1011 } 1012 } 1013 } 1014 1015 /* 1016 * Get a word from a process at the given address. 1017 * The address is assumed to be on a word boundary. 1018 * 1019 * A simple cache scheme is used to avoid redundant ptrace calls 1020 * to the instruction space since it is assumed to be pure. 1021 * 1022 * It is necessary to use a write-through scheme so that 1023 * breakpoints right next to each other don't interfere. 1024 */ 1025 1026 private Integer nfetchs, nreads, nwrites; 1027 1028 private Word fetch(p, seg, addr) 1029 Process p; 1030 PioSeg seg; 1031 register int addr; 1032 { 1033 register CacheWord *wp; 1034 register Word w; 1035 1036 switch (seg) { 1037 case TEXTSEG: 1038 ++nfetchs; 1039 wp = &p->word[cachehash(addr)]; 1040 if (addr == 0 or wp->addr != addr) { 1041 ++nreads; 1042 w = ptrace(IREAD, p->pid, addr, 0); 1043 wp->addr = addr; 1044 wp->val = w; 1045 } else { 1046 w = wp->val; 1047 } 1048 break; 1049 1050 case DATASEG: 1051 w = ptrace(DREAD, p->pid, addr, 0); 1052 break; 1053 1054 default: 1055 panic("fetch: bad seg %d", seg); 1056 /* NOTREACHED */ 1057 } 1058 return w; 1059 } 1060 1061 /* 1062 * Put a word into the process' address space at the given address. 1063 * The address is assumed to be on a word boundary. 1064 */ 1065 1066 private store(p, seg, addr, data) 1067 Process p; 1068 PioSeg seg; 1069 int addr; 1070 Word data; 1071 { 1072 register CacheWord *wp; 1073 1074 switch (seg) { 1075 case TEXTSEG: 1076 ++nwrites; 1077 wp = &p->word[cachehash(addr)]; 1078 wp->addr = addr; 1079 wp->val = data; 1080 ptrace(IWRITE, p->pid, addr, data); 1081 break; 1082 1083 case DATASEG: 1084 ptrace(DWRITE, p->pid, addr, data); 1085 break; 1086 1087 default: 1088 panic("store: bad seg %d", seg); 1089 /* NOTREACHED */ 1090 } 1091 } 1092 1093 public printptraceinfo() 1094 { 1095 printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 1096 } 1097 1098 /* 1099 * Swap file numbers so as to redirect standard input and output. 1100 */ 1101 1102 private fswap(oldfd, newfd) 1103 int oldfd; 1104 int newfd; 1105 { 1106 if (oldfd != newfd) { 1107 close(oldfd); 1108 dup(newfd); 1109 close(newfd); 1110 } 1111 } 1112