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