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