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