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