|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)process.c 5.6 (Berkeley) 6/1/90"; ! 22: #endif /* not lint */ ! 23: ! 24: /* ! 25: * Process management. ! 26: * ! 27: * This module contains the routines to manage the execution and ! 28: * tracing of the debuggee process. ! 29: */ ! 30: ! 31: #include "defs.h" ! 32: #include "process.h" ! 33: #include "machine.h" ! 34: #include "events.h" ! 35: #include "tree.h" ! 36: #include "eval.h" ! 37: #include "operators.h" ! 38: #include "source.h" ! 39: #include "object.h" ! 40: #include "mappings.h" ! 41: #include "main.h" ! 42: #include "coredump.h" ! 43: #include <signal.h> ! 44: #include <errno.h> ! 45: #include <sys/stat.h> ! 46: ! 47: #ifndef public ! 48: ! 49: typedef struct Process *Process; ! 50: ! 51: Process process; ! 52: ! 53: #define DEFSIG -1 ! 54: ! 55: #include "machine.h" ! 56: ! 57: #endif ! 58: ! 59: #define NOTSTARTED 1 ! 60: #define STOPPED 0177 ! 61: #define FINISHED 0 ! 62: ! 63: /* ! 64: * A cache of the instruction segment is kept to reduce the number ! 65: * of system calls. Might be better just to read the entire ! 66: * code space into memory. ! 67: */ ! 68: ! 69: #define CACHESIZE 1003 ! 70: ! 71: typedef struct { ! 72: Word addr; ! 73: Word val; ! 74: } CacheWord; ! 75: ! 76: /* ! 77: * This structure holds the information we need from the user structure. ! 78: */ ! 79: ! 80: struct Process { ! 81: int pid; /* process being traced */ ! 82: int mask; /* process status word */ ! 83: Word reg[NREG]; /* process' registers */ ! 84: Word oreg[NREG]; /* registers when process last stopped */ ! 85: short status; /* either STOPPED or FINISHED */ ! 86: short signo; /* signal that stopped process */ ! 87: short sigcode; /* extra signal information */ ! 88: int exitval; /* return value from exit() */ ! 89: long sigset; /* bit array of traced signals */ ! 90: CacheWord word[CACHESIZE]; /* text segment cache */ ! 91: Ttyinfo ttyinfo; /* process' terminal characteristics */ ! 92: Address sigstatus; /* process' handler for current signal */ ! 93: }; ! 94: ! 95: /* ! 96: * These definitions are for the arguments to "pio". ! 97: */ ! 98: ! 99: typedef enum { PREAD, PWRITE } PioOp; ! 100: typedef enum { TEXTSEG, DATASEG } PioSeg; ! 101: ! 102: private struct Process pbuf; ! 103: ! 104: #define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */ ! 105: ! 106: extern int errno; ! 107: ! 108: private Boolean just_started; ! 109: private int argc; ! 110: private String argv[MAXNCMDARGS]; ! 111: private String infile, outfile; ! 112: ! 113: /* ! 114: * Initialize process information. ! 115: */ ! 116: ! 117: public process_init() ! 118: { ! 119: register integer i; ! 120: char buf[10]; ! 121: ! 122: process = &pbuf; ! 123: process->status = (coredump) ? STOPPED : NOTSTARTED; ! 124: setsigtrace(); ! 125: # if vax || tahoe ! 126: for (i = 0; i < NREG; i++) { ! 127: sprintf(buf, "$r%d", i); ! 128: defregname(identname(buf, false), i); ! 129: } ! 130: # ifdef vax ! 131: defregname(identname("$ap", true), ARGP); ! 132: # endif ! 133: # else ! 134: # ifdef mc68000 ! 135: for (i = 0; i < 8; i++) { ! 136: sprintf(buf, "$d%d", i); ! 137: defregname(identname(buf, false), i); ! 138: sprintf(buf, "$a%d", i); ! 139: defregname(identname(buf, false), i + 8); ! 140: } ! 141: # endif ! 142: # endif ! 143: defregname(identname("$fp", true), FRP); ! 144: defregname(identname("$sp", true), STKP); ! 145: defregname(identname("$pc", true), PROGCTR); ! 146: if (coredump) { ! 147: coredump_readin(process->mask, process->reg, process->signo); ! 148: pc = process->reg[PROGCTR]; ! 149: } ! 150: arginit(); ! 151: } ! 152: ! 153: /* ! 154: * Routines to get at process information from outside this module. ! 155: */ ! 156: ! 157: public Word reg(n) ! 158: Integer n; ! 159: { ! 160: register Word w; ! 161: ! 162: if (n == NREG) { ! 163: w = process->mask; ! 164: } else { ! 165: w = process->reg[n]; ! 166: } ! 167: return w; ! 168: } ! 169: ! 170: public setreg(n, w) ! 171: Integer n; ! 172: Word w; ! 173: { ! 174: process->reg[n] = w; ! 175: } ! 176: ! 177: /* ! 178: * Begin execution. ! 179: * ! 180: * We set a breakpoint at the end of the code so that the ! 181: * process data doesn't disappear after the program terminates. ! 182: */ ! 183: ! 184: private Boolean remade(); ! 185: ! 186: public start(argv, infile, outfile) ! 187: String argv[]; ! 188: String infile, outfile; ! 189: { ! 190: String pargv[4]; ! 191: Node cond; ! 192: ! 193: if (coredump) { ! 194: coredump = false; ! 195: fclose(corefile); ! 196: coredump_close(); ! 197: } ! 198: if (argv == nil) { ! 199: argv = pargv; ! 200: pargv[0] = objname; ! 201: pargv[1] = nil; ! 202: } else { ! 203: argv[argc] = nil; ! 204: } ! 205: pstart(process, argv, infile, outfile); ! 206: if (remade(objname)) { ! 207: reinit(argv, infile, outfile); ! 208: } ! 209: if (process->status == STOPPED) { ! 210: pc = CODESTART; ! 211: setcurfunc(program); ! 212: if (objsize != 0) { ! 213: cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); ! 214: event_once(cond, buildcmdlist(build(O_ENDX))); ! 215: } ! 216: } ! 217: } ! 218: ! 219: /* ! 220: * Check to see if the object file has changed since the symbolic ! 221: * information last was read. ! 222: */ ! 223: ! 224: private time_t modtime; ! 225: ! 226: private Boolean remade(filename) ! 227: String filename; ! 228: { ! 229: struct stat s; ! 230: Boolean b; ! 231: ! 232: stat(filename, &s); ! 233: b = (Boolean) (modtime != 0 and modtime < s.st_mtime); ! 234: modtime = s.st_mtime; ! 235: return b; ! 236: } ! 237: ! 238: /* ! 239: * Set up what signals we want to trace. ! 240: */ ! 241: ! 242: private setsigtrace() ! 243: { ! 244: register Integer i; ! 245: register Process p; ! 246: ! 247: p = process; ! 248: for (i = 1; i <= NSIG; i++) { ! 249: psigtrace(p, i, true); ! 250: } ! 251: psigtrace(p, SIGHUP, false); ! 252: psigtrace(p, SIGKILL, false); ! 253: psigtrace(p, SIGALRM, false); ! 254: # ifdef SIGTSTP ! 255: psigtrace(p, SIGTSTP, false); ! 256: psigtrace(p, SIGCONT, false); ! 257: # endif ! 258: psigtrace(p, SIGCHLD, false); ! 259: psigtrace(p, SIGWINCH, false); ! 260: } ! 261: ! 262: /* ! 263: * Initialize the argument list. ! 264: */ ! 265: ! 266: public arginit() ! 267: { ! 268: infile = nil; ! 269: outfile = nil; ! 270: argv[0] = objname; ! 271: argc = 1; ! 272: } ! 273: ! 274: /* ! 275: * Add an argument to the list for the debuggee. ! 276: */ ! 277: ! 278: public newarg(arg) ! 279: String arg; ! 280: { ! 281: if (argc >= MAXNCMDARGS) { ! 282: error("too many arguments"); ! 283: } ! 284: argv[argc++] = arg; ! 285: } ! 286: ! 287: /* ! 288: * Set the standard input for the debuggee. ! 289: */ ! 290: ! 291: public inarg(filename) ! 292: String filename; ! 293: { ! 294: if (infile != nil) { ! 295: error("multiple input redirects"); ! 296: } ! 297: infile = filename; ! 298: } ! 299: ! 300: /* ! 301: * Set the standard output for the debuggee. ! 302: * Probably should check to avoid overwriting an existing file. ! 303: */ ! 304: ! 305: public outarg(filename) ! 306: String filename; ! 307: { ! 308: if (outfile != nil) { ! 309: error("multiple output redirect"); ! 310: } ! 311: outfile = filename; ! 312: } ! 313: ! 314: /* ! 315: * Start debuggee executing. ! 316: */ ! 317: ! 318: public run() ! 319: { ! 320: process->status = STOPPED; ! 321: fixbps(); ! 322: curline = 0; ! 323: start(argv, infile, outfile); ! 324: just_started = true; ! 325: isstopped = false; ! 326: cont(0); ! 327: } ! 328: ! 329: /* ! 330: * Continue execution wherever we left off. ! 331: * ! 332: * Note that this routine never returns. Eventually bpact() will fail ! 333: * and we'll call printstatus or step will call it. ! 334: */ ! 335: ! 336: typedef int Intfunc(); ! 337: ! 338: private sig_t dbintr; ! 339: private void intr(); ! 340: ! 341: public cont(signo) ! 342: integer signo; ! 343: { ! 344: integer s; ! 345: ! 346: dbintr = signal(SIGINT, intr); ! 347: if (just_started) { ! 348: just_started = false; ! 349: } else { ! 350: if (not isstopped) { ! 351: error("can't continue execution"); ! 352: } ! 353: isstopped = false; ! 354: stepover(); ! 355: } ! 356: s = signo; ! 357: for (;;) { ! 358: if (single_stepping) { ! 359: printnews(); ! 360: } else { ! 361: setallbps(); ! 362: resume(s); ! 363: unsetallbps(); ! 364: s = DEFSIG; ! 365: if (not isbperr() or not bpact()) { ! 366: printstatus(); ! 367: } ! 368: } ! 369: stepover(); ! 370: } ! 371: /* NOTREACHED */ ! 372: } ! 373: ! 374: /* ! 375: * This routine is called if we get an interrupt while "running" ! 376: * but actually in the debugger. Could happen, for example, while ! 377: * processing breakpoints. ! 378: * ! 379: * We basically just want to keep going; the assumption is ! 380: * that when the process resumes it will get the interrupt, ! 381: * which will then be handled. ! 382: */ ! 383: ! 384: private void intr() ! 385: { ! 386: signal(SIGINT, intr); ! 387: } ! 388: ! 389: public fixintr() ! 390: { ! 391: signal(SIGINT, dbintr); ! 392: } ! 393: ! 394: /* ! 395: * Resume execution. ! 396: */ ! 397: ! 398: public resume(signo) ! 399: int signo; ! 400: { ! 401: register Process p; ! 402: ! 403: p = process; ! 404: pcont(p, signo); ! 405: pc = process->reg[PROGCTR]; ! 406: if (p->status != STOPPED) { ! 407: if (p->signo != 0) { ! 408: error("program terminated by signal %d", p->signo); ! 409: } else if (not runfirst) { ! 410: if (p->exitval == 0) { ! 411: error("program exited"); ! 412: } else { ! 413: error("program exited with code %d", p->exitval); ! 414: } ! 415: } ! 416: } ! 417: } ! 418: ! 419: /* ! 420: * Continue execution up to the next source line. ! 421: * ! 422: * There are two ways to define the next source line depending on what ! 423: * is desired when a procedure or function call is encountered. Step ! 424: * stops at the beginning of the procedure or call; next skips over it. ! 425: */ ! 426: ! 427: /* ! 428: * Stepc is what is called when the step command is given. ! 429: * It has to play with the "isstopped" information. ! 430: */ ! 431: ! 432: public stepc() ! 433: { ! 434: if (not isstopped) { ! 435: error("can't continue execution"); ! 436: } ! 437: isstopped = false; ! 438: dostep(false); ! 439: isstopped = true; ! 440: } ! 441: ! 442: public next() ! 443: { ! 444: Address oldfrp, newfrp; ! 445: ! 446: if (not isstopped) { ! 447: error("can't continue execution"); ! 448: } ! 449: isstopped = false; ! 450: oldfrp = reg(FRP); ! 451: do { ! 452: dostep(true); ! 453: pc = reg(PROGCTR); ! 454: newfrp = reg(FRP); ! 455: } while (newfrp < oldfrp and newfrp != 0); ! 456: isstopped = true; ! 457: } ! 458: ! 459: /* ! 460: * Continue execution until the current function returns, or, ! 461: * if the given argument is non-nil, until execution returns to ! 462: * somewhere within the given function. ! 463: */ ! 464: ! 465: public rtnfunc (f) ! 466: Symbol f; ! 467: { ! 468: Address addr; ! 469: Symbol t; ! 470: ! 471: if (not isstopped) { ! 472: error("can't continue execution"); ! 473: } else if (f != nil and not isactive(f)) { ! 474: error("%s is not active", symname(f)); ! 475: } else { ! 476: addr = return_addr(); ! 477: if (addr == nil) { ! 478: error("no place to return to"); ! 479: } else { ! 480: isstopped = false; ! 481: contto(addr); ! 482: if (f != nil) { ! 483: for (;;) { ! 484: t = whatblock(pc); ! 485: addr = return_addr(); ! 486: if (t == f or addr == nil) break; ! 487: contto(addr); ! 488: } ! 489: } ! 490: if (not bpact()) { ! 491: isstopped = true; ! 492: printstatus(); ! 493: } ! 494: } ! 495: } ! 496: } ! 497: ! 498: /* ! 499: * Single-step over the current machine instruction. ! 500: * ! 501: * If we're single-stepping by source line we want to step to the ! 502: * next source line. Otherwise we're going to continue so there's ! 503: * no reason to do all the work necessary to single-step to the next ! 504: * source line. ! 505: */ ! 506: ! 507: public stepover() ! 508: { ! 509: Boolean b; ! 510: ! 511: if (traceexec) { ! 512: printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); ! 513: } ! 514: if (single_stepping) { ! 515: dostep(false); ! 516: } else { ! 517: b = inst_tracing; ! 518: inst_tracing = true; ! 519: dostep(false); ! 520: inst_tracing = b; ! 521: } ! 522: if (traceexec) { ! 523: printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); ! 524: } ! 525: } ! 526: ! 527: /* ! 528: * Resume execution up to the given address. We can either ignore ! 529: * breakpoints (stepto) or catch them (contto). ! 530: */ ! 531: ! 532: public stepto(addr) ! 533: Address addr; ! 534: { ! 535: xto(addr, false); ! 536: } ! 537: ! 538: private contto (addr) ! 539: Address addr; ! 540: { ! 541: xto(addr, true); ! 542: } ! 543: ! 544: private xto (addr, catchbps) ! 545: Address addr; ! 546: boolean catchbps; ! 547: { ! 548: Address curpc; ! 549: ! 550: if (catchbps) { ! 551: stepover(); ! 552: } ! 553: curpc = process->reg[PROGCTR]; ! 554: if (addr != curpc) { ! 555: if (traceexec) { ! 556: printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); ! 557: } ! 558: if (catchbps) { ! 559: setallbps(); ! 560: } ! 561: setbp(addr); ! 562: resume(DEFSIG); ! 563: unsetbp(addr); ! 564: if (catchbps) { ! 565: unsetallbps(); ! 566: } ! 567: if (not isbperr()) { ! 568: printstatus(); ! 569: } ! 570: } ! 571: } ! 572: ! 573: /* ! 574: * Print the status of the process. ! 575: * This routine does not return. ! 576: */ ! 577: ! 578: public printstatus () ! 579: { ! 580: int status; ! 581: ! 582: if (process->status == FINISHED) { ! 583: exit(0); ! 584: } else { ! 585: if (runfirst) { ! 586: fprintf(stderr, "\nEntering debugger ...\n"); ! 587: printheading(); ! 588: init(); ! 589: } ! 590: setcurfunc(whatblock(pc)); ! 591: getsrcpos(); ! 592: if (process->signo == SIGINT) { ! 593: isstopped = true; ! 594: printerror(); ! 595: } else if (isbperr() and isstopped) { ! 596: printf("stopped "); ! 597: printloc(); ! 598: putchar('\n'); ! 599: if (curline > 0) { ! 600: printlines(curline, curline); ! 601: } else { ! 602: printinst(pc, pc); ! 603: } ! 604: erecover(); ! 605: } else { ! 606: fixintr(); ! 607: isstopped = true; ! 608: printerror(); ! 609: } ! 610: } ! 611: } ! 612: ! 613: /* ! 614: * Print out the current location in the debuggee. ! 615: */ ! 616: ! 617: public printloc() ! 618: { ! 619: printf("in "); ! 620: printname(stdout, curfunc); ! 621: putchar(' '); ! 622: if (curline > 0 and not useInstLoc) { ! 623: printsrcpos(); ! 624: } else { ! 625: useInstLoc = false; ! 626: curline = 0; ! 627: printf("at 0x%x", pc); ! 628: } ! 629: } ! 630: ! 631: /* ! 632: * Some functions for testing the state of the process. ! 633: */ ! 634: ! 635: public Boolean notstarted(p) ! 636: Process p; ! 637: { ! 638: return (Boolean) (p->status == NOTSTARTED); ! 639: } ! 640: ! 641: public Boolean isfinished(p) ! 642: Process p; ! 643: { ! 644: return (Boolean) (p->status == FINISHED); ! 645: } ! 646: ! 647: /* ! 648: * Predicate to test if the reason the process stopped was because ! 649: * of a breakpoint. If so, as a side effect clear the local copy of ! 650: * signal handler associated with process. We must do this so as to ! 651: * not confuse future stepping or continuing by possibly concluding ! 652: * the process should continue with a SIGTRAP handler. ! 653: */ ! 654: ! 655: public boolean isbperr() ! 656: { ! 657: Process p; ! 658: boolean b; ! 659: ! 660: p = process; ! 661: if (p->status == STOPPED and p->signo == SIGTRAP) { ! 662: b = true; ! 663: p->sigstatus = 0; ! 664: } else { ! 665: b = false; ! 666: } ! 667: return b; ! 668: } ! 669: ! 670: /* ! 671: * Return the signal number that stopped the process. ! 672: */ ! 673: ! 674: public integer errnum (p) ! 675: Process p; ! 676: { ! 677: return p->signo; ! 678: } ! 679: ! 680: /* ! 681: * Return the signal code associated with the signal. ! 682: */ ! 683: ! 684: public integer errcode (p) ! 685: Process p; ! 686: { ! 687: return p->sigcode; ! 688: } ! 689: ! 690: /* ! 691: * Return the termination code of the process. ! 692: */ ! 693: ! 694: public integer exitcode (p) ! 695: Process p; ! 696: { ! 697: return p->exitval; ! 698: } ! 699: ! 700: /* ! 701: * These routines are used to access the debuggee process from ! 702: * outside this module. ! 703: * ! 704: * They invoke "pio" which eventually leads to a call to "ptrace". ! 705: * The system generates an I/O error when a ptrace fails. During reads ! 706: * these are ignored, during writes they are reported as an error, and ! 707: * for anything else they cause a fatal error. ! 708: */ ! 709: ! 710: extern Intfunc *onsyserr(); ! 711: ! 712: private badaddr; ! 713: private read_err(), write_err(); ! 714: ! 715: /* ! 716: * Read from the process' instruction area. ! 717: */ ! 718: ! 719: public iread(buff, addr, nbytes) ! 720: char *buff; ! 721: Address addr; ! 722: int nbytes; ! 723: { ! 724: Intfunc *f; ! 725: ! 726: f = onsyserr(EIO, read_err); ! 727: badaddr = addr; ! 728: if (coredump) { ! 729: coredump_readtext(buff, addr, nbytes); ! 730: } else { ! 731: pio(process, PREAD, TEXTSEG, buff, addr, nbytes); ! 732: } ! 733: onsyserr(EIO, f); ! 734: } ! 735: ! 736: /* ! 737: * Write to the process' instruction area, usually in order to set ! 738: * or unset a breakpoint. ! 739: */ ! 740: ! 741: public iwrite(buff, addr, nbytes) ! 742: char *buff; ! 743: Address addr; ! 744: int nbytes; ! 745: { ! 746: Intfunc *f; ! 747: ! 748: if (coredump) { ! 749: error("no process to write to"); ! 750: } ! 751: f = onsyserr(EIO, write_err); ! 752: badaddr = addr; ! 753: pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); ! 754: onsyserr(EIO, f); ! 755: } ! 756: ! 757: /* ! 758: * Read for the process' data area. ! 759: */ ! 760: ! 761: public dread(buff, addr, nbytes) ! 762: char *buff; ! 763: Address addr; ! 764: int nbytes; ! 765: { ! 766: Intfunc *f; ! 767: ! 768: badaddr = addr; ! 769: if (coredump) { ! 770: f = onsyserr(EFAULT, read_err); ! 771: coredump_readdata(buff, addr, nbytes); ! 772: onsyserr(EFAULT, f); ! 773: } else { ! 774: f = onsyserr(EIO, read_err); ! 775: pio(process, PREAD, DATASEG, buff, addr, nbytes); ! 776: onsyserr(EIO, f); ! 777: } ! 778: } ! 779: ! 780: /* ! 781: * Write to the process' data area. ! 782: */ ! 783: ! 784: public dwrite(buff, addr, nbytes) ! 785: char *buff; ! 786: Address addr; ! 787: int nbytes; ! 788: { ! 789: Intfunc *f; ! 790: ! 791: if (coredump) { ! 792: error("no process to write to"); ! 793: } ! 794: f = onsyserr(EIO, write_err); ! 795: badaddr = addr; ! 796: pio(process, PWRITE, DATASEG, buff, addr, nbytes); ! 797: onsyserr(EIO, f); ! 798: } ! 799: ! 800: /* ! 801: * Trap for errors in reading or writing to a process. ! 802: * The current approach is to "ignore" read errors and complain ! 803: * bitterly about write errors. ! 804: */ ! 805: ! 806: private read_err() ! 807: { ! 808: /* ! 809: * Ignore. ! 810: */ ! 811: } ! 812: ! 813: private write_err() ! 814: { ! 815: error("can't write to process (address 0x%x)", badaddr); ! 816: } ! 817: ! 818: /* ! 819: * Ptrace interface. ! 820: */ ! 821: ! 822: #define WMASK (~(sizeof(Word) - 1)) ! 823: #define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE)) ! 824: ! 825: #define FIRSTSIG SIGINT ! 826: #define LASTSIG SIGQUIT ! 827: #define ischild(pid) ((pid) == 0) ! 828: #define traceme() ptrace(0, 0, 0, 0) ! 829: #define setrep(n) (1 << ((n)-1)) ! 830: #define istraced(p) (p->sigset&setrep(p->signo)) ! 831: ! 832: /* ! 833: * Ptrace options (specified in first argument). ! 834: */ ! 835: ! 836: #define UREAD 3 /* read from process's user structure */ ! 837: #define UWRITE 6 /* write to process's user structure */ ! 838: #define IREAD 1 /* read from process's instruction space */ ! 839: #define IWRITE 4 /* write to process's instruction space */ ! 840: #define DREAD 2 /* read from process's data space */ ! 841: #define DWRITE 5 /* write to process's data space */ ! 842: #define CONT 7 /* continue stopped process */ ! 843: #define SSTEP 9 /* continue for approximately one instruction */ ! 844: #define PKILL 8 /* terminate the process */ ! 845: ! 846: #ifdef IRIS ! 847: # define readreg(p, r) ptrace(10, p->pid, r, 0) ! 848: # define writereg(p, r, v) ptrace(11, p->pid, r, v) ! 849: #else ! 850: # define readreg(p, r) ptrace(UREAD, p->pid, regloc(r), 0); ! 851: # define writereg(p, r, v) ptrace(UWRITE, p->pid, regloc(r), v); ! 852: #endif ! 853: ! 854: /* ! 855: * Start up a new process by forking and exec-ing the ! 856: * given argument list, returning when the process is loaded ! 857: * and ready to execute. The PROCESS information (pointed to ! 858: * by the first argument) is appropriately filled. ! 859: * ! 860: * If the given PROCESS structure is associated with an already running ! 861: * process, we terminate it. ! 862: */ ! 863: ! 864: /* VARARGS2 */ ! 865: private pstart(p, argv, infile, outfile) ! 866: Process p; ! 867: String argv[]; ! 868: String infile; ! 869: String outfile; ! 870: { ! 871: int status; ! 872: ! 873: if (p->pid != 0) { ! 874: pterm(p); ! 875: cacheflush(p); ! 876: } ! 877: fflush(stdout); ! 878: psigtrace(p, SIGTRAP, true); ! 879: # ifdef IRIS ! 880: p->pid = fork(); ! 881: # else ! 882: p->pid = vfork(); ! 883: # endif ! 884: if (p->pid == -1) { ! 885: panic("can't fork"); ! 886: } ! 887: if (ischild(p->pid)) { ! 888: nocatcherrs(); ! 889: traceme(); ! 890: if (infile != nil) { ! 891: infrom(infile); ! 892: } ! 893: if (outfile != nil) { ! 894: outto(outfile); ! 895: } ! 896: execv(argv[0], argv); ! 897: _exit(1); ! 898: } ! 899: pwait(p->pid, &status); ! 900: getinfo(p, status); ! 901: if (p->status != STOPPED) { ! 902: beginerrmsg(); ! 903: fprintf(stderr, "warning: cannot execute %s\n", argv[0]); ! 904: } else { ! 905: ptraced(p->pid); ! 906: } ! 907: } ! 908: ! 909: /* ! 910: * Terminate a ptrace'd process. ! 911: */ ! 912: ! 913: public pterm (p) ! 914: Process p; ! 915: { ! 916: integer status; ! 917: ! 918: if (p != nil and p->pid != 0) { ! 919: ptrace(PKILL, p->pid, 0, 0); ! 920: pwait(p->pid, &status); ! 921: unptraced(p->pid); ! 922: } ! 923: } ! 924: ! 925: /* ! 926: * Continue a stopped process. The first argument points to a Process ! 927: * structure. Before the process is restarted it's user area is modified ! 928: * according to the values in the structure. When this routine finishes, ! 929: * the structure has the new values from the process's user area. ! 930: * ! 931: * Pcont terminates when the process stops with a signal pending that ! 932: * is being traced (via psigtrace), or when the process terminates. ! 933: */ ! 934: ! 935: private pcont(p, signo) ! 936: Process p; ! 937: int signo; ! 938: { ! 939: int s, status; ! 940: ! 941: if (p->pid == 0) { ! 942: error("program is not active"); ! 943: } ! 944: s = signo; ! 945: do { ! 946: setinfo(p, s); ! 947: if (traceexec) { ! 948: printf("!! pcont from 0x%x with signal %d (%d)\n", ! 949: p->reg[PROGCTR], s, p->signo); ! 950: fflush(stdout); ! 951: } ! 952: sigs_off(); ! 953: if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { ! 954: panic("error %d trying to continue process", errno); ! 955: } ! 956: pwait(p->pid, &status); ! 957: sigs_on(); ! 958: getinfo(p, status); ! 959: if (p->status == STOPPED and traceexec and not istraced(p)) { ! 960: printf("!! ignored signal %d at 0x%x\n", ! 961: p->signo, p->reg[PROGCTR]); ! 962: fflush(stdout); ! 963: } ! 964: s = p->signo; ! 965: } while (p->status == STOPPED and not istraced(p)); ! 966: if (traceexec) { ! 967: printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); ! 968: fflush(stdout); ! 969: } ! 970: } ! 971: ! 972: /* ! 973: * Single step as best ptrace can. ! 974: */ ! 975: ! 976: public pstep(p, signo) ! 977: Process p; ! 978: integer signo; ! 979: { ! 980: int s, status; ! 981: ! 982: s = signo; ! 983: do { ! 984: setinfo(p, s); ! 985: if (traceexec) { ! 986: printf("!! pstep from 0x%x with signal %d (%d)\n", ! 987: p->reg[PROGCTR], s, p->signo); ! 988: fflush(stdout); ! 989: } ! 990: sigs_off(); ! 991: if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { ! 992: panic("error %d trying to step process", errno); ! 993: } ! 994: pwait(p->pid, &status); ! 995: sigs_on(); ! 996: getinfo(p, status); ! 997: # if mc68000 || m68000 ! 998: if (p->status == STOPPED and p->signo == SIGTRAP) { ! 999: p->reg[PROGCTR] += 2; ! 1000: } ! 1001: # endif ! 1002: if (p->status == STOPPED and traceexec and not istraced(p)) { ! 1003: printf("!! pstep ignored signal %d at 0x%x\n", ! 1004: p->signo, p->reg[PROGCTR]); ! 1005: fflush(stdout); ! 1006: } ! 1007: s = p->signo; ! 1008: } while (p->status == STOPPED and not istraced(p)); ! 1009: if (traceexec) { ! 1010: printf("!! pstep to 0x%x on signal %d\n", ! 1011: p->reg[PROGCTR], p->signo); ! 1012: fflush(stdout); ! 1013: } ! 1014: if (p->status != STOPPED) { ! 1015: if (p->exitval == 0) { ! 1016: error("program exited\n"); ! 1017: } else { ! 1018: error("program exited with code %d\n", p->exitval); ! 1019: } ! 1020: } ! 1021: } ! 1022: ! 1023: /* ! 1024: * Return from execution when the given signal is pending. ! 1025: */ ! 1026: ! 1027: public psigtrace(p, sig, sw) ! 1028: Process p; ! 1029: int sig; ! 1030: Boolean sw; ! 1031: { ! 1032: if (sw) { ! 1033: p->sigset |= setrep(sig); ! 1034: } else { ! 1035: p->sigset &= ~setrep(sig); ! 1036: } ! 1037: } ! 1038: ! 1039: /* ! 1040: * Don't catch any signals. ! 1041: * Particularly useful when letting a process finish uninhibited. ! 1042: */ ! 1043: ! 1044: public unsetsigtraces(p) ! 1045: Process p; ! 1046: { ! 1047: p->sigset = 0; ! 1048: } ! 1049: ! 1050: /* ! 1051: * Turn off attention to signals not being caught. ! 1052: */ ! 1053: ! 1054: private sig_t sigfunc[NSIG]; ! 1055: ! 1056: private sigs_off() ! 1057: { ! 1058: register int i; ! 1059: ! 1060: for (i = FIRSTSIG; i < LASTSIG; i++) { ! 1061: if (i != SIGKILL) { ! 1062: sigfunc[i] = signal(i, SIG_IGN); ! 1063: } ! 1064: } ! 1065: } ! 1066: ! 1067: /* ! 1068: * Turn back on attention to signals. ! 1069: */ ! 1070: ! 1071: private sigs_on() ! 1072: { ! 1073: register int i; ! 1074: ! 1075: for (i = FIRSTSIG; i < LASTSIG; i++) { ! 1076: if (i != SIGKILL) { ! 1077: signal(i, sigfunc[i]); ! 1078: } ! 1079: } ! 1080: } ! 1081: ! 1082: /* ! 1083: * Get process information from user area. ! 1084: */ ! 1085: ! 1086: private getinfo (p, status) ! 1087: register Process p; ! 1088: register int status; ! 1089: { ! 1090: register int i; ! 1091: Address addr; ! 1092: ! 1093: p->signo = (status&0177); ! 1094: p->exitval = ((status >> 8)&0377); ! 1095: if (p->signo != STOPPED) { ! 1096: p->status = FINISHED; ! 1097: p->pid = 0; ! 1098: p->reg[PROGCTR] = 0; ! 1099: } else { ! 1100: p->status = p->signo; ! 1101: p->signo = p->exitval; ! 1102: p->exitval = 0; ! 1103: # ifdef IRIS ! 1104: p->mask = readreg(p, RPS); ! 1105: # else ! 1106: p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0); ! 1107: p->mask = readreg(p, PS); ! 1108: # endif ! 1109: for (i = 0; i < NREG; i++) { ! 1110: p->reg[i] = readreg(p, rloc[i]); ! 1111: p->oreg[i] = p->reg[i]; ! 1112: } ! 1113: # ifdef mc68000 ! 1114: if (p->status == STOPPED and p->signo == SIGTRAP and ! 1115: p->reg[PROGCTR] > CODESTART ! 1116: ) { ! 1117: p->reg[PROGCTR] -= 2; ! 1118: } ! 1119: # endif ! 1120: savetty(stdout, &(p->ttyinfo)); ! 1121: addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); ! 1122: p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); ! 1123: } ! 1124: } ! 1125: ! 1126: /* ! 1127: * Set process's user area information from given process structure. ! 1128: */ ! 1129: ! 1130: private setinfo (p, signo) ! 1131: register Process p; ! 1132: int signo; ! 1133: { ! 1134: register int i; ! 1135: register int r; ! 1136: ! 1137: if (signo == DEFSIG) { ! 1138: if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { ! 1139: p->signo = 0; ! 1140: } ! 1141: } else { ! 1142: p->signo = signo; ! 1143: } ! 1144: for (i = 0; i < NREG; i++) { ! 1145: if ((r = p->reg[i]) != p->oreg[i]) { ! 1146: writereg(p, rloc[i], r); ! 1147: } ! 1148: } ! 1149: restoretty(stdout, &(p->ttyinfo)); ! 1150: } ! 1151: ! 1152: /* ! 1153: * Return the address associated with the current signal. ! 1154: * (Plus two since the address points to the beginning of a procedure). ! 1155: */ ! 1156: ! 1157: public Address usignal (p) ! 1158: Process p; ! 1159: { ! 1160: Address r; ! 1161: ! 1162: r = p->sigstatus; ! 1163: if (r != 0 and r != 1) { ! 1164: r += FUNCOFFSET; ! 1165: } ! 1166: return r; ! 1167: } ! 1168: ! 1169: /* ! 1170: * Structure for reading and writing by words, but dealing with bytes. ! 1171: */ ! 1172: ! 1173: typedef union { ! 1174: Word pword; ! 1175: Byte pbyte[sizeof(Word)]; ! 1176: } Pword; ! 1177: ! 1178: /* ! 1179: * Read (write) from (to) the process' address space. ! 1180: * We must deal with ptrace's inability to look anywhere other ! 1181: * than at a word boundary. ! 1182: */ ! 1183: ! 1184: private Word fetch(); ! 1185: private store(); ! 1186: ! 1187: private pio(p, op, seg, buff, addr, nbytes) ! 1188: Process p; ! 1189: PioOp op; ! 1190: PioSeg seg; ! 1191: char *buff; ! 1192: Address addr; ! 1193: int nbytes; ! 1194: { ! 1195: register int i; ! 1196: register Address newaddr; ! 1197: register char *cp; ! 1198: char *bufend; ! 1199: Pword w; ! 1200: Address wordaddr; ! 1201: int byteoff; ! 1202: ! 1203: if (p->status != STOPPED) { ! 1204: error("program is not active"); ! 1205: } ! 1206: cp = buff; ! 1207: newaddr = addr; ! 1208: wordaddr = (newaddr&WMASK); ! 1209: if (wordaddr != newaddr) { ! 1210: w.pword = fetch(p, seg, wordaddr); ! 1211: for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { ! 1212: if (op == PREAD) { ! 1213: *cp++ = w.pbyte[i]; ! 1214: } else { ! 1215: w.pbyte[i] = *cp++; ! 1216: } ! 1217: nbytes--; ! 1218: } ! 1219: if (op == PWRITE) { ! 1220: store(p, seg, wordaddr, w.pword); ! 1221: } ! 1222: newaddr = wordaddr + sizeof(Word); ! 1223: } ! 1224: byteoff = (nbytes&(~WMASK)); ! 1225: nbytes -= byteoff; ! 1226: bufend = cp + nbytes; ! 1227: #ifdef tahoe ! 1228: if (((int)cp)&WMASK) { ! 1229: /* ! 1230: * Must copy a byte at a time, buffer not word addressable. ! 1231: */ ! 1232: while (cp < bufend) { ! 1233: if (op == PREAD) { ! 1234: w.pword = fetch(p, seg, newaddr); ! 1235: for (i = 0; i < sizeof(Word); i++) ! 1236: *cp++ = w.pbyte[i]; ! 1237: } else { ! 1238: for (i = 0; i < sizeof(Word); i++) ! 1239: w.pbyte[i] = *cp++; ! 1240: store(p, seg, newaddr, w.pword); ! 1241: } ! 1242: newaddr += sizeof(Word); ! 1243: } ! 1244: } else { ! 1245: /* ! 1246: * Buffer, word aligned, act normally... ! 1247: */ ! 1248: #endif ! 1249: while (cp < bufend) { ! 1250: if (op == PREAD) { ! 1251: *((Word *) cp) = fetch(p, seg, newaddr); ! 1252: } else { ! 1253: store(p, seg, newaddr, *((Word *) cp)); ! 1254: } ! 1255: cp += sizeof(Word); ! 1256: newaddr += sizeof(Word); ! 1257: } ! 1258: #ifdef tahoe ! 1259: } ! 1260: #endif ! 1261: if (byteoff > 0) { ! 1262: w.pword = fetch(p, seg, newaddr); ! 1263: for (i = 0; i < byteoff; i++) { ! 1264: if (op == PREAD) { ! 1265: *cp++ = w.pbyte[i]; ! 1266: } else { ! 1267: w.pbyte[i] = *cp++; ! 1268: } ! 1269: } ! 1270: if (op == PWRITE) { ! 1271: store(p, seg, newaddr, w.pword); ! 1272: } ! 1273: } ! 1274: } ! 1275: ! 1276: /* ! 1277: * Get a word from a process at the given address. ! 1278: * The address is assumed to be on a word boundary. ! 1279: * ! 1280: * A simple cache scheme is used to avoid redundant ptrace calls ! 1281: * to the instruction space since it is assumed to be pure. ! 1282: * ! 1283: * It is necessary to use a write-through scheme so that ! 1284: * breakpoints right next to each other don't interfere. ! 1285: */ ! 1286: ! 1287: private Integer nfetchs, nreads, nwrites; ! 1288: ! 1289: private Word fetch(p, seg, addr) ! 1290: Process p; ! 1291: PioSeg seg; ! 1292: register int addr; ! 1293: { ! 1294: register CacheWord *wp; ! 1295: register Word w; ! 1296: ! 1297: switch (seg) { ! 1298: case TEXTSEG: ! 1299: ++nfetchs; ! 1300: wp = &p->word[cachehash(addr)]; ! 1301: if (addr == 0 or wp->addr != addr) { ! 1302: ++nreads; ! 1303: w = ptrace(IREAD, p->pid, addr, 0); ! 1304: wp->addr = addr; ! 1305: wp->val = w; ! 1306: } else { ! 1307: w = wp->val; ! 1308: } ! 1309: break; ! 1310: ! 1311: case DATASEG: ! 1312: w = ptrace(DREAD, p->pid, addr, 0); ! 1313: break; ! 1314: ! 1315: default: ! 1316: panic("fetch: bad seg %d", seg); ! 1317: /* NOTREACHED */ ! 1318: } ! 1319: return w; ! 1320: } ! 1321: ! 1322: /* ! 1323: * Put a word into the process' address space at the given address. ! 1324: * The address is assumed to be on a word boundary. ! 1325: */ ! 1326: ! 1327: private store(p, seg, addr, data) ! 1328: Process p; ! 1329: PioSeg seg; ! 1330: int addr; ! 1331: Word data; ! 1332: { ! 1333: register CacheWord *wp; ! 1334: ! 1335: switch (seg) { ! 1336: case TEXTSEG: ! 1337: ++nwrites; ! 1338: wp = &p->word[cachehash(addr)]; ! 1339: wp->addr = addr; ! 1340: wp->val = data; ! 1341: ptrace(IWRITE, p->pid, addr, data); ! 1342: break; ! 1343: ! 1344: case DATASEG: ! 1345: ptrace(DWRITE, p->pid, addr, data); ! 1346: break; ! 1347: ! 1348: default: ! 1349: panic("store: bad seg %d", seg); ! 1350: /* NOTREACHED */ ! 1351: } ! 1352: } ! 1353: ! 1354: /* ! 1355: * Flush the instruction cache associated with a process. ! 1356: */ ! 1357: ! 1358: private cacheflush (p) ! 1359: Process p; ! 1360: { ! 1361: bzero(p->word, sizeof(p->word)); ! 1362: } ! 1363: ! 1364: public printptraceinfo() ! 1365: { ! 1366: printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); ! 1367: } ! 1368: ! 1369: /* ! 1370: * Redirect input. ! 1371: * Assuming this is called from a child, we should be careful to avoid ! 1372: * (possibly) shared standard I/O buffers. ! 1373: */ ! 1374: ! 1375: private infrom (filename) ! 1376: String filename; ! 1377: { ! 1378: Fileid in; ! 1379: ! 1380: in = open(filename, 0); ! 1381: if (in == -1) { ! 1382: write(2, "can't read ", 11); ! 1383: write(2, filename, strlen(filename)); ! 1384: write(2, "\n", 1); ! 1385: _exit(1); ! 1386: } ! 1387: fswap(0, in); ! 1388: } ! 1389: ! 1390: /* ! 1391: * Redirect standard output. ! 1392: * Same assumptions as for "infrom" above. ! 1393: */ ! 1394: ! 1395: private outto (filename) ! 1396: String filename; ! 1397: { ! 1398: Fileid out; ! 1399: ! 1400: out = creat(filename, 0666); ! 1401: if (out == -1) { ! 1402: write(2, "can't write ", 12); ! 1403: write(2, filename, strlen(filename)); ! 1404: write(2, "\n", 1); ! 1405: _exit(1); ! 1406: } ! 1407: fswap(1, out); ! 1408: } ! 1409: ! 1410: /* ! 1411: * Swap file numbers, useful for redirecting standard input or output. ! 1412: */ ! 1413: ! 1414: private fswap(oldfd, newfd) ! 1415: Fileid oldfd; ! 1416: Fileid newfd; ! 1417: { ! 1418: if (oldfd != newfd) { ! 1419: close(oldfd); ! 1420: dup(newfd); ! 1421: close(newfd); ! 1422: } ! 1423: } ! 1424: ! 1425: /* ! 1426: * Signal name manipulation. ! 1427: */ ! 1428: ! 1429: private String signames[NSIG] = { ! 1430: 0, ! 1431: "HUP", "INT", "QUIT", "ILL", "TRAP", ! 1432: "IOT", "EMT", "FPE", "KILL", "BUS", ! 1433: "SEGV", "SYS", "PIPE", "ALRM", "TERM", ! 1434: 0, "STOP", "TSTP", "CONT", "CHLD", ! 1435: "TTIN", "TTOU", "TINT", "XCPU", "XFSZ", ! 1436: "VTALRM", "PROF", "WINCH", "USR1", "USR2" ! 1437: }; ! 1438: ! 1439: /* ! 1440: * Get the signal number associated with a given name. ! 1441: * The name is first translated to upper case if necessary. ! 1442: */ ! 1443: ! 1444: public integer siglookup (s) ! 1445: String s; ! 1446: { ! 1447: register char *p, *q; ! 1448: char buf[100]; ! 1449: integer i; ! 1450: ! 1451: p = s; ! 1452: q = buf; ! 1453: while (*p != '\0') { ! 1454: if (*p >= 'a' and *p <= 'z') { ! 1455: *q = (*p - 'a') + 'A'; ! 1456: } else { ! 1457: *q = *p; ! 1458: } ! 1459: ++p; ! 1460: ++q; ! 1461: } ! 1462: *q = '\0'; ! 1463: p = buf; ! 1464: if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') { ! 1465: p += 3; ! 1466: } ! 1467: i = 1; ! 1468: for (;;) { ! 1469: if (i >= sizeof(signames) div sizeof(signames[0])) { ! 1470: error("signal \"%s\" unknown", s); ! 1471: i = 0; ! 1472: break; ! 1473: } ! 1474: if (signames[i] != nil and streq(signames[i], p)) { ! 1475: break; ! 1476: } ! 1477: ++i; ! 1478: } ! 1479: return i; ! 1480: } ! 1481: ! 1482: /* ! 1483: * Print all signals being ignored by the debugger. ! 1484: * These signals are auotmatically ! 1485: * passed on to the debugged process. ! 1486: */ ! 1487: ! 1488: public printsigsignored (p) ! 1489: Process p; ! 1490: { ! 1491: printsigs(~p->sigset); ! 1492: } ! 1493: ! 1494: /* ! 1495: * Print all signals being intercepted by ! 1496: * the debugger for the specified process. ! 1497: */ ! 1498: ! 1499: public printsigscaught(p) ! 1500: Process p; ! 1501: { ! 1502: printsigs(p->sigset); ! 1503: } ! 1504: ! 1505: private printsigs (set) ! 1506: integer set; ! 1507: { ! 1508: integer s; ! 1509: char separator[2]; ! 1510: ! 1511: separator[0] = '\0'; ! 1512: for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) { ! 1513: if (set & setrep(s)) { ! 1514: if (signames[s] != nil) { ! 1515: printf("%s%s", separator, signames[s]); ! 1516: separator[0] = ' '; ! 1517: separator[1] = '\0'; ! 1518: } ! 1519: } ! 1520: } ! 1521: if (separator[0] == ' ') { ! 1522: putchar('\n'); ! 1523: } ! 1524: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.