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