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