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