1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)process.c 1.7 04/03/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() 302 { 303 dbintr = signal(SIGINT, intr); 304 if (just_started) { 305 just_started = false; 306 } else { 307 if (not isstopped) { 308 error("can't continue execution"); 309 } 310 isstopped = false; 311 step(); 312 } 313 for (;;) { 314 if (single_stepping) { 315 printnews(); 316 } else { 317 setallbps(); 318 resume(); 319 unsetallbps(); 320 if (bpact() fails) { 321 printstatus(); 322 } 323 } 324 step(); 325 } 326 /* NOTREACHED */ 327 } 328 329 /* 330 * This routine is called if we get an interrupt while "running" px 331 * but actually in the debugger. Could happen, for example, while 332 * processing breakpoints. 333 * 334 * We basically just want to keep going; the assumption is 335 * that when the process resumes it will get the interrupt 336 * which will then be handled. 337 */ 338 339 private intr() 340 { 341 signal(SIGINT, intr); 342 } 343 344 public fixintr() 345 { 346 signal(SIGINT, dbintr); 347 } 348 349 /* 350 * Resume execution. 351 */ 352 353 public resume() 354 { 355 register Process p; 356 357 p = process; 358 if (traceexec) { 359 printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]); 360 fflush(stdout); 361 } 362 pcont(p); 363 pc = process->reg[PROGCTR]; 364 if (traceexec) { 365 printf("execution stops at pc 0x%x on sig %d\n", 366 process->reg[PROGCTR], p->signo); 367 fflush(stdout); 368 } 369 if (p->status != STOPPED) { 370 error("program unexpectedly exited with %d", p->exitval); 371 } 372 } 373 374 /* 375 * Continue execution up to the next source line. 376 * 377 * There are two ways to define the next source line depending on what 378 * is desired when a procedure or function call is encountered. Step 379 * stops at the beginning of the procedure or call; next skips over it. 380 */ 381 382 /* 383 * Stepc is what is called when the step command is given. 384 * It has to play with the "isstopped" information. 385 */ 386 387 public stepc() 388 { 389 if (not isstopped) { 390 error("can't continue execution"); 391 } 392 isstopped = false; 393 dostep(false); 394 isstopped = true; 395 } 396 397 public next() 398 { 399 if (not isstopped) { 400 error("can't continue execution"); 401 } 402 isstopped = false; 403 dostep(true); 404 isstopped = true; 405 } 406 407 public step() 408 { 409 dostep(false); 410 } 411 412 /* 413 * Resume execution up to the given address. It is assumed that 414 * no breakpoints exist between the current address and the one 415 * we're stepping to. This saves us from setting all the breakpoints. 416 */ 417 418 public stepto(addr) 419 Address addr; 420 { 421 setbp(addr); 422 resume(); 423 unsetbp(addr); 424 if (not isbperr()) { 425 printstatus(); 426 } 427 } 428 429 /* 430 * Print the status of the process. 431 * This routine does not return. 432 */ 433 434 public printstatus() 435 { 436 if (process->status == FINISHED) { 437 exit(0); 438 } else { 439 curfunc = whatblock(pc); 440 getsrcpos(); 441 if (process->signo == SIGINT) { 442 isstopped = true; 443 printerror(); 444 } else if (isbperr() and isstopped) { 445 printf("stopped "); 446 printloc(); 447 putchar('\n'); 448 if (curline > 0) { 449 printlines(curline, curline); 450 } else { 451 printinst(pc, pc); 452 } 453 erecover(); 454 } else { 455 fixbps(); 456 fixintr(); 457 isstopped = true; 458 printerror(); 459 } 460 } 461 } 462 463 /* 464 * Print out the current location in the debuggee. 465 */ 466 467 public printloc() 468 { 469 printf("in "); 470 printname(stdout, curfunc); 471 putchar(' '); 472 if (curline > 0) { 473 printsrcpos(); 474 } else { 475 printf("at 0x%x", pc); 476 } 477 } 478 479 /* 480 * Some functions for testing the state of the process. 481 */ 482 483 public Boolean notstarted(p) 484 Process p; 485 { 486 return (Boolean) (p->status == NOTSTARTED); 487 } 488 489 public Boolean isfinished(p) 490 Process p; 491 { 492 return (Boolean) (p->status == FINISHED); 493 } 494 495 /* 496 * Return the signal number which stopped the process. 497 */ 498 499 public Integer errnum(p) 500 Process p; 501 { 502 return p->signo; 503 } 504 505 /* 506 * Return the termination code of the process. 507 */ 508 509 public Integer exitcode(p) 510 Process p; 511 { 512 return p->exitval; 513 } 514 515 /* 516 * These routines are used to access the debuggee process from 517 * outside this module. 518 * 519 * They invoke "pio" which eventually leads to a call to "ptrace". 520 * The system generates an I/O error when a ptrace fails, we assume 521 * during a read/write to the process that such an error is due to 522 * a misguided address and ignore it. 523 */ 524 525 extern Intfunc *onsyserr(); 526 527 private badaddr; 528 private rwerr(); 529 530 /* 531 * Read from the process' instruction area. 532 */ 533 534 public iread(buff, addr, nbytes) 535 char *buff; 536 Address addr; 537 int nbytes; 538 { 539 Intfunc *f; 540 541 f = onsyserr(EIO, rwerr); 542 badaddr = addr; 543 if (coredump) { 544 coredump_readtext(buff, addr, nbytes); 545 } else { 546 pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 547 } 548 onsyserr(EIO, f); 549 } 550 551 /* 552 * Write to the process' instruction area, usually in order to set 553 * or unset a breakpoint. 554 */ 555 556 public iwrite(buff, addr, nbytes) 557 char *buff; 558 Address addr; 559 int nbytes; 560 { 561 Intfunc *f; 562 563 if (coredump) { 564 error("no process to write to"); 565 } 566 f = onsyserr(EIO, rwerr); 567 badaddr = addr; 568 pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 569 onsyserr(EIO, f); 570 } 571 572 /* 573 * Read for the process' data area. 574 */ 575 576 public dread(buff, addr, nbytes) 577 char *buff; 578 Address addr; 579 int nbytes; 580 { 581 Intfunc *f; 582 583 f = onsyserr(EIO, rwerr); 584 badaddr = addr; 585 if (coredump) { 586 coredump_readdata(buff, addr, nbytes); 587 } else { 588 pio(process, PREAD, DATASEG, buff, addr, nbytes); 589 } 590 onsyserr(EIO, f); 591 } 592 593 /* 594 * Write to the process' data area. 595 */ 596 597 public dwrite(buff, addr, nbytes) 598 char *buff; 599 Address addr; 600 int nbytes; 601 { 602 Intfunc *f; 603 604 if (coredump) { 605 error("no process to write to"); 606 } 607 f = onsyserr(EIO, rwerr); 608 badaddr = addr; 609 pio(process, PWRITE, DATASEG, buff, addr, nbytes); 610 onsyserr(EIO, f); 611 } 612 613 /* 614 * Error handler. 615 */ 616 617 private rwerr() 618 { 619 /* 620 * Current response is to ignore the error and let the result 621 * (-1) ripple back up to the process. 622 * 623 error("bad read/write process address 0x%x", badaddr); 624 */ 625 } 626 627 /* 628 * Ptrace interface. 629 */ 630 631 /* 632 * This magic macro enables us to look at the process' registers 633 * in its user structure. Very gross. 634 */ 635 636 #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 637 638 #define WMASK (~(sizeof(Word) - 1)) 639 #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 640 641 #define FIRSTSIG SIGINT 642 #define LASTSIG SIGQUIT 643 #define ischild(pid) ((pid) == 0) 644 #define traceme() ptrace(0, 0, 0, 0) 645 #define setrep(n) (1 << ((n)-1)) 646 #define istraced(p) (p->sigset&setrep(p->signo)) 647 648 /* 649 * Ptrace options (specified in first argument). 650 */ 651 652 #define UREAD 3 /* read from process's user structure */ 653 #define UWRITE 6 /* write to process's user structure */ 654 #define IREAD 1 /* read from process's instruction space */ 655 #define IWRITE 4 /* write to process's instruction space */ 656 #define DREAD 2 /* read from process's data space */ 657 #define DWRITE 5 /* write to process's data space */ 658 #define CONT 7 /* continue stopped process */ 659 #define SSTEP 9 /* continue for approximately one instruction */ 660 #define PKILL 8 /* terminate the process */ 661 662 /* 663 * Start up a new process by forking and exec-ing the 664 * given argument list, returning when the process is loaded 665 * and ready to execute. The PROCESS information (pointed to 666 * by the first argument) is appropriately filled. 667 * 668 * If the given PROCESS structure is associated with an already running 669 * process, we terminate it. 670 */ 671 672 /* VARARGS2 */ 673 private pstart(p, argv, infile, outfile) 674 Process p; 675 String argv[]; 676 String infile; 677 String outfile; 678 { 679 int status; 680 681 if (p->pid != 0) { /* child already running? */ 682 ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 683 } 684 psigtrace(p, SIGTRAP, true); 685 if ((p->pid = vfork()) == -1) { 686 panic("can't fork"); 687 } 688 if (ischild(p->pid)) { 689 Fileid in, out; 690 691 traceme(); 692 if (infile != nil) { 693 in = open(infile, 0); 694 if (in == -1) { 695 write(2, "can't read ", 11); 696 write(2, infile, strlen(infile)); 697 write(2, "\n", 1); 698 _exit(1); 699 } 700 fswap(0, in); 701 } 702 if (outfile != nil) { 703 out = creat(outfile, 0666); 704 if (out == -1) { 705 write(2, "can't write ", 12); 706 write(2, outfile, strlen(outfile)); 707 write(2, "\n", 1); 708 _exit(1); 709 } 710 fswap(1, out); 711 } 712 execv(argv[0], argv); 713 write(2, "can't exec ", 11); 714 write(2, argv[0], strlen(argv[0])); 715 write(2, "\n", 1); 716 _exit(1); 717 } 718 pwait(p->pid, &status); 719 getinfo(p, status); 720 if (p->status != STOPPED) { 721 error("program could not begin execution"); 722 } 723 } 724 725 /* 726 * Continue a stopped process. The argument points to a PROCESS structure. 727 * Before the process is restarted it's user area is modified according to 728 * the values in the structure. When this routine finishes, 729 * the structure has the new values from the process's user area. 730 * 731 * Pcont terminates when the process stops with a signal pending that 732 * is being traced (via psigtrace), or when the process terminates. 733 */ 734 735 private pcont(p) 736 Process p; 737 { 738 int status; 739 740 if (p->pid == 0) { 741 error("program not active"); 742 } 743 do { 744 setinfo(p); 745 sigs_off(); 746 if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 747 panic("can't continue process"); 748 } 749 pwait(p->pid, &status); 750 sigs_on(); 751 getinfo(p, status); 752 } while (p->status == STOPPED and not istraced(p)); 753 } 754 755 /* 756 * Single step as best ptrace can. 757 */ 758 759 public pstep(p) 760 Process p; 761 { 762 int status; 763 764 setinfo(p); 765 sigs_off(); 766 ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 767 pwait(p->pid, &status); 768 sigs_on(); 769 getinfo(p, status); 770 } 771 772 /* 773 * Return from execution when the given signal is pending. 774 */ 775 776 public psigtrace(p, sig, sw) 777 Process p; 778 int sig; 779 Boolean sw; 780 { 781 if (sw) { 782 p->sigset |= setrep(sig); 783 } else { 784 p->sigset &= ~setrep(sig); 785 } 786 } 787 788 /* 789 * Don't catch any signals. 790 * Particularly useful when letting a process finish uninhibited. 791 */ 792 793 public unsetsigtraces(p) 794 Process p; 795 { 796 p->sigset = 0; 797 } 798 799 /* 800 * Turn off attention to signals not being caught. 801 */ 802 803 private Intfunc *sigfunc[NSIG]; 804 805 private sigs_off() 806 { 807 register int i; 808 809 for (i = FIRSTSIG; i < LASTSIG; i++) { 810 if (i != SIGKILL) { 811 sigfunc[i] = signal(i, SIG_IGN); 812 } 813 } 814 } 815 816 /* 817 * Turn back on attention to signals. 818 */ 819 820 private sigs_on() 821 { 822 register int i; 823 824 for (i = FIRSTSIG; i < LASTSIG; i++) { 825 if (i != SIGKILL) { 826 signal(i, sigfunc[i]); 827 } 828 } 829 } 830 831 /* 832 * Get process information from user area. 833 */ 834 835 private int rloc[] ={ 836 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 837 }; 838 839 private getinfo(p, status) 840 register Process p; 841 register int status; 842 { 843 register int i; 844 845 p->signo = (status&0177); 846 p->exitval = ((status >> 8)&0377); 847 if (p->signo != STOPPED) { 848 p->status = FINISHED; 849 } else { 850 p->status = p->signo; 851 p->signo = p->exitval; 852 p->exitval = 0; 853 p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 854 for (i = 0; i < NREG; i++) { 855 p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 856 p->oreg[i] = p->reg[i]; 857 } 858 savetty(stdout, &(p->ttyinfo)); 859 } 860 } 861 862 /* 863 * Set process's user area information from given process structure. 864 */ 865 866 private setinfo(p) 867 register Process p; 868 { 869 register int i; 870 register int r; 871 872 if (istraced(p)) { 873 p->signo = 0; 874 } 875 for (i = 0; i < NREG; i++) { 876 if ((r = p->reg[i]) != p->oreg[i]) { 877 ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 878 } 879 } 880 restoretty(stdout, &(p->ttyinfo)); 881 } 882 883 /* 884 * Structure for reading and writing by words, but dealing with bytes. 885 */ 886 887 typedef union { 888 Word pword; 889 Byte pbyte[sizeof(Word)]; 890 } Pword; 891 892 /* 893 * Read (write) from (to) the process' address space. 894 * We must deal with ptrace's inability to look anywhere other 895 * than at a word boundary. 896 */ 897 898 private Word fetch(); 899 private store(); 900 901 private pio(p, op, seg, buff, addr, nbytes) 902 Process p; 903 PioOp op; 904 PioSeg seg; 905 char *buff; 906 Address addr; 907 int nbytes; 908 { 909 register int i; 910 register Address newaddr; 911 register char *cp; 912 char *bufend; 913 Pword w; 914 Address wordaddr; 915 int byteoff; 916 917 if (p->status != STOPPED) { 918 error("program is not active"); 919 } 920 cp = buff; 921 newaddr = addr; 922 wordaddr = (newaddr&WMASK); 923 if (wordaddr != newaddr) { 924 w.pword = fetch(p, seg, wordaddr); 925 for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 926 if (op == PREAD) { 927 *cp++ = w.pbyte[i]; 928 } else { 929 w.pbyte[i] = *cp++; 930 } 931 nbytes--; 932 } 933 if (op == PWRITE) { 934 store(p, seg, wordaddr, w.pword); 935 } 936 newaddr = wordaddr + sizeof(Word); 937 } 938 byteoff = (nbytes&(~WMASK)); 939 nbytes -= byteoff; 940 bufend = cp + nbytes; 941 while (cp < bufend) { 942 if (op == PREAD) { 943 *((Word *) cp) = fetch(p, seg, newaddr); 944 } else { 945 store(p, seg, newaddr, *((Word *) cp)); 946 } 947 cp += sizeof(Word); 948 newaddr += sizeof(Word); 949 } 950 if (byteoff > 0) { 951 w.pword = fetch(p, seg, newaddr); 952 for (i = 0; i < byteoff; i++) { 953 if (op == PREAD) { 954 *cp++ = w.pbyte[i]; 955 } else { 956 w.pbyte[i] = *cp++; 957 } 958 } 959 if (op == PWRITE) { 960 store(p, seg, newaddr, w.pword); 961 } 962 } 963 } 964 965 /* 966 * Get a word from a process at the given address. 967 * The address is assumed to be on a word boundary. 968 * 969 * A simple cache scheme is used to avoid redundant ptrace calls 970 * to the instruction space since it is assumed to be pure. 971 * 972 * It is necessary to use a write-through scheme so that 973 * breakpoints right next to each other don't interfere. 974 */ 975 976 private Integer nfetchs, nreads, nwrites; 977 978 private Word fetch(p, seg, addr) 979 Process p; 980 PioSeg seg; 981 register int addr; 982 { 983 register CacheWord *wp; 984 register Word w; 985 986 switch (seg) { 987 case TEXTSEG: 988 ++nfetchs; 989 wp = &p->word[cachehash(addr)]; 990 if (addr == 0 or wp->addr != addr) { 991 ++nreads; 992 w = ptrace(IREAD, p->pid, addr, 0); 993 wp->addr = addr; 994 wp->val = w; 995 } else { 996 w = wp->val; 997 } 998 break; 999 1000 case DATASEG: 1001 w = ptrace(DREAD, p->pid, addr, 0); 1002 break; 1003 1004 default: 1005 panic("fetch: bad seg %d", seg); 1006 /* NOTREACHED */ 1007 } 1008 return w; 1009 } 1010 1011 /* 1012 * Put a word into the process' address space at the given address. 1013 * The address is assumed to be on a word boundary. 1014 */ 1015 1016 private store(p, seg, addr, data) 1017 Process p; 1018 PioSeg seg; 1019 int addr; 1020 Word data; 1021 { 1022 register CacheWord *wp; 1023 1024 switch (seg) { 1025 case TEXTSEG: 1026 ++nwrites; 1027 wp = &p->word[cachehash(addr)]; 1028 wp->addr = addr; 1029 wp->val = data; 1030 ptrace(IWRITE, p->pid, addr, data); 1031 break; 1032 1033 case DATASEG: 1034 ptrace(DWRITE, p->pid, addr, data); 1035 break; 1036 1037 default: 1038 panic("store: bad seg %d", seg); 1039 /* NOTREACHED */ 1040 } 1041 } 1042 1043 public printptraceinfo() 1044 { 1045 printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 1046 } 1047 1048 /* 1049 * Swap file numbers so as to redirect standard input and output. 1050 */ 1051 1052 private fswap(oldfd, newfd) 1053 int oldfd; 1054 int newfd; 1055 { 1056 if (oldfd != newfd) { 1057 close(oldfd); 1058 dup(newfd); 1059 close(newfd); 1060 } 1061 } 1062