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: }