19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*18230Slinton static char sccsid[] = "@(#)process.c 1.17 (Berkeley) 03/01/85"; 49677Slinton 5*18230Slinton static char rcsid[] = "$Header: process.c,v 1.5 84/12/26 10:41:37 linton Exp $"; 6*18230Slinton 79677Slinton /* 89677Slinton * Process management. 99677Slinton * 109677Slinton * This module contains the routines to manage the execution and 119677Slinton * tracing of the debuggee process. 129677Slinton */ 139677Slinton 149677Slinton #include "defs.h" 159677Slinton #include "process.h" 169677Slinton #include "machine.h" 179677Slinton #include "events.h" 189677Slinton #include "tree.h" 1914757Slinton #include "eval.h" 209677Slinton #include "operators.h" 219677Slinton #include "source.h" 229677Slinton #include "object.h" 239677Slinton #include "mappings.h" 249677Slinton #include "main.h" 259677Slinton #include "coredump.h" 269677Slinton #include <signal.h> 279677Slinton #include <errno.h> 289677Slinton #include <sys/param.h> 2916617Ssam #include <sys/dir.h> 3016617Ssam #include <sys/user.h> 319843Slinton #include <machine/reg.h> 329677Slinton #include <sys/stat.h> 339677Slinton 349677Slinton #ifndef public 359677Slinton 369677Slinton typedef struct Process *Process; 379677Slinton 389677Slinton Process process; 399677Slinton 4014757Slinton #define DEFSIG -1 4114757Slinton 429677Slinton #include "machine.h" 439677Slinton 449677Slinton #endif 459677Slinton 469677Slinton #define NOTSTARTED 1 479677Slinton #define STOPPED 0177 489677Slinton #define FINISHED 0 499677Slinton 509677Slinton /* 5116617Ssam * A cache of the instruction segment is kept to reduce the number 5216617Ssam * of system calls. Might be better just to read the entire 5316617Ssam * code space into memory. 549677Slinton */ 559677Slinton 569677Slinton #define CSIZE 1003 /* size of instruction cache */ 579677Slinton 589677Slinton typedef struct { 599677Slinton Word addr; 609677Slinton Word val; 619677Slinton } CacheWord; 629677Slinton 639677Slinton /* 649677Slinton * This structure holds the information we need from the user structure. 659677Slinton */ 669677Slinton 679677Slinton struct Process { 689677Slinton int pid; /* process being traced */ 6911768Slinton int mask; /* process status word */ 7011768Slinton Word reg[NREG]; /* process' registers */ 719677Slinton Word oreg[NREG]; /* registers when process last stopped */ 729677Slinton short status; /* either STOPPED or FINISHED */ 739677Slinton short signo; /* signal that stopped process */ 74*18230Slinton short sigcode; /* extra signal information */ 759677Slinton int exitval; /* return value from exit() */ 769677Slinton long sigset; /* bit array of traced signals */ 779677Slinton CacheWord word[CSIZE]; /* text segment cache */ 7811768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 7916617Ssam Address sigstatus; /* process' handler for current signal */ 809677Slinton }; 819677Slinton 829677Slinton /* 839677Slinton * These definitions are for the arguments to "pio". 849677Slinton */ 859677Slinton 869677Slinton typedef enum { PREAD, PWRITE } PioOp; 879677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 889677Slinton 899677Slinton private struct Process pbuf; 909677Slinton 91*18230Slinton #define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */ 929677Slinton 9314395Slinton extern int errno; 9414395Slinton 959677Slinton private Boolean just_started; 969677Slinton private int argc; 979677Slinton private String argv[MAXNCMDARGS]; 989677Slinton private String infile, outfile; 999677Slinton 1009677Slinton /* 1019677Slinton * Initialize process information. 1029677Slinton */ 1039677Slinton 1049677Slinton public process_init() 1059677Slinton { 1069677Slinton register Integer i; 1079677Slinton Char buf[10]; 1089677Slinton 1099677Slinton process = &pbuf; 1109677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1119677Slinton setsigtrace(); 1129677Slinton for (i = 0; i < NREG; i++) { 1139677Slinton sprintf(buf, "$r%d", i); 1149677Slinton defregname(identname(buf, false), i); 1159677Slinton } 1169677Slinton defregname(identname("$ap", true), ARGP); 1179677Slinton defregname(identname("$fp", true), FRP); 1189677Slinton defregname(identname("$sp", true), STKP); 1199677Slinton defregname(identname("$pc", true), PROGCTR); 1209677Slinton if (coredump) { 1219677Slinton coredump_readin(process->mask, process->reg, process->signo); 12212484Slinton pc = process->reg[PROGCTR]; 12312484Slinton getsrcpos(); 1249677Slinton } 12512484Slinton arginit(); 1269677Slinton } 1279677Slinton 1289677Slinton /* 1299677Slinton * Routines to get at process information from outside this module. 1309677Slinton */ 1319677Slinton 1329677Slinton public Word reg(n) 1339677Slinton Integer n; 1349677Slinton { 1359677Slinton register Word w; 1369677Slinton 1379677Slinton if (n == NREG) { 1389677Slinton w = process->mask; 1399677Slinton } else { 1409677Slinton w = process->reg[n]; 1419677Slinton } 1429677Slinton return w; 1439677Slinton } 1449677Slinton 1459677Slinton public setreg(n, w) 1469677Slinton Integer n; 1479677Slinton Word w; 1489677Slinton { 1499677Slinton process->reg[n] = w; 1509677Slinton } 1519677Slinton 1529677Slinton /* 1539677Slinton * Begin execution. 1549677Slinton * 1559677Slinton * We set a breakpoint at the end of the code so that the 1569677Slinton * process data doesn't disappear after the program terminates. 1579677Slinton */ 1589677Slinton 1599677Slinton private Boolean remade(); 1609677Slinton 1619677Slinton public start(argv, infile, outfile) 1629677Slinton String argv[]; 1639677Slinton String infile, outfile; 1649677Slinton { 1659677Slinton String pargv[4]; 1669677Slinton Node cond; 1679677Slinton 1689677Slinton if (coredump) { 1699677Slinton coredump = false; 1709677Slinton fclose(corefile); 1719677Slinton coredump_close(); 1729677Slinton } 1739677Slinton if (argv == nil) { 1749677Slinton argv = pargv; 1759677Slinton pargv[0] = objname; 1769677Slinton pargv[1] = nil; 1779677Slinton } else { 1789677Slinton argv[argc] = nil; 1799677Slinton } 180*18230Slinton pstart(process, argv, infile, outfile); 1819677Slinton if (remade(objname)) { 1829677Slinton reinit(argv, infile, outfile); 1839677Slinton } 1849677Slinton if (process->status == STOPPED) { 1859677Slinton pc = 0; 18616617Ssam setcurfunc(program); 1879677Slinton if (objsize != 0) { 1889677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1899677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1909677Slinton } 1919677Slinton } 1929677Slinton } 1939677Slinton 1949677Slinton /* 1959677Slinton * Check to see if the object file has changed since the symbolic 1969677Slinton * information last was read. 1979677Slinton */ 1989677Slinton 1999677Slinton private time_t modtime; 2009677Slinton 2019677Slinton private Boolean remade(filename) 2029677Slinton String filename; 2039677Slinton { 2049677Slinton struct stat s; 2059677Slinton Boolean b; 2069677Slinton 2079677Slinton stat(filename, &s); 2089677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2099677Slinton modtime = s.st_mtime; 2109677Slinton return b; 2119677Slinton } 2129677Slinton 2139677Slinton /* 2149677Slinton * Set up what signals we want to trace. 2159677Slinton */ 2169677Slinton 2179677Slinton private setsigtrace() 2189677Slinton { 2199677Slinton register Integer i; 2209677Slinton register Process p; 2219677Slinton 2229677Slinton p = process; 2239677Slinton for (i = 1; i <= NSIG; i++) { 2249677Slinton psigtrace(p, i, true); 2259677Slinton } 2269677Slinton psigtrace(p, SIGHUP, false); 2279677Slinton psigtrace(p, SIGKILL, false); 2289677Slinton psigtrace(p, SIGALRM, false); 2299677Slinton psigtrace(p, SIGTSTP, false); 2309677Slinton psigtrace(p, SIGCONT, false); 2319677Slinton psigtrace(p, SIGCHLD, false); 2329677Slinton } 2339677Slinton 2349677Slinton /* 2359677Slinton * Initialize the argument list. 2369677Slinton */ 2379677Slinton 2389677Slinton public arginit() 2399677Slinton { 2409677Slinton infile = nil; 2419677Slinton outfile = nil; 2429677Slinton argv[0] = objname; 2439677Slinton argc = 1; 2449677Slinton } 2459677Slinton 2469677Slinton /* 2479677Slinton * Add an argument to the list for the debuggee. 2489677Slinton */ 2499677Slinton 2509677Slinton public newarg(arg) 2519677Slinton String arg; 2529677Slinton { 2539677Slinton if (argc >= MAXNCMDARGS) { 2549677Slinton error("too many arguments"); 2559677Slinton } 2569677Slinton argv[argc++] = arg; 2579677Slinton } 2589677Slinton 2599677Slinton /* 2609677Slinton * Set the standard input for the debuggee. 2619677Slinton */ 2629677Slinton 2639677Slinton public inarg(filename) 2649677Slinton String filename; 2659677Slinton { 2669677Slinton if (infile != nil) { 2679677Slinton error("multiple input redirects"); 2689677Slinton } 2699677Slinton infile = filename; 2709677Slinton } 2719677Slinton 2729677Slinton /* 2739677Slinton * Set the standard output for the debuggee. 2749677Slinton * Probably should check to avoid overwriting an existing file. 2759677Slinton */ 2769677Slinton 2779677Slinton public outarg(filename) 2789677Slinton String filename; 2799677Slinton { 2809677Slinton if (outfile != nil) { 2819677Slinton error("multiple output redirect"); 2829677Slinton } 2839677Slinton outfile = filename; 2849677Slinton } 2859677Slinton 2869677Slinton /* 2879677Slinton * Start debuggee executing. 2889677Slinton */ 2899677Slinton 2909677Slinton public run() 2919677Slinton { 2929677Slinton process->status = STOPPED; 2939677Slinton fixbps(); 2949677Slinton curline = 0; 2959677Slinton start(argv, infile, outfile); 2969677Slinton just_started = true; 2979677Slinton isstopped = false; 29814757Slinton cont(0); 2999677Slinton } 3009677Slinton 3019677Slinton /* 3029677Slinton * Continue execution wherever we left off. 3039677Slinton * 3049677Slinton * Note that this routine never returns. Eventually bpact() will fail 3059677Slinton * and we'll call printstatus or step will call it. 3069677Slinton */ 3079677Slinton 3089677Slinton typedef int Intfunc(); 3099677Slinton 3109677Slinton private Intfunc *dbintr; 3119677Slinton private intr(); 3129677Slinton 31311867Slinton public cont(signo) 31416617Ssam integer signo; 3159677Slinton { 31616617Ssam integer s; 31716617Ssam 3189677Slinton dbintr = signal(SIGINT, intr); 3199677Slinton if (just_started) { 3209677Slinton just_started = false; 3219677Slinton } else { 3229677Slinton if (not isstopped) { 3239677Slinton error("can't continue execution"); 3249677Slinton } 3259677Slinton isstopped = false; 32611867Slinton stepover(); 3279677Slinton } 32816617Ssam s = signo; 3299677Slinton for (;;) { 3309677Slinton if (single_stepping) { 3319677Slinton printnews(); 3329677Slinton } else { 3339677Slinton setallbps(); 33416617Ssam resume(s); 3359677Slinton unsetallbps(); 33616617Ssam s = DEFSIG; 337*18230Slinton if (not isbperr() or not bpact()) { 3389677Slinton printstatus(); 3399677Slinton } 3409677Slinton } 34111867Slinton stepover(); 3429677Slinton } 3439677Slinton /* NOTREACHED */ 3449677Slinton } 3459677Slinton 3469677Slinton /* 347*18230Slinton * This routine is called if we get an interrupt while "running" 3489677Slinton * but actually in the debugger. Could happen, for example, while 3499677Slinton * processing breakpoints. 3509677Slinton * 3519677Slinton * We basically just want to keep going; the assumption is 352*18230Slinton * that when the process resumes it will get the interrupt, 3539677Slinton * which will then be handled. 3549677Slinton */ 3559677Slinton 3569677Slinton private intr() 3579677Slinton { 3589677Slinton signal(SIGINT, intr); 3599677Slinton } 3609677Slinton 3619677Slinton public fixintr() 3629677Slinton { 3639677Slinton signal(SIGINT, dbintr); 3649677Slinton } 3659677Slinton 3669677Slinton /* 3679677Slinton * Resume execution. 3689677Slinton */ 3699677Slinton 37011867Slinton public resume(signo) 37111867Slinton int signo; 3729677Slinton { 3739677Slinton register Process p; 3749677Slinton 3759677Slinton p = process; 37611867Slinton pcont(p, signo); 3779677Slinton pc = process->reg[PROGCTR]; 37811832Slinton if (p->status != STOPPED) { 37911867Slinton if (p->signo != 0) { 38011867Slinton error("program terminated by signal %d", p->signo); 38114757Slinton } else if (not runfirst) { 382*18230Slinton if (p->exitval == 0) { 383*18230Slinton error("program exited"); 384*18230Slinton } else { 385*18230Slinton error("program exited with code %d", p->exitval); 386*18230Slinton } 38711867Slinton } 38811832Slinton } 3899677Slinton } 3909677Slinton 3919677Slinton /* 3929677Slinton * Continue execution up to the next source line. 3939677Slinton * 3949677Slinton * There are two ways to define the next source line depending on what 3959677Slinton * is desired when a procedure or function call is encountered. Step 3969677Slinton * stops at the beginning of the procedure or call; next skips over it. 3979677Slinton */ 3989677Slinton 3999677Slinton /* 4009677Slinton * Stepc is what is called when the step command is given. 4019677Slinton * It has to play with the "isstopped" information. 4029677Slinton */ 4039677Slinton 4049677Slinton public stepc() 4059677Slinton { 4069677Slinton if (not isstopped) { 4079677Slinton error("can't continue execution"); 4089677Slinton } 4099677Slinton isstopped = false; 4109677Slinton dostep(false); 4119677Slinton isstopped = true; 4129677Slinton } 4139677Slinton 4149677Slinton public next() 4159677Slinton { 41616617Ssam Address oldfrp, newfrp; 41716617Ssam 4189677Slinton if (not isstopped) { 4199677Slinton error("can't continue execution"); 4209677Slinton } 4219677Slinton isstopped = false; 42216617Ssam oldfrp = reg(FRP); 42316617Ssam do { 42416617Ssam dostep(true); 42516617Ssam pc = reg(PROGCTR); 42616617Ssam newfrp = reg(FRP); 42716617Ssam } while (newfrp < oldfrp and newfrp != 0); 4289677Slinton isstopped = true; 4299677Slinton } 4309677Slinton 43111867Slinton /* 43216617Ssam * Continue execution until the current function returns, or, 43316617Ssam * if the given argument is non-nil, until execution returns to 43416617Ssam * somewhere within the given function. 43516617Ssam */ 43616617Ssam 43716617Ssam public rtnfunc (f) 43816617Ssam Symbol f; 43916617Ssam { 44016617Ssam Address addr; 44116617Ssam Symbol t; 44216617Ssam 44316617Ssam if (not isstopped) { 44416617Ssam error("can't continue execution"); 44516617Ssam } else if (f != nil and not isactive(f)) { 44616617Ssam error("%s is not active", symname(f)); 44716617Ssam } else { 44816617Ssam addr = return_addr(); 44916617Ssam if (addr == nil) { 45016617Ssam error("no place to return to"); 45116617Ssam } else { 45216617Ssam isstopped = false; 45316617Ssam contto(addr); 45416617Ssam if (f != nil) { 45516617Ssam for (;;) { 45616617Ssam t = whatblock(pc); 45716617Ssam addr = return_addr(); 45816617Ssam if (t == f or addr == nil) break; 45916617Ssam contto(addr); 46016617Ssam } 46116617Ssam } 462*18230Slinton if (not bpact()) { 46316617Ssam isstopped = true; 46416617Ssam printstatus(); 46516617Ssam } 46616617Ssam } 46716617Ssam } 46816617Ssam } 46916617Ssam 47016617Ssam /* 47111867Slinton * Single-step over the current machine instruction. 47211867Slinton * 47311867Slinton * If we're single-stepping by source line we want to step to the 47411867Slinton * next source line. Otherwise we're going to continue so there's 47511867Slinton * no reason to do all the work necessary to single-step to the next 47611867Slinton * source line. 47711867Slinton */ 47811867Slinton 47916617Ssam public stepover() 4809677Slinton { 48111867Slinton Boolean b; 48211867Slinton 48316617Ssam if (traceexec) { 48416617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); 48516617Ssam } 48611867Slinton if (single_stepping) { 48711867Slinton dostep(false); 48811867Slinton } else { 48911867Slinton b = inst_tracing; 49011867Slinton inst_tracing = true; 49111867Slinton dostep(false); 49211867Slinton inst_tracing = b; 49311867Slinton } 49416617Ssam if (traceexec) { 49516617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); 49616617Ssam } 4979677Slinton } 4989677Slinton 4999677Slinton /* 500*18230Slinton * Resume execution up to the given address. We can either ignore 501*18230Slinton * breakpoints (stepto) or catch them (contto). 5029677Slinton */ 5039677Slinton 5049677Slinton public stepto(addr) 5059677Slinton Address addr; 5069677Slinton { 50716617Ssam xto(addr, false); 50816617Ssam } 50916617Ssam 51016617Ssam private contto (addr) 51116617Ssam Address addr; 51216617Ssam { 51316617Ssam xto(addr, true); 51416617Ssam } 51516617Ssam 51616617Ssam private xto (addr, catchbps) 51716617Ssam Address addr; 51816617Ssam boolean catchbps; 51916617Ssam { 52016617Ssam Address curpc; 52116617Ssam 52216617Ssam if (catchbps) { 52316617Ssam stepover(); 5249677Slinton } 52516617Ssam curpc = process->reg[PROGCTR]; 52616617Ssam if (addr != curpc) { 52716617Ssam if (traceexec) { 52816617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); 52916617Ssam } 53016617Ssam if (catchbps) { 53116617Ssam setallbps(); 53216617Ssam } 53316617Ssam setbp(addr); 53416617Ssam resume(DEFSIG); 53516617Ssam unsetbp(addr); 53616617Ssam if (catchbps) { 53716617Ssam unsetallbps(); 53816617Ssam } 53916617Ssam if (not isbperr()) { 54016617Ssam printstatus(); 54116617Ssam } 54216617Ssam } 5439677Slinton } 5449677Slinton 5459677Slinton /* 5469677Slinton * Print the status of the process. 5479677Slinton * This routine does not return. 5489677Slinton */ 5499677Slinton 5509677Slinton public printstatus() 5519677Slinton { 55214395Slinton int status; 55314395Slinton 5549843Slinton if (process->status == FINISHED) { 5559843Slinton exit(0); 5569843Slinton } else { 55716617Ssam setcurfunc(whatblock(pc)); 5589677Slinton getsrcpos(); 5599843Slinton if (process->signo == SIGINT) { 5609843Slinton isstopped = true; 5619843Slinton printerror(); 5629843Slinton } else if (isbperr() and isstopped) { 5639843Slinton printf("stopped "); 56411172Slinton printloc(); 56511172Slinton putchar('\n'); 5669843Slinton if (curline > 0) { 5679843Slinton printlines(curline, curline); 5689843Slinton } else { 5699843Slinton printinst(pc, pc); 5709843Slinton } 5719843Slinton erecover(); 5729677Slinton } else { 5739843Slinton fixintr(); 5749677Slinton isstopped = true; 5759677Slinton printerror(); 5769677Slinton } 5779677Slinton } 5789677Slinton } 5799677Slinton 5809677Slinton /* 58111172Slinton * Print out the current location in the debuggee. 58211172Slinton */ 58311172Slinton 58411172Slinton public printloc() 58511172Slinton { 58611172Slinton printf("in "); 58711172Slinton printname(stdout, curfunc); 58811172Slinton putchar(' '); 58914757Slinton if (curline > 0 and not useInstLoc) { 59011172Slinton printsrcpos(); 59111172Slinton } else { 59214757Slinton useInstLoc = false; 59314757Slinton curline = 0; 59411172Slinton printf("at 0x%x", pc); 59511172Slinton } 59611172Slinton } 59711172Slinton 59811172Slinton /* 5999677Slinton * Some functions for testing the state of the process. 6009677Slinton */ 6019677Slinton 6029677Slinton public Boolean notstarted(p) 6039677Slinton Process p; 6049677Slinton { 6059677Slinton return (Boolean) (p->status == NOTSTARTED); 6069677Slinton } 6079677Slinton 6089677Slinton public Boolean isfinished(p) 6099677Slinton Process p; 6109677Slinton { 6119677Slinton return (Boolean) (p->status == FINISHED); 6129677Slinton } 6139677Slinton 6149677Slinton /* 615*18230Slinton * Predicate to test if the reason the process stopped was because 616*18230Slinton * of a breakpoint. If so, as a side effect clear the local copy of 617*18230Slinton * signal handler associated with process. We must do this so as to 618*18230Slinton * not confuse future stepping or continuing by possibly concluding 619*18230Slinton * the process should continue with a SIGTRAP handler. 6209677Slinton */ 6219677Slinton 622*18230Slinton public boolean isbperr() 623*18230Slinton { 624*18230Slinton Process p; 625*18230Slinton boolean b; 626*18230Slinton 627*18230Slinton p = process; 628*18230Slinton if (p->status == STOPPED and p->signo == SIGTRAP) { 629*18230Slinton b = true; 630*18230Slinton p->sigstatus = 0; 631*18230Slinton } else { 632*18230Slinton b = false; 633*18230Slinton } 634*18230Slinton return b; 635*18230Slinton } 636*18230Slinton 637*18230Slinton /* 638*18230Slinton * Return the signal number that stopped the process. 639*18230Slinton */ 640*18230Slinton 641*18230Slinton public integer errnum (p) 6429677Slinton Process p; 6439677Slinton { 6449677Slinton return p->signo; 6459677Slinton } 6469677Slinton 647*18230Slinton /* 648*18230Slinton * Return the signal code associated with the signal. 649*18230Slinton */ 650*18230Slinton 651*18230Slinton public integer errcode (p) 65216931Ssam Process p; 65316931Ssam { 65416931Ssam return p->sigcode; 65516931Ssam } 65616931Ssam 6579677Slinton /* 6589677Slinton * Return the termination code of the process. 6599677Slinton */ 6609677Slinton 661*18230Slinton public integer exitcode (p) 6629677Slinton Process p; 6639677Slinton { 6649677Slinton return p->exitval; 6659677Slinton } 6669677Slinton 6679677Slinton /* 6689677Slinton * These routines are used to access the debuggee process from 6699677Slinton * outside this module. 6709677Slinton * 6719677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 67214757Slinton * The system generates an I/O error when a ptrace fails. During reads 67314757Slinton * these are ignored, during writes they are reported as an error, and 67414757Slinton * for anything else they cause a fatal error. 6759677Slinton */ 6769677Slinton 6779677Slinton extern Intfunc *onsyserr(); 6789677Slinton 6799677Slinton private badaddr; 68014757Slinton private read_err(), write_err(); 6819677Slinton 6829677Slinton /* 6839677Slinton * Read from the process' instruction area. 6849677Slinton */ 6859677Slinton 6869677Slinton public iread(buff, addr, nbytes) 6879677Slinton char *buff; 6889677Slinton Address addr; 6899677Slinton int nbytes; 6909677Slinton { 6919677Slinton Intfunc *f; 6929677Slinton 69314757Slinton f = onsyserr(EIO, read_err); 6949677Slinton badaddr = addr; 6959677Slinton if (coredump) { 6969677Slinton coredump_readtext(buff, addr, nbytes); 6979677Slinton } else { 6989677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 6999677Slinton } 7009677Slinton onsyserr(EIO, f); 7019677Slinton } 7029677Slinton 7039677Slinton /* 7049677Slinton * Write to the process' instruction area, usually in order to set 7059677Slinton * or unset a breakpoint. 7069677Slinton */ 7079677Slinton 7089677Slinton public iwrite(buff, addr, nbytes) 7099677Slinton char *buff; 7109677Slinton Address addr; 7119677Slinton int nbytes; 7129677Slinton { 7139677Slinton Intfunc *f; 7149677Slinton 7159677Slinton if (coredump) { 7169677Slinton error("no process to write to"); 7179677Slinton } 71814757Slinton f = onsyserr(EIO, write_err); 7199677Slinton badaddr = addr; 7209677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 7219677Slinton onsyserr(EIO, f); 7229677Slinton } 7239677Slinton 7249677Slinton /* 7259677Slinton * Read for the process' data area. 7269677Slinton */ 7279677Slinton 7289677Slinton public dread(buff, addr, nbytes) 7299677Slinton char *buff; 7309677Slinton Address addr; 7319677Slinton int nbytes; 7329677Slinton { 7339677Slinton Intfunc *f; 7349677Slinton 7359677Slinton badaddr = addr; 7369677Slinton if (coredump) { 737*18230Slinton f = onsyserr(EFAULT, read_err); 7389677Slinton coredump_readdata(buff, addr, nbytes); 739*18230Slinton onsyserr(EFAULT, f); 7409677Slinton } else { 741*18230Slinton f = onsyserr(EIO, read_err); 7429677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 743*18230Slinton onsyserr(EIO, f); 7449677Slinton } 7459677Slinton } 7469677Slinton 7479677Slinton /* 7489677Slinton * Write to the process' data area. 7499677Slinton */ 7509677Slinton 7519677Slinton public dwrite(buff, addr, nbytes) 7529677Slinton char *buff; 7539677Slinton Address addr; 7549677Slinton int nbytes; 7559677Slinton { 7569677Slinton Intfunc *f; 7579677Slinton 7589677Slinton if (coredump) { 7599677Slinton error("no process to write to"); 7609677Slinton } 76114757Slinton f = onsyserr(EIO, write_err); 7629677Slinton badaddr = addr; 7639677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 7649677Slinton onsyserr(EIO, f); 7659677Slinton } 7669677Slinton 7679677Slinton /* 76814757Slinton * Trap for errors in reading or writing to a process. 76914757Slinton * The current approach is to "ignore" read errors and complain 77014757Slinton * bitterly about write errors. 7719677Slinton */ 7729677Slinton 77314757Slinton private read_err() 7749677Slinton { 77511560Slinton /* 77614757Slinton * Ignore. 77711560Slinton */ 7789677Slinton } 7799677Slinton 78014757Slinton private write_err() 78114757Slinton { 78214757Slinton error("can't write to process (address 0x%x)", badaddr); 78314757Slinton } 78414757Slinton 7859677Slinton /* 7869677Slinton * Ptrace interface. 7879677Slinton */ 7889677Slinton 7899677Slinton /* 7909677Slinton * This magic macro enables us to look at the process' registers 79114757Slinton * in its user structure. 7929677Slinton */ 7939677Slinton 7949677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 7959677Slinton 7969677Slinton #define WMASK (~(sizeof(Word) - 1)) 7979677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 7989677Slinton 7999677Slinton #define FIRSTSIG SIGINT 8009677Slinton #define LASTSIG SIGQUIT 8019677Slinton #define ischild(pid) ((pid) == 0) 802*18230Slinton #define traceme() ptrace(0, 0, 0, 0) 8039677Slinton #define setrep(n) (1 << ((n)-1)) 8049677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 8059677Slinton 8069677Slinton /* 807*18230Slinton * Ptrace options (specified in first argument). 808*18230Slinton */ 809*18230Slinton 810*18230Slinton #define UREAD 3 /* read from process's user structure */ 811*18230Slinton #define UWRITE 6 /* write to process's user structure */ 812*18230Slinton #define IREAD 1 /* read from process's instruction space */ 813*18230Slinton #define IWRITE 4 /* write to process's instruction space */ 814*18230Slinton #define DREAD 2 /* read from process's data space */ 815*18230Slinton #define DWRITE 5 /* write to process's data space */ 816*18230Slinton #define CONT 7 /* continue stopped process */ 817*18230Slinton #define SSTEP 9 /* continue for approximately one instruction */ 818*18230Slinton #define PKILL 8 /* terminate the process */ 819*18230Slinton 820*18230Slinton /* 8219677Slinton * Start up a new process by forking and exec-ing the 8229677Slinton * given argument list, returning when the process is loaded 8239677Slinton * and ready to execute. The PROCESS information (pointed to 8249677Slinton * by the first argument) is appropriately filled. 8259677Slinton * 8269677Slinton * If the given PROCESS structure is associated with an already running 8279677Slinton * process, we terminate it. 8289677Slinton */ 8299677Slinton 8309677Slinton /* VARARGS2 */ 8319677Slinton private pstart(p, argv, infile, outfile) 8329677Slinton Process p; 8339677Slinton String argv[]; 8349677Slinton String infile; 8359677Slinton String outfile; 8369677Slinton { 8379677Slinton int status; 8389677Slinton 83916617Ssam if (p->pid != 0) { 84016617Ssam pterm(p); 841*18230Slinton cacheflush(p); 8429677Slinton } 843*18230Slinton fflush(stdout); 8449677Slinton psigtrace(p, SIGTRAP, true); 84514395Slinton p->pid = vfork(); 84614395Slinton if (p->pid == -1) { 8479677Slinton panic("can't fork"); 8489677Slinton } 8499677Slinton if (ischild(p->pid)) { 850*18230Slinton nocatcherrs(); 8519677Slinton traceme(); 8529677Slinton if (infile != nil) { 85316617Ssam infrom(infile); 8549677Slinton } 8559677Slinton if (outfile != nil) { 85616617Ssam outto(outfile); 8579677Slinton } 85811832Slinton execv(argv[0], argv); 85911172Slinton _exit(1); 8609677Slinton } 8619677Slinton pwait(p->pid, &status); 8629677Slinton getinfo(p, status); 8639677Slinton if (p->status != STOPPED) { 864*18230Slinton beginerrmsg(); 865*18230Slinton fprintf(stderr, "warning: cannot execute %s\n", argv[0]); 866*18230Slinton } else { 867*18230Slinton ptraced(p->pid); 8689677Slinton } 8699677Slinton } 8709677Slinton 8719677Slinton /* 87216617Ssam * Terminate a ptrace'd process. 87316617Ssam */ 87416617Ssam 87516617Ssam public pterm (p) 87616617Ssam Process p; 87716617Ssam { 87816617Ssam integer status; 87916617Ssam 88016617Ssam if (p != nil and p->pid != 0) { 881*18230Slinton ptrace(PKILL, p->pid, 0, 0); 88216617Ssam pwait(p->pid, &status); 88316617Ssam unptraced(p->pid); 88416617Ssam } 88516617Ssam } 88616617Ssam 88716617Ssam /* 88811867Slinton * Continue a stopped process. The first argument points to a Process 88911867Slinton * structure. Before the process is restarted it's user area is modified 89011867Slinton * according to the values in the structure. When this routine finishes, 8919677Slinton * the structure has the new values from the process's user area. 8929677Slinton * 8939677Slinton * Pcont terminates when the process stops with a signal pending that 8949677Slinton * is being traced (via psigtrace), or when the process terminates. 8959677Slinton */ 8969677Slinton 89711867Slinton private pcont(p, signo) 8989677Slinton Process p; 89911867Slinton int signo; 9009677Slinton { 90116617Ssam int s, status; 9029677Slinton 9039677Slinton if (p->pid == 0) { 904*18230Slinton error("program is not active"); 9059677Slinton } 90616617Ssam s = signo; 9079677Slinton do { 90816617Ssam setinfo(p, s); 90916617Ssam if (traceexec) { 91016617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n", 91116617Ssam p->reg[PROGCTR], s, p->signo); 91216617Ssam fflush(stdout); 91316617Ssam } 9149677Slinton sigs_off(); 915*18230Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 91614395Slinton panic("error %d trying to continue process", errno); 9179677Slinton } 9189677Slinton pwait(p->pid, &status); 9199677Slinton sigs_on(); 9209677Slinton getinfo(p, status); 921*18230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 922*18230Slinton printf("!! ignored signal %d at 0x%x\n", 923*18230Slinton p->signo, p->reg[PROGCTR]); 92416617Ssam fflush(stdout); 92516617Ssam } 92616617Ssam s = p->signo; 9279677Slinton } while (p->status == STOPPED and not istraced(p)); 92816617Ssam if (traceexec) { 92916617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 93016617Ssam fflush(stdout); 93116617Ssam } 9329677Slinton } 9339677Slinton 9349677Slinton /* 9359677Slinton * Single step as best ptrace can. 9369677Slinton */ 9379677Slinton 93816617Ssam public pstep(p, signo) 9399677Slinton Process p; 94016617Ssam integer signo; 9419677Slinton { 942*18230Slinton int s, status; 9439677Slinton 944*18230Slinton s = signo; 945*18230Slinton do { 946*18230Slinton setinfo(p, s); 947*18230Slinton if (traceexec) { 948*18230Slinton printf("!! pstep from 0x%x with signal %d (%d)\n", 949*18230Slinton p->reg[PROGCTR], s, p->signo); 950*18230Slinton fflush(stdout); 951*18230Slinton } 952*18230Slinton sigs_off(); 953*18230Slinton if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { 954*18230Slinton panic("error %d trying to step process", errno); 955*18230Slinton } 956*18230Slinton pwait(p->pid, &status); 957*18230Slinton sigs_on(); 958*18230Slinton getinfo(p, status); 959*18230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 960*18230Slinton printf("!! pstep ignored signal %d at 0x%x\n", 961*18230Slinton p->signo, p->reg[PROGCTR]); 962*18230Slinton fflush(stdout); 963*18230Slinton } 964*18230Slinton s = p->signo; 965*18230Slinton } while (p->status == STOPPED and not istraced(p)); 96616617Ssam if (traceexec) { 967*18230Slinton printf("!! pstep to 0x%x on signal %d\n", 968*18230Slinton p->reg[PROGCTR], p->signo); 96916617Ssam fflush(stdout); 97016617Ssam } 97116617Ssam if (p->status != STOPPED) { 972*18230Slinton if (p->exitval == 0) { 973*18230Slinton error("program exited\n"); 974*18230Slinton } else { 975*18230Slinton error("program exited with code %d\n", p->exitval); 976*18230Slinton } 97716617Ssam } 9789677Slinton } 9799677Slinton 9809677Slinton /* 9819677Slinton * Return from execution when the given signal is pending. 9829677Slinton */ 9839677Slinton 9849677Slinton public psigtrace(p, sig, sw) 9859677Slinton Process p; 9869677Slinton int sig; 9879677Slinton Boolean sw; 9889677Slinton { 9899677Slinton if (sw) { 9909677Slinton p->sigset |= setrep(sig); 9919677Slinton } else { 9929677Slinton p->sigset &= ~setrep(sig); 9939677Slinton } 9949677Slinton } 9959677Slinton 9969677Slinton /* 9979677Slinton * Don't catch any signals. 9989677Slinton * Particularly useful when letting a process finish uninhibited. 9999677Slinton */ 10009677Slinton 10019677Slinton public unsetsigtraces(p) 10029677Slinton Process p; 10039677Slinton { 10049677Slinton p->sigset = 0; 10059677Slinton } 10069677Slinton 10079677Slinton /* 10089677Slinton * Turn off attention to signals not being caught. 10099677Slinton */ 10109677Slinton 10119677Slinton private Intfunc *sigfunc[NSIG]; 10129677Slinton 10139677Slinton private sigs_off() 10149677Slinton { 10159677Slinton register int i; 10169677Slinton 10179677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10189677Slinton if (i != SIGKILL) { 10199677Slinton sigfunc[i] = signal(i, SIG_IGN); 10209677Slinton } 10219677Slinton } 10229677Slinton } 10239677Slinton 10249677Slinton /* 10259677Slinton * Turn back on attention to signals. 10269677Slinton */ 10279677Slinton 10289677Slinton private sigs_on() 10299677Slinton { 10309677Slinton register int i; 10319677Slinton 10329677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10339677Slinton if (i != SIGKILL) { 10349677Slinton signal(i, sigfunc[i]); 10359677Slinton } 10369677Slinton } 10379677Slinton } 10389677Slinton 10399677Slinton /* 10409677Slinton * Get process information from user area. 10419677Slinton */ 10429677Slinton 10439677Slinton private int rloc[] ={ 10449677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 10459677Slinton }; 10469677Slinton 10479677Slinton private getinfo(p, status) 10489677Slinton register Process p; 10499677Slinton register int status; 10509677Slinton { 10519677Slinton register int i; 105216617Ssam Address addr; 10539677Slinton 10549677Slinton p->signo = (status&0177); 10559677Slinton p->exitval = ((status >> 8)&0377); 10569677Slinton if (p->signo != STOPPED) { 10579677Slinton p->status = FINISHED; 105814757Slinton p->pid = 0; 105916617Ssam p->reg[PROGCTR] = 0; 10609677Slinton } else { 10619677Slinton p->status = p->signo; 10629677Slinton p->signo = p->exitval; 1063*18230Slinton p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0); 10649677Slinton p->exitval = 0; 1065*18230Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 10669677Slinton for (i = 0; i < NREG; i++) { 1067*18230Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 10689677Slinton p->oreg[i] = p->reg[i]; 10699677Slinton } 107011768Slinton savetty(stdout, &(p->ttyinfo)); 107116617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); 1072*18230Slinton p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); 10739677Slinton } 10749677Slinton } 10759677Slinton 10769677Slinton /* 10779677Slinton * Set process's user area information from given process structure. 10789677Slinton */ 10799677Slinton 108011867Slinton private setinfo(p, signo) 10819677Slinton register Process p; 108211867Slinton int signo; 10839677Slinton { 10849677Slinton register int i; 10859677Slinton register int r; 10869677Slinton 108714757Slinton if (signo == DEFSIG) { 108816617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { 108914757Slinton p->signo = 0; 109014757Slinton } 109114757Slinton } else { 109211867Slinton p->signo = signo; 10939677Slinton } 10949677Slinton for (i = 0; i < NREG; i++) { 10959677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 1096*18230Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 10979677Slinton } 10989677Slinton } 109911768Slinton restoretty(stdout, &(p->ttyinfo)); 11009677Slinton } 11019677Slinton 11029677Slinton /* 110316617Ssam * Return the address associated with the current signal. 110416617Ssam * (Plus two since the address points to the beginning of a procedure). 110516617Ssam */ 110616617Ssam 110716617Ssam public Address usignal (p) 110816617Ssam Process p; 110916617Ssam { 111016617Ssam Address r; 111116617Ssam 111216617Ssam r = p->sigstatus; 111316617Ssam if (r != 0 and r != 1) { 111416617Ssam r += 2; 111516617Ssam } 111616617Ssam return r; 111716617Ssam } 111816617Ssam 111916617Ssam /* 11209677Slinton * Structure for reading and writing by words, but dealing with bytes. 11219677Slinton */ 11229677Slinton 11239677Slinton typedef union { 11249677Slinton Word pword; 11259677Slinton Byte pbyte[sizeof(Word)]; 11269677Slinton } Pword; 11279677Slinton 11289677Slinton /* 11299677Slinton * Read (write) from (to) the process' address space. 11309677Slinton * We must deal with ptrace's inability to look anywhere other 11319677Slinton * than at a word boundary. 11329677Slinton */ 11339677Slinton 11349677Slinton private Word fetch(); 11359677Slinton private store(); 11369677Slinton 11379677Slinton private pio(p, op, seg, buff, addr, nbytes) 11389677Slinton Process p; 11399677Slinton PioOp op; 11409677Slinton PioSeg seg; 11419677Slinton char *buff; 11429677Slinton Address addr; 11439677Slinton int nbytes; 11449677Slinton { 11459677Slinton register int i; 11469677Slinton register Address newaddr; 11479677Slinton register char *cp; 11489677Slinton char *bufend; 11499677Slinton Pword w; 11509677Slinton Address wordaddr; 11519677Slinton int byteoff; 11529677Slinton 11539677Slinton if (p->status != STOPPED) { 11549677Slinton error("program is not active"); 11559677Slinton } 11569677Slinton cp = buff; 11579677Slinton newaddr = addr; 11589677Slinton wordaddr = (newaddr&WMASK); 11599677Slinton if (wordaddr != newaddr) { 11609677Slinton w.pword = fetch(p, seg, wordaddr); 11619677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 11629677Slinton if (op == PREAD) { 11639677Slinton *cp++ = w.pbyte[i]; 11649677Slinton } else { 11659677Slinton w.pbyte[i] = *cp++; 11669677Slinton } 11679677Slinton nbytes--; 11689677Slinton } 11699677Slinton if (op == PWRITE) { 11709677Slinton store(p, seg, wordaddr, w.pword); 11719677Slinton } 11729677Slinton newaddr = wordaddr + sizeof(Word); 11739677Slinton } 11749677Slinton byteoff = (nbytes&(~WMASK)); 11759677Slinton nbytes -= byteoff; 11769677Slinton bufend = cp + nbytes; 11779677Slinton while (cp < bufend) { 11789677Slinton if (op == PREAD) { 11799677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 11809677Slinton } else { 11819677Slinton store(p, seg, newaddr, *((Word *) cp)); 11829677Slinton } 11839677Slinton cp += sizeof(Word); 11849677Slinton newaddr += sizeof(Word); 11859677Slinton } 11869677Slinton if (byteoff > 0) { 11879677Slinton w.pword = fetch(p, seg, newaddr); 11889677Slinton for (i = 0; i < byteoff; i++) { 11899677Slinton if (op == PREAD) { 11909677Slinton *cp++ = w.pbyte[i]; 11919677Slinton } else { 11929677Slinton w.pbyte[i] = *cp++; 11939677Slinton } 11949677Slinton } 11959677Slinton if (op == PWRITE) { 11969677Slinton store(p, seg, newaddr, w.pword); 11979677Slinton } 11989677Slinton } 11999677Slinton } 12009677Slinton 12019677Slinton /* 12029677Slinton * Get a word from a process at the given address. 12039677Slinton * The address is assumed to be on a word boundary. 12049677Slinton * 12059677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 12069677Slinton * to the instruction space since it is assumed to be pure. 12079677Slinton * 12089677Slinton * It is necessary to use a write-through scheme so that 12099677Slinton * breakpoints right next to each other don't interfere. 12109677Slinton */ 12119677Slinton 12129677Slinton private Integer nfetchs, nreads, nwrites; 12139677Slinton 12149677Slinton private Word fetch(p, seg, addr) 12159677Slinton Process p; 12169677Slinton PioSeg seg; 12179677Slinton register int addr; 12189677Slinton { 12199677Slinton register CacheWord *wp; 12209677Slinton register Word w; 12219677Slinton 12229677Slinton switch (seg) { 12239677Slinton case TEXTSEG: 12249677Slinton ++nfetchs; 12259677Slinton wp = &p->word[cachehash(addr)]; 12269677Slinton if (addr == 0 or wp->addr != addr) { 12279677Slinton ++nreads; 1228*18230Slinton w = ptrace(IREAD, p->pid, addr, 0); 12299677Slinton wp->addr = addr; 12309677Slinton wp->val = w; 12319677Slinton } else { 12329677Slinton w = wp->val; 12339677Slinton } 12349677Slinton break; 12359677Slinton 12369677Slinton case DATASEG: 1237*18230Slinton w = ptrace(DREAD, p->pid, addr, 0); 12389677Slinton break; 12399677Slinton 12409677Slinton default: 12419677Slinton panic("fetch: bad seg %d", seg); 12429677Slinton /* NOTREACHED */ 12439677Slinton } 12449677Slinton return w; 12459677Slinton } 12469677Slinton 12479677Slinton /* 12489677Slinton * Put a word into the process' address space at the given address. 12499677Slinton * The address is assumed to be on a word boundary. 12509677Slinton */ 12519677Slinton 12529677Slinton private store(p, seg, addr, data) 12539677Slinton Process p; 12549677Slinton PioSeg seg; 12559677Slinton int addr; 12569677Slinton Word data; 12579677Slinton { 12589677Slinton register CacheWord *wp; 12599677Slinton 12609677Slinton switch (seg) { 12619677Slinton case TEXTSEG: 12629677Slinton ++nwrites; 12639677Slinton wp = &p->word[cachehash(addr)]; 12649677Slinton wp->addr = addr; 12659677Slinton wp->val = data; 1266*18230Slinton ptrace(IWRITE, p->pid, addr, data); 12679677Slinton break; 12689677Slinton 12699677Slinton case DATASEG: 1270*18230Slinton ptrace(DWRITE, p->pid, addr, data); 12719677Slinton break; 12729677Slinton 12739677Slinton default: 12749677Slinton panic("store: bad seg %d", seg); 12759677Slinton /* NOTREACHED */ 12769677Slinton } 12779677Slinton } 12789677Slinton 1279*18230Slinton /* 1280*18230Slinton * Flush the instruction cache associated with a process. 1281*18230Slinton */ 1282*18230Slinton 1283*18230Slinton private cacheflush (p) 1284*18230Slinton Process p; 1285*18230Slinton { 1286*18230Slinton bzero(p->word, sizeof(p->word)); 1287*18230Slinton } 1288*18230Slinton 12899677Slinton public printptraceinfo() 12909677Slinton { 12919677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 12929677Slinton } 12939677Slinton 12949677Slinton /* 129516617Ssam * Redirect input. 129616617Ssam * Assuming this is called from a child, we should be careful to avoid 129716617Ssam * (possibly) shared standard I/O buffers. 12989677Slinton */ 12999677Slinton 130016617Ssam private infrom (filename) 130116617Ssam String filename; 130216617Ssam { 130316617Ssam Fileid in; 130416617Ssam 130516617Ssam in = open(filename, 0); 130616617Ssam if (in == -1) { 130716617Ssam write(2, "can't read ", 11); 130816617Ssam write(2, filename, strlen(filename)); 130916617Ssam write(2, "\n", 1); 131016617Ssam _exit(1); 131116617Ssam } 131216617Ssam fswap(0, in); 131316617Ssam } 131416617Ssam 131516617Ssam /* 131616617Ssam * Redirect standard output. 131716617Ssam * Same assumptions as for "infrom" above. 131816617Ssam */ 131916617Ssam 132016617Ssam private outto (filename) 132116617Ssam String filename; 132216617Ssam { 132316617Ssam Fileid out; 132416617Ssam 132516617Ssam out = creat(filename, 0666); 132616617Ssam if (out == -1) { 132716617Ssam write(2, "can't write ", 12); 132816617Ssam write(2, filename, strlen(filename)); 132916617Ssam write(2, "\n", 1); 133016617Ssam _exit(1); 133116617Ssam } 133216617Ssam fswap(1, out); 133316617Ssam } 133416617Ssam 133516617Ssam /* 133616617Ssam * Swap file numbers, useful for redirecting standard input or output. 133716617Ssam */ 133816617Ssam 13399677Slinton private fswap(oldfd, newfd) 134016617Ssam Fileid oldfd; 134116617Ssam Fileid newfd; 13429677Slinton { 13439677Slinton if (oldfd != newfd) { 13449677Slinton close(oldfd); 13459677Slinton dup(newfd); 13469677Slinton close(newfd); 13479677Slinton } 13489677Slinton } 134916928Ssam 135016928Ssam /* 1351*18230Slinton * Signal name manipulation. 135216928Ssam */ 1353*18230Slinton 1354*18230Slinton private String signames[NSIG] = { 1355*18230Slinton 0, 1356*18230Slinton "HUP", "INT", "QUIT", "ILL", "TRAP", 1357*18230Slinton "IOT", "EMT", "FPE", "KILL", "BUS", 1358*18230Slinton "SEGV", "SYS", "PIPE", "ALRM", "TERM", 1359*18230Slinton 0, "STOP", "TSTP", "CONT", "CHLD", 1360*18230Slinton "TTIN", "TTOU", "TINT", "XCPU", "XFSZ", 136116928Ssam }; 136216928Ssam 136316928Ssam /* 1364*18230Slinton * Get the signal number associated with a given name. 1365*18230Slinton * The name is first translated to upper case if necessary. 136616928Ssam */ 1367*18230Slinton 1368*18230Slinton public integer siglookup (s) 136916928Ssam String s; 137016928Ssam { 1371*18230Slinton register char *p, *q; 1372*18230Slinton char buf[100]; 1373*18230Slinton integer i; 137416928Ssam 1375*18230Slinton p = s; 1376*18230Slinton q = buf; 1377*18230Slinton while (*p != '\0') { 1378*18230Slinton if (*p >= 'a' and *p <= 'z') { 1379*18230Slinton *q = (*p - 'a') + 'A'; 1380*18230Slinton } else { 1381*18230Slinton *q = *p; 1382*18230Slinton } 1383*18230Slinton ++p; 1384*18230Slinton ++q; 1385*18230Slinton } 1386*18230Slinton *q = '\0'; 1387*18230Slinton p = buf; 1388*18230Slinton if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') { 1389*18230Slinton p += 3; 1390*18230Slinton } 1391*18230Slinton i = 1; 1392*18230Slinton for (;;) { 1393*18230Slinton if (i >= sizeof(signames) div sizeof(signames[0])) { 1394*18230Slinton error("signal \"%s\" unknown", s); 1395*18230Slinton i = 0; 1396*18230Slinton break; 1397*18230Slinton } 1398*18230Slinton if (signames[i] != nil and streq(signames[i], p)) { 1399*18230Slinton break; 1400*18230Slinton } 1401*18230Slinton ++i; 1402*18230Slinton } 1403*18230Slinton return i; 140416928Ssam } 140516928Ssam 140616928Ssam /* 1407*18230Slinton * Print all signals being ignored by the debugger. 1408*18230Slinton * These signals are auotmatically 140916928Ssam * passed on to the debugged process. 141016928Ssam */ 1411*18230Slinton 1412*18230Slinton public printsigsignored (p) 141316931Ssam Process p; 141416928Ssam { 141516931Ssam printsigs(~p->sigset); 141616928Ssam } 141716928Ssam 141816928Ssam /* 141916928Ssam * Print all signals being intercepted by 142016928Ssam * the debugger for the specified process. 142116928Ssam */ 1422*18230Slinton 142316931Ssam public printsigscaught(p) 142416931Ssam Process p; 142516928Ssam { 142616931Ssam printsigs(p->sigset); 142716931Ssam } 142816931Ssam 1429*18230Slinton private printsigs (set) 1430*18230Slinton integer set; 143116931Ssam { 1432*18230Slinton integer s; 1433*18230Slinton char separator[2]; 143416931Ssam 1435*18230Slinton separator[0] = '\0'; 1436*18230Slinton for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) { 1437*18230Slinton if (set & setrep(s)) { 1438*18230Slinton if (signames[s] != nil) { 1439*18230Slinton printf("%s%s", separator, signames[s]); 1440*18230Slinton separator[0] = ' '; 1441*18230Slinton separator[1] = '\0'; 1442*18230Slinton } 144316928Ssam } 1444*18230Slinton } 1445*18230Slinton if (separator[0] == ' ') { 144616931Ssam putchar('\n'); 144716931Ssam } 144816928Ssam } 1449