19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*16928Ssam static char sccsid[] = "@(#)process.c 1.14 (Berkeley) 08/12/84"; 49677Slinton 59677Slinton /* 69677Slinton * Process management. 79677Slinton * 89677Slinton * This module contains the routines to manage the execution and 99677Slinton * tracing of the debuggee process. 109677Slinton */ 119677Slinton 129677Slinton #include "defs.h" 139677Slinton #include "process.h" 149677Slinton #include "machine.h" 159677Slinton #include "events.h" 169677Slinton #include "tree.h" 1714757Slinton #include "eval.h" 189677Slinton #include "operators.h" 199677Slinton #include "source.h" 209677Slinton #include "object.h" 219677Slinton #include "mappings.h" 229677Slinton #include "main.h" 239677Slinton #include "coredump.h" 249677Slinton #include <signal.h> 259677Slinton #include <errno.h> 269677Slinton #include <sys/param.h> 2716617Ssam #include <sys/dir.h> 2816617Ssam #include <sys/user.h> 299843Slinton #include <machine/reg.h> 309677Slinton #include <sys/stat.h> 319677Slinton 329677Slinton #ifndef public 339677Slinton 349677Slinton typedef struct Process *Process; 359677Slinton 369677Slinton Process process; 379677Slinton 3814757Slinton #define DEFSIG -1 3914757Slinton 409677Slinton #include "machine.h" 419677Slinton 429677Slinton #endif 439677Slinton 449677Slinton #define NOTSTARTED 1 459677Slinton #define STOPPED 0177 469677Slinton #define FINISHED 0 479677Slinton 489677Slinton /* 4916617Ssam * A cache of the instruction segment is kept to reduce the number 5016617Ssam * of system calls. Might be better just to read the entire 5116617Ssam * code space into memory. 529677Slinton */ 539677Slinton 549677Slinton #define CSIZE 1003 /* size of instruction cache */ 559677Slinton 569677Slinton typedef struct { 579677Slinton Word addr; 589677Slinton Word val; 599677Slinton } CacheWord; 609677Slinton 619677Slinton /* 629677Slinton * This structure holds the information we need from the user structure. 639677Slinton */ 649677Slinton 659677Slinton struct Process { 669677Slinton int pid; /* process being traced */ 6711768Slinton int mask; /* process status word */ 6811768Slinton Word reg[NREG]; /* process' registers */ 699677Slinton Word oreg[NREG]; /* registers when process last stopped */ 709677Slinton short status; /* either STOPPED or FINISHED */ 719677Slinton short signo; /* signal that stopped process */ 729677Slinton int exitval; /* return value from exit() */ 739677Slinton long sigset; /* bit array of traced signals */ 749677Slinton CacheWord word[CSIZE]; /* text segment cache */ 7511768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 7616617Ssam Address sigstatus; /* process' handler for current signal */ 779677Slinton }; 789677Slinton 799677Slinton /* 809677Slinton * These definitions are for the arguments to "pio". 819677Slinton */ 829677Slinton 839677Slinton typedef enum { PREAD, PWRITE } PioOp; 849677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 859677Slinton 869677Slinton private struct Process pbuf; 879677Slinton 8813841Slinton #define MAXNCMDARGS 100 /* maximum number of arguments to RUN */ 899677Slinton 9014395Slinton extern int errno; 9114395Slinton 929677Slinton private Boolean just_started; 939677Slinton private int argc; 949677Slinton private String argv[MAXNCMDARGS]; 959677Slinton private String infile, outfile; 969677Slinton 979677Slinton /* 989677Slinton * Initialize process information. 999677Slinton */ 1009677Slinton 1019677Slinton public process_init() 1029677Slinton { 1039677Slinton register Integer i; 1049677Slinton Char buf[10]; 1059677Slinton 1069677Slinton process = &pbuf; 1079677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1089677Slinton setsigtrace(); 1099677Slinton for (i = 0; i < NREG; i++) { 1109677Slinton sprintf(buf, "$r%d", i); 1119677Slinton defregname(identname(buf, false), i); 1129677Slinton } 1139677Slinton defregname(identname("$ap", true), ARGP); 1149677Slinton defregname(identname("$fp", true), FRP); 1159677Slinton defregname(identname("$sp", true), STKP); 1169677Slinton defregname(identname("$pc", true), PROGCTR); 1179677Slinton if (coredump) { 1189677Slinton coredump_readin(process->mask, process->reg, process->signo); 11912484Slinton pc = process->reg[PROGCTR]; 12012484Slinton getsrcpos(); 1219677Slinton } 12212484Slinton arginit(); 1239677Slinton } 1249677Slinton 1259677Slinton /* 1269677Slinton * Routines to get at process information from outside this module. 1279677Slinton */ 1289677Slinton 1299677Slinton public Word reg(n) 1309677Slinton Integer n; 1319677Slinton { 1329677Slinton register Word w; 1339677Slinton 1349677Slinton if (n == NREG) { 1359677Slinton w = process->mask; 1369677Slinton } else { 1379677Slinton w = process->reg[n]; 1389677Slinton } 1399677Slinton return w; 1409677Slinton } 1419677Slinton 1429677Slinton public setreg(n, w) 1439677Slinton Integer n; 1449677Slinton Word w; 1459677Slinton { 1469677Slinton process->reg[n] = w; 1479677Slinton } 1489677Slinton 1499677Slinton /* 1509677Slinton * Begin execution. 1519677Slinton * 1529677Slinton * We set a breakpoint at the end of the code so that the 1539677Slinton * process data doesn't disappear after the program terminates. 1549677Slinton */ 1559677Slinton 1569677Slinton private Boolean remade(); 1579677Slinton 1589677Slinton public start(argv, infile, outfile) 1599677Slinton String argv[]; 1609677Slinton String infile, outfile; 1619677Slinton { 1629677Slinton String pargv[4]; 1639677Slinton Node cond; 1649677Slinton 1659677Slinton if (coredump) { 1669677Slinton coredump = false; 1679677Slinton fclose(corefile); 1689677Slinton coredump_close(); 1699677Slinton } 1709677Slinton if (argv == nil) { 1719677Slinton argv = pargv; 1729677Slinton pargv[0] = objname; 1739677Slinton pargv[1] = nil; 1749677Slinton } else { 1759677Slinton argv[argc] = nil; 1769677Slinton } 1779677Slinton if (remade(objname)) { 1789677Slinton reinit(argv, infile, outfile); 1799677Slinton } 1809677Slinton pstart(process, argv, infile, outfile); 1819677Slinton if (process->status == STOPPED) { 1829677Slinton pc = 0; 18316617Ssam setcurfunc(program); 1849677Slinton if (objsize != 0) { 1859677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1869677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1879677Slinton } 1889677Slinton } 1899677Slinton } 1909677Slinton 1919677Slinton /* 1929677Slinton * Check to see if the object file has changed since the symbolic 1939677Slinton * information last was read. 1949677Slinton */ 1959677Slinton 1969677Slinton private time_t modtime; 1979677Slinton 1989677Slinton private Boolean remade(filename) 1999677Slinton String filename; 2009677Slinton { 2019677Slinton struct stat s; 2029677Slinton Boolean b; 2039677Slinton 2049677Slinton stat(filename, &s); 2059677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2069677Slinton modtime = s.st_mtime; 2079677Slinton return b; 2089677Slinton } 2099677Slinton 2109677Slinton /* 2119677Slinton * Set up what signals we want to trace. 2129677Slinton */ 2139677Slinton 2149677Slinton private setsigtrace() 2159677Slinton { 2169677Slinton register Integer i; 2179677Slinton register Process p; 2189677Slinton 2199677Slinton p = process; 2209677Slinton for (i = 1; i <= NSIG; i++) { 2219677Slinton psigtrace(p, i, true); 2229677Slinton } 2239677Slinton psigtrace(p, SIGHUP, false); 2249677Slinton psigtrace(p, SIGKILL, false); 2259677Slinton psigtrace(p, SIGALRM, false); 2269677Slinton psigtrace(p, SIGTSTP, false); 2279677Slinton psigtrace(p, SIGCONT, false); 2289677Slinton psigtrace(p, SIGCHLD, false); 2299677Slinton } 2309677Slinton 2319677Slinton /* 2329677Slinton * Initialize the argument list. 2339677Slinton */ 2349677Slinton 2359677Slinton public arginit() 2369677Slinton { 2379677Slinton infile = nil; 2389677Slinton outfile = nil; 2399677Slinton argv[0] = objname; 2409677Slinton argc = 1; 2419677Slinton } 2429677Slinton 2439677Slinton /* 2449677Slinton * Add an argument to the list for the debuggee. 2459677Slinton */ 2469677Slinton 2479677Slinton public newarg(arg) 2489677Slinton String arg; 2499677Slinton { 2509677Slinton if (argc >= MAXNCMDARGS) { 2519677Slinton error("too many arguments"); 2529677Slinton } 2539677Slinton argv[argc++] = arg; 2549677Slinton } 2559677Slinton 2569677Slinton /* 2579677Slinton * Set the standard input for the debuggee. 2589677Slinton */ 2599677Slinton 2609677Slinton public inarg(filename) 2619677Slinton String filename; 2629677Slinton { 2639677Slinton if (infile != nil) { 2649677Slinton error("multiple input redirects"); 2659677Slinton } 2669677Slinton infile = filename; 2679677Slinton } 2689677Slinton 2699677Slinton /* 2709677Slinton * Set the standard output for the debuggee. 2719677Slinton * Probably should check to avoid overwriting an existing file. 2729677Slinton */ 2739677Slinton 2749677Slinton public outarg(filename) 2759677Slinton String filename; 2769677Slinton { 2779677Slinton if (outfile != nil) { 2789677Slinton error("multiple output redirect"); 2799677Slinton } 2809677Slinton outfile = filename; 2819677Slinton } 2829677Slinton 2839677Slinton /* 2849677Slinton * Start debuggee executing. 2859677Slinton */ 2869677Slinton 2879677Slinton public run() 2889677Slinton { 2899677Slinton process->status = STOPPED; 2909677Slinton fixbps(); 2919677Slinton curline = 0; 2929677Slinton start(argv, infile, outfile); 2939677Slinton just_started = true; 2949677Slinton isstopped = false; 29514757Slinton cont(0); 2969677Slinton } 2979677Slinton 2989677Slinton /* 2999677Slinton * Continue execution wherever we left off. 3009677Slinton * 3019677Slinton * Note that this routine never returns. Eventually bpact() will fail 3029677Slinton * and we'll call printstatus or step will call it. 3039677Slinton */ 3049677Slinton 3059677Slinton typedef int Intfunc(); 3069677Slinton 3079677Slinton private Intfunc *dbintr; 3089677Slinton private intr(); 3099677Slinton 3109677Slinton #define succeeds == true 3119677Slinton #define fails == false 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; 3379677Slinton if (bpact() fails) { 3389677Slinton printstatus(); 3399677Slinton } 3409677Slinton } 34111867Slinton stepover(); 3429677Slinton } 3439677Slinton /* NOTREACHED */ 3449677Slinton } 3459677Slinton 3469677Slinton /* 3479677Slinton * This routine is called if we get an interrupt while "running" px 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 3529677Slinton * 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) { 38211867Slinton error("program unexpectedly exited with %d", p->exitval); 38311867Slinton } 38411832Slinton } 3859677Slinton } 3869677Slinton 3879677Slinton /* 3889677Slinton * Continue execution up to the next source line. 3899677Slinton * 3909677Slinton * There are two ways to define the next source line depending on what 3919677Slinton * is desired when a procedure or function call is encountered. Step 3929677Slinton * stops at the beginning of the procedure or call; next skips over it. 3939677Slinton */ 3949677Slinton 3959677Slinton /* 3969677Slinton * Stepc is what is called when the step command is given. 3979677Slinton * It has to play with the "isstopped" information. 3989677Slinton */ 3999677Slinton 4009677Slinton public stepc() 4019677Slinton { 4029677Slinton if (not isstopped) { 4039677Slinton error("can't continue execution"); 4049677Slinton } 4059677Slinton isstopped = false; 4069677Slinton dostep(false); 4079677Slinton isstopped = true; 4089677Slinton } 4099677Slinton 4109677Slinton public next() 4119677Slinton { 41216617Ssam Address oldfrp, newfrp; 41316617Ssam 4149677Slinton if (not isstopped) { 4159677Slinton error("can't continue execution"); 4169677Slinton } 4179677Slinton isstopped = false; 41816617Ssam oldfrp = reg(FRP); 41916617Ssam do { 42016617Ssam dostep(true); 42116617Ssam pc = reg(PROGCTR); 42216617Ssam newfrp = reg(FRP); 42316617Ssam } while (newfrp < oldfrp and newfrp != 0); 4249677Slinton isstopped = true; 4259677Slinton } 4269677Slinton 42711867Slinton /* 42816617Ssam * Continue execution until the current function returns, or, 42916617Ssam * if the given argument is non-nil, until execution returns to 43016617Ssam * somewhere within the given function. 43116617Ssam */ 43216617Ssam 43316617Ssam public rtnfunc (f) 43416617Ssam Symbol f; 43516617Ssam { 43616617Ssam Address addr; 43716617Ssam Symbol t; 43816617Ssam 43916617Ssam if (not isstopped) { 44016617Ssam error("can't continue execution"); 44116617Ssam } else if (f != nil and not isactive(f)) { 44216617Ssam error("%s is not active", symname(f)); 44316617Ssam } else { 44416617Ssam addr = return_addr(); 44516617Ssam if (addr == nil) { 44616617Ssam error("no place to return to"); 44716617Ssam } else { 44816617Ssam isstopped = false; 44916617Ssam contto(addr); 45016617Ssam if (f != nil) { 45116617Ssam for (;;) { 45216617Ssam t = whatblock(pc); 45316617Ssam addr = return_addr(); 45416617Ssam if (t == f or addr == nil) break; 45516617Ssam contto(addr); 45616617Ssam } 45716617Ssam } 45816617Ssam if (bpact() fails) { 45916617Ssam isstopped = true; 46016617Ssam printstatus(); 46116617Ssam } 46216617Ssam } 46316617Ssam } 46416617Ssam } 46516617Ssam 46616617Ssam /* 46711867Slinton * Single-step over the current machine instruction. 46811867Slinton * 46911867Slinton * If we're single-stepping by source line we want to step to the 47011867Slinton * next source line. Otherwise we're going to continue so there's 47111867Slinton * no reason to do all the work necessary to single-step to the next 47211867Slinton * source line. 47311867Slinton */ 47411867Slinton 47516617Ssam public stepover() 4769677Slinton { 47711867Slinton Boolean b; 47811867Slinton 47916617Ssam if (traceexec) { 48016617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); 48116617Ssam } 48211867Slinton if (single_stepping) { 48311867Slinton dostep(false); 48411867Slinton } else { 48511867Slinton b = inst_tracing; 48611867Slinton inst_tracing = true; 48711867Slinton dostep(false); 48811867Slinton inst_tracing = b; 48911867Slinton } 49016617Ssam if (traceexec) { 49116617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); 49216617Ssam } 4939677Slinton } 4949677Slinton 4959677Slinton /* 4969677Slinton * Resume execution up to the given address. It is assumed that 4979677Slinton * no breakpoints exist between the current address and the one 4989677Slinton * we're stepping to. This saves us from setting all the breakpoints. 4999677Slinton */ 5009677Slinton 5019677Slinton public stepto(addr) 5029677Slinton Address addr; 5039677Slinton { 50416617Ssam xto(addr, false); 50516617Ssam } 50616617Ssam 50716617Ssam private contto (addr) 50816617Ssam Address addr; 50916617Ssam { 51016617Ssam xto(addr, true); 51116617Ssam } 51216617Ssam 51316617Ssam private xto (addr, catchbps) 51416617Ssam Address addr; 51516617Ssam boolean catchbps; 51616617Ssam { 51716617Ssam Address curpc; 51816617Ssam 51916617Ssam if (catchbps) { 52016617Ssam stepover(); 5219677Slinton } 52216617Ssam curpc = process->reg[PROGCTR]; 52316617Ssam if (addr != curpc) { 52416617Ssam if (traceexec) { 52516617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); 52616617Ssam } 52716617Ssam if (catchbps) { 52816617Ssam setallbps(); 52916617Ssam } 53016617Ssam setbp(addr); 53116617Ssam resume(DEFSIG); 53216617Ssam unsetbp(addr); 53316617Ssam if (catchbps) { 53416617Ssam unsetallbps(); 53516617Ssam } 53616617Ssam if (not isbperr()) { 53716617Ssam printstatus(); 53816617Ssam } 53916617Ssam } 5409677Slinton } 5419677Slinton 5429677Slinton /* 5439677Slinton * Print the status of the process. 5449677Slinton * This routine does not return. 5459677Slinton */ 5469677Slinton 5479677Slinton public printstatus() 5489677Slinton { 54914395Slinton int status; 55014395Slinton 5519843Slinton if (process->status == FINISHED) { 5529843Slinton exit(0); 5539843Slinton } else { 55416617Ssam setcurfunc(whatblock(pc)); 5559677Slinton getsrcpos(); 5569843Slinton if (process->signo == SIGINT) { 5579843Slinton isstopped = true; 5589843Slinton printerror(); 5599843Slinton } else if (isbperr() and isstopped) { 5609843Slinton printf("stopped "); 56111172Slinton printloc(); 56211172Slinton putchar('\n'); 5639843Slinton if (curline > 0) { 5649843Slinton printlines(curline, curline); 5659843Slinton } else { 5669843Slinton printinst(pc, pc); 5679843Slinton } 5689843Slinton erecover(); 5699677Slinton } else { 5709843Slinton fixintr(); 5719677Slinton isstopped = true; 5729677Slinton printerror(); 5739677Slinton } 5749677Slinton } 5759677Slinton } 5769677Slinton 5779677Slinton /* 57811172Slinton * Print out the current location in the debuggee. 57911172Slinton */ 58011172Slinton 58111172Slinton public printloc() 58211172Slinton { 58311172Slinton printf("in "); 58411172Slinton printname(stdout, curfunc); 58511172Slinton putchar(' '); 58614757Slinton if (curline > 0 and not useInstLoc) { 58711172Slinton printsrcpos(); 58811172Slinton } else { 58914757Slinton useInstLoc = false; 59014757Slinton curline = 0; 59111172Slinton printf("at 0x%x", pc); 59211172Slinton } 59311172Slinton } 59411172Slinton 59511172Slinton /* 5969677Slinton * Some functions for testing the state of the process. 5979677Slinton */ 5989677Slinton 5999677Slinton public Boolean notstarted(p) 6009677Slinton Process p; 6019677Slinton { 6029677Slinton return (Boolean) (p->status == NOTSTARTED); 6039677Slinton } 6049677Slinton 6059677Slinton public Boolean isfinished(p) 6069677Slinton Process p; 6079677Slinton { 6089677Slinton return (Boolean) (p->status == FINISHED); 6099677Slinton } 6109677Slinton 6119677Slinton /* 6129677Slinton * Return the signal number which stopped the process. 6139677Slinton */ 6149677Slinton 6159677Slinton public Integer errnum(p) 6169677Slinton Process p; 6179677Slinton { 6189677Slinton return p->signo; 6199677Slinton } 6209677Slinton 6219677Slinton /* 6229677Slinton * Return the termination code of the process. 6239677Slinton */ 6249677Slinton 6259677Slinton public Integer exitcode(p) 6269677Slinton Process p; 6279677Slinton { 6289677Slinton return p->exitval; 6299677Slinton } 6309677Slinton 6319677Slinton /* 6329677Slinton * These routines are used to access the debuggee process from 6339677Slinton * outside this module. 6349677Slinton * 6359677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 63614757Slinton * The system generates an I/O error when a ptrace fails. During reads 63714757Slinton * these are ignored, during writes they are reported as an error, and 63814757Slinton * for anything else they cause a fatal error. 6399677Slinton */ 6409677Slinton 6419677Slinton extern Intfunc *onsyserr(); 6429677Slinton 6439677Slinton private badaddr; 64414757Slinton private read_err(), write_err(); 6459677Slinton 6469677Slinton /* 6479677Slinton * Read from the process' instruction area. 6489677Slinton */ 6499677Slinton 6509677Slinton public iread(buff, addr, nbytes) 6519677Slinton char *buff; 6529677Slinton Address addr; 6539677Slinton int nbytes; 6549677Slinton { 6559677Slinton Intfunc *f; 6569677Slinton 65714757Slinton f = onsyserr(EIO, read_err); 6589677Slinton badaddr = addr; 6599677Slinton if (coredump) { 6609677Slinton coredump_readtext(buff, addr, nbytes); 6619677Slinton } else { 6629677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 6639677Slinton } 6649677Slinton onsyserr(EIO, f); 6659677Slinton } 6669677Slinton 6679677Slinton /* 6689677Slinton * Write to the process' instruction area, usually in order to set 6699677Slinton * or unset a breakpoint. 6709677Slinton */ 6719677Slinton 6729677Slinton public iwrite(buff, addr, nbytes) 6739677Slinton char *buff; 6749677Slinton Address addr; 6759677Slinton int nbytes; 6769677Slinton { 6779677Slinton Intfunc *f; 6789677Slinton 6799677Slinton if (coredump) { 6809677Slinton error("no process to write to"); 6819677Slinton } 68214757Slinton f = onsyserr(EIO, write_err); 6839677Slinton badaddr = addr; 6849677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 6859677Slinton onsyserr(EIO, f); 6869677Slinton } 6879677Slinton 6889677Slinton /* 6899677Slinton * Read for the process' data area. 6909677Slinton */ 6919677Slinton 6929677Slinton public dread(buff, addr, nbytes) 6939677Slinton char *buff; 6949677Slinton Address addr; 6959677Slinton int nbytes; 6969677Slinton { 6979677Slinton Intfunc *f; 6989677Slinton 69914757Slinton f = onsyserr(EIO, read_err); 7009677Slinton badaddr = addr; 7019677Slinton if (coredump) { 7029677Slinton coredump_readdata(buff, addr, nbytes); 7039677Slinton } else { 7049677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 7059677Slinton } 7069677Slinton onsyserr(EIO, f); 7079677Slinton } 7089677Slinton 7099677Slinton /* 7109677Slinton * Write to the process' data area. 7119677Slinton */ 7129677Slinton 7139677Slinton public dwrite(buff, addr, nbytes) 7149677Slinton char *buff; 7159677Slinton Address addr; 7169677Slinton int nbytes; 7179677Slinton { 7189677Slinton Intfunc *f; 7199677Slinton 7209677Slinton if (coredump) { 7219677Slinton error("no process to write to"); 7229677Slinton } 72314757Slinton f = onsyserr(EIO, write_err); 7249677Slinton badaddr = addr; 7259677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 7269677Slinton onsyserr(EIO, f); 7279677Slinton } 7289677Slinton 7299677Slinton /* 73014757Slinton * Trap for errors in reading or writing to a process. 73114757Slinton * The current approach is to "ignore" read errors and complain 73214757Slinton * bitterly about write errors. 7339677Slinton */ 7349677Slinton 73514757Slinton private read_err() 7369677Slinton { 73711560Slinton /* 73814757Slinton * Ignore. 73911560Slinton */ 7409677Slinton } 7419677Slinton 74214757Slinton private write_err() 74314757Slinton { 74414757Slinton error("can't write to process (address 0x%x)", badaddr); 74514757Slinton } 74614757Slinton 7479677Slinton /* 7489677Slinton * Ptrace interface. 7499677Slinton */ 7509677Slinton 7519677Slinton /* 7529677Slinton * This magic macro enables us to look at the process' registers 75314757Slinton * in its user structure. 7549677Slinton */ 7559677Slinton 7569677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 7579677Slinton 7589677Slinton #define WMASK (~(sizeof(Word) - 1)) 7599677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 7609677Slinton 7619677Slinton #define FIRSTSIG SIGINT 7629677Slinton #define LASTSIG SIGQUIT 7639677Slinton #define ischild(pid) ((pid) == 0) 7649677Slinton #define traceme() ptrace(0, 0, 0, 0) 7659677Slinton #define setrep(n) (1 << ((n)-1)) 7669677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 7679677Slinton 7689677Slinton /* 7699677Slinton * Ptrace options (specified in first argument). 7709677Slinton */ 7719677Slinton 7729677Slinton #define UREAD 3 /* read from process's user structure */ 7739677Slinton #define UWRITE 6 /* write to process's user structure */ 7749677Slinton #define IREAD 1 /* read from process's instruction space */ 7759677Slinton #define IWRITE 4 /* write to process's instruction space */ 7769677Slinton #define DREAD 2 /* read from process's data space */ 7779677Slinton #define DWRITE 5 /* write to process's data space */ 7789677Slinton #define CONT 7 /* continue stopped process */ 7799677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 7809677Slinton #define PKILL 8 /* terminate the process */ 7819677Slinton 7829677Slinton /* 7839677Slinton * Start up a new process by forking and exec-ing the 7849677Slinton * given argument list, returning when the process is loaded 7859677Slinton * and ready to execute. The PROCESS information (pointed to 7869677Slinton * by the first argument) is appropriately filled. 7879677Slinton * 7889677Slinton * If the given PROCESS structure is associated with an already running 7899677Slinton * process, we terminate it. 7909677Slinton */ 7919677Slinton 7929677Slinton /* VARARGS2 */ 7939677Slinton private pstart(p, argv, infile, outfile) 7949677Slinton Process p; 7959677Slinton String argv[]; 7969677Slinton String infile; 7979677Slinton String outfile; 7989677Slinton { 7999677Slinton int status; 8009677Slinton 80116617Ssam if (p->pid != 0) { 80216617Ssam pterm(p); 8039677Slinton } 8049677Slinton psigtrace(p, SIGTRAP, true); 80514395Slinton p->pid = vfork(); 80614395Slinton if (p->pid == -1) { 8079677Slinton panic("can't fork"); 8089677Slinton } 8099677Slinton if (ischild(p->pid)) { 8109677Slinton traceme(); 8119677Slinton if (infile != nil) { 81216617Ssam infrom(infile); 8139677Slinton } 8149677Slinton if (outfile != nil) { 81516617Ssam outto(outfile); 8169677Slinton } 81711832Slinton execv(argv[0], argv); 81811172Slinton write(2, "can't exec ", 11); 81911172Slinton write(2, argv[0], strlen(argv[0])); 82011172Slinton write(2, "\n", 1); 82111172Slinton _exit(1); 8229677Slinton } 8239677Slinton pwait(p->pid, &status); 8249677Slinton getinfo(p, status); 8259677Slinton if (p->status != STOPPED) { 8269677Slinton error("program could not begin execution"); 8279677Slinton } 82814395Slinton ptraced(p->pid); 8299677Slinton } 8309677Slinton 8319677Slinton /* 83216617Ssam * Terminate a ptrace'd process. 83316617Ssam */ 83416617Ssam 83516617Ssam public pterm (p) 83616617Ssam Process p; 83716617Ssam { 83816617Ssam integer status; 83916617Ssam 84016617Ssam if (p != nil and p->pid != 0) { 84116617Ssam ptrace(PKILL, p->pid, 0, 0); 84216617Ssam pwait(p->pid, &status); 84316617Ssam unptraced(p->pid); 84416617Ssam } 84516617Ssam } 84616617Ssam 84716617Ssam /* 84811867Slinton * Continue a stopped process. The first argument points to a Process 84911867Slinton * structure. Before the process is restarted it's user area is modified 85011867Slinton * according to the values in the structure. When this routine finishes, 8519677Slinton * the structure has the new values from the process's user area. 8529677Slinton * 8539677Slinton * Pcont terminates when the process stops with a signal pending that 8549677Slinton * is being traced (via psigtrace), or when the process terminates. 8559677Slinton */ 8569677Slinton 85711867Slinton private pcont(p, signo) 8589677Slinton Process p; 85911867Slinton int signo; 8609677Slinton { 86116617Ssam int s, status; 8629677Slinton 8639677Slinton if (p->pid == 0) { 8649677Slinton error("program not active"); 8659677Slinton } 86616617Ssam s = signo; 8679677Slinton do { 86816617Ssam setinfo(p, s); 86916617Ssam if (traceexec) { 87016617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n", 87116617Ssam p->reg[PROGCTR], s, p->signo); 87216617Ssam fflush(stdout); 87316617Ssam } 8749677Slinton sigs_off(); 8759677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 87614395Slinton panic("error %d trying to continue process", errno); 8779677Slinton } 8789677Slinton pwait(p->pid, &status); 8799677Slinton sigs_on(); 8809677Slinton getinfo(p, status); 88116617Ssam if (traceexec and not istraced(p)) { 88216617Ssam printf("!! ignored signal %d at 0x%x\n", p->signo, p->reg[PROGCTR]); 88316617Ssam fflush(stdout); 88416617Ssam } 88516617Ssam s = p->signo; 8869677Slinton } while (p->status == STOPPED and not istraced(p)); 88716617Ssam if (traceexec) { 88816617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 88916617Ssam fflush(stdout); 89016617Ssam } 8919677Slinton } 8929677Slinton 8939677Slinton /* 8949677Slinton * Single step as best ptrace can. 8959677Slinton */ 8969677Slinton 89716617Ssam public pstep(p, signo) 8989677Slinton Process p; 89916617Ssam integer signo; 9009677Slinton { 9019677Slinton int status; 9029677Slinton 90316617Ssam setinfo(p, signo); 90416617Ssam if (traceexec) { 90516617Ssam printf("!! pstep from pc 0x%x with signal %d (%d)\n", 90616617Ssam p->reg[PROGCTR], signo, p->signo); 90716617Ssam fflush(stdout); 90816617Ssam } 9099677Slinton sigs_off(); 91016617Ssam if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { 91116617Ssam panic("error %d trying to step process", errno); 91216617Ssam } 9139677Slinton pwait(p->pid, &status); 9149677Slinton sigs_on(); 9159677Slinton getinfo(p, status); 91616617Ssam if (traceexec) { 91716617Ssam printf("!! pstep to pc 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 91816617Ssam fflush(stdout); 91916617Ssam } 92016617Ssam if (p->status != STOPPED) { 92116617Ssam error("program unexpectedly exited with %d\n", p->exitval); 92216617Ssam } 9239677Slinton } 9249677Slinton 9259677Slinton /* 9269677Slinton * Return from execution when the given signal is pending. 9279677Slinton */ 9289677Slinton 9299677Slinton public psigtrace(p, sig, sw) 9309677Slinton Process p; 9319677Slinton int sig; 9329677Slinton Boolean sw; 9339677Slinton { 9349677Slinton if (sw) { 9359677Slinton p->sigset |= setrep(sig); 9369677Slinton } else { 9379677Slinton p->sigset &= ~setrep(sig); 9389677Slinton } 9399677Slinton } 9409677Slinton 9419677Slinton /* 9429677Slinton * Don't catch any signals. 9439677Slinton * Particularly useful when letting a process finish uninhibited. 9449677Slinton */ 9459677Slinton 9469677Slinton public unsetsigtraces(p) 9479677Slinton Process p; 9489677Slinton { 9499677Slinton p->sigset = 0; 9509677Slinton } 9519677Slinton 9529677Slinton /* 9539677Slinton * Turn off attention to signals not being caught. 9549677Slinton */ 9559677Slinton 9569677Slinton private Intfunc *sigfunc[NSIG]; 9579677Slinton 9589677Slinton private sigs_off() 9599677Slinton { 9609677Slinton register int i; 9619677Slinton 9629677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 9639677Slinton if (i != SIGKILL) { 9649677Slinton sigfunc[i] = signal(i, SIG_IGN); 9659677Slinton } 9669677Slinton } 9679677Slinton } 9689677Slinton 9699677Slinton /* 9709677Slinton * Turn back on attention to signals. 9719677Slinton */ 9729677Slinton 9739677Slinton private sigs_on() 9749677Slinton { 9759677Slinton register int i; 9769677Slinton 9779677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 9789677Slinton if (i != SIGKILL) { 9799677Slinton signal(i, sigfunc[i]); 9809677Slinton } 9819677Slinton } 9829677Slinton } 9839677Slinton 9849677Slinton /* 9859677Slinton * Get process information from user area. 9869677Slinton */ 9879677Slinton 9889677Slinton private int rloc[] ={ 9899677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 9909677Slinton }; 9919677Slinton 9929677Slinton private getinfo(p, status) 9939677Slinton register Process p; 9949677Slinton register int status; 9959677Slinton { 9969677Slinton register int i; 99716617Ssam Address addr; 9989677Slinton 9999677Slinton p->signo = (status&0177); 10009677Slinton p->exitval = ((status >> 8)&0377); 10019677Slinton if (p->signo != STOPPED) { 10029677Slinton p->status = FINISHED; 100314757Slinton p->pid = 0; 100416617Ssam p->reg[PROGCTR] = 0; 10059677Slinton } else { 10069677Slinton p->status = p->signo; 10079677Slinton p->signo = p->exitval; 10089677Slinton p->exitval = 0; 10099677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 10109677Slinton for (i = 0; i < NREG; i++) { 10119677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 10129677Slinton p->oreg[i] = p->reg[i]; 10139677Slinton } 101411768Slinton savetty(stdout, &(p->ttyinfo)); 101516617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); 101616617Ssam p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); 10179677Slinton } 10189677Slinton } 10199677Slinton 10209677Slinton /* 10219677Slinton * Set process's user area information from given process structure. 10229677Slinton */ 10239677Slinton 102411867Slinton private setinfo(p, signo) 10259677Slinton register Process p; 102611867Slinton int signo; 10279677Slinton { 10289677Slinton register int i; 10299677Slinton register int r; 10309677Slinton 103114757Slinton if (signo == DEFSIG) { 103216617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { 103314757Slinton p->signo = 0; 103414757Slinton } 103514757Slinton } else { 103611867Slinton p->signo = signo; 10379677Slinton } 10389677Slinton for (i = 0; i < NREG; i++) { 10399677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 10409677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 10419677Slinton } 10429677Slinton } 104311768Slinton restoretty(stdout, &(p->ttyinfo)); 10449677Slinton } 10459677Slinton 10469677Slinton /* 104716617Ssam * Return the address associated with the current signal. 104816617Ssam * (Plus two since the address points to the beginning of a procedure). 104916617Ssam */ 105016617Ssam 105116617Ssam public Address usignal (p) 105216617Ssam Process p; 105316617Ssam { 105416617Ssam Address r; 105516617Ssam 105616617Ssam r = p->sigstatus; 105716617Ssam if (r != 0 and r != 1) { 105816617Ssam r += 2; 105916617Ssam } 106016617Ssam return r; 106116617Ssam } 106216617Ssam 106316617Ssam /* 10649677Slinton * Structure for reading and writing by words, but dealing with bytes. 10659677Slinton */ 10669677Slinton 10679677Slinton typedef union { 10689677Slinton Word pword; 10699677Slinton Byte pbyte[sizeof(Word)]; 10709677Slinton } Pword; 10719677Slinton 10729677Slinton /* 10739677Slinton * Read (write) from (to) the process' address space. 10749677Slinton * We must deal with ptrace's inability to look anywhere other 10759677Slinton * than at a word boundary. 10769677Slinton */ 10779677Slinton 10789677Slinton private Word fetch(); 10799677Slinton private store(); 10809677Slinton 10819677Slinton private pio(p, op, seg, buff, addr, nbytes) 10829677Slinton Process p; 10839677Slinton PioOp op; 10849677Slinton PioSeg seg; 10859677Slinton char *buff; 10869677Slinton Address addr; 10879677Slinton int nbytes; 10889677Slinton { 10899677Slinton register int i; 10909677Slinton register Address newaddr; 10919677Slinton register char *cp; 10929677Slinton char *bufend; 10939677Slinton Pword w; 10949677Slinton Address wordaddr; 10959677Slinton int byteoff; 10969677Slinton 10979677Slinton if (p->status != STOPPED) { 10989677Slinton error("program is not active"); 10999677Slinton } 11009677Slinton cp = buff; 11019677Slinton newaddr = addr; 11029677Slinton wordaddr = (newaddr&WMASK); 11039677Slinton if (wordaddr != newaddr) { 11049677Slinton w.pword = fetch(p, seg, wordaddr); 11059677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 11069677Slinton if (op == PREAD) { 11079677Slinton *cp++ = w.pbyte[i]; 11089677Slinton } else { 11099677Slinton w.pbyte[i] = *cp++; 11109677Slinton } 11119677Slinton nbytes--; 11129677Slinton } 11139677Slinton if (op == PWRITE) { 11149677Slinton store(p, seg, wordaddr, w.pword); 11159677Slinton } 11169677Slinton newaddr = wordaddr + sizeof(Word); 11179677Slinton } 11189677Slinton byteoff = (nbytes&(~WMASK)); 11199677Slinton nbytes -= byteoff; 11209677Slinton bufend = cp + nbytes; 11219677Slinton while (cp < bufend) { 11229677Slinton if (op == PREAD) { 11239677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 11249677Slinton } else { 11259677Slinton store(p, seg, newaddr, *((Word *) cp)); 11269677Slinton } 11279677Slinton cp += sizeof(Word); 11289677Slinton newaddr += sizeof(Word); 11299677Slinton } 11309677Slinton if (byteoff > 0) { 11319677Slinton w.pword = fetch(p, seg, newaddr); 11329677Slinton for (i = 0; i < byteoff; i++) { 11339677Slinton if (op == PREAD) { 11349677Slinton *cp++ = w.pbyte[i]; 11359677Slinton } else { 11369677Slinton w.pbyte[i] = *cp++; 11379677Slinton } 11389677Slinton } 11399677Slinton if (op == PWRITE) { 11409677Slinton store(p, seg, newaddr, w.pword); 11419677Slinton } 11429677Slinton } 11439677Slinton } 11449677Slinton 11459677Slinton /* 11469677Slinton * Get a word from a process at the given address. 11479677Slinton * The address is assumed to be on a word boundary. 11489677Slinton * 11499677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 11509677Slinton * to the instruction space since it is assumed to be pure. 11519677Slinton * 11529677Slinton * It is necessary to use a write-through scheme so that 11539677Slinton * breakpoints right next to each other don't interfere. 11549677Slinton */ 11559677Slinton 11569677Slinton private Integer nfetchs, nreads, nwrites; 11579677Slinton 11589677Slinton private Word fetch(p, seg, addr) 11599677Slinton Process p; 11609677Slinton PioSeg seg; 11619677Slinton register int addr; 11629677Slinton { 11639677Slinton register CacheWord *wp; 11649677Slinton register Word w; 11659677Slinton 11669677Slinton switch (seg) { 11679677Slinton case TEXTSEG: 11689677Slinton ++nfetchs; 11699677Slinton wp = &p->word[cachehash(addr)]; 11709677Slinton if (addr == 0 or wp->addr != addr) { 11719677Slinton ++nreads; 11729677Slinton w = ptrace(IREAD, p->pid, addr, 0); 11739677Slinton wp->addr = addr; 11749677Slinton wp->val = w; 11759677Slinton } else { 11769677Slinton w = wp->val; 11779677Slinton } 11789677Slinton break; 11799677Slinton 11809677Slinton case DATASEG: 11819677Slinton w = ptrace(DREAD, p->pid, addr, 0); 11829677Slinton break; 11839677Slinton 11849677Slinton default: 11859677Slinton panic("fetch: bad seg %d", seg); 11869677Slinton /* NOTREACHED */ 11879677Slinton } 11889677Slinton return w; 11899677Slinton } 11909677Slinton 11919677Slinton /* 11929677Slinton * Put a word into the process' address space at the given address. 11939677Slinton * The address is assumed to be on a word boundary. 11949677Slinton */ 11959677Slinton 11969677Slinton private store(p, seg, addr, data) 11979677Slinton Process p; 11989677Slinton PioSeg seg; 11999677Slinton int addr; 12009677Slinton Word data; 12019677Slinton { 12029677Slinton register CacheWord *wp; 12039677Slinton 12049677Slinton switch (seg) { 12059677Slinton case TEXTSEG: 12069677Slinton ++nwrites; 12079677Slinton wp = &p->word[cachehash(addr)]; 12089677Slinton wp->addr = addr; 12099677Slinton wp->val = data; 12109677Slinton ptrace(IWRITE, p->pid, addr, data); 12119677Slinton break; 12129677Slinton 12139677Slinton case DATASEG: 12149677Slinton ptrace(DWRITE, p->pid, addr, data); 12159677Slinton break; 12169677Slinton 12179677Slinton default: 12189677Slinton panic("store: bad seg %d", seg); 12199677Slinton /* NOTREACHED */ 12209677Slinton } 12219677Slinton } 12229677Slinton 12239677Slinton public printptraceinfo() 12249677Slinton { 12259677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 12269677Slinton } 12279677Slinton 12289677Slinton /* 122916617Ssam * Redirect input. 123016617Ssam * Assuming this is called from a child, we should be careful to avoid 123116617Ssam * (possibly) shared standard I/O buffers. 12329677Slinton */ 12339677Slinton 123416617Ssam private infrom (filename) 123516617Ssam String filename; 123616617Ssam { 123716617Ssam Fileid in; 123816617Ssam 123916617Ssam in = open(filename, 0); 124016617Ssam if (in == -1) { 124116617Ssam write(2, "can't read ", 11); 124216617Ssam write(2, filename, strlen(filename)); 124316617Ssam write(2, "\n", 1); 124416617Ssam _exit(1); 124516617Ssam } 124616617Ssam fswap(0, in); 124716617Ssam } 124816617Ssam 124916617Ssam /* 125016617Ssam * Redirect standard output. 125116617Ssam * Same assumptions as for "infrom" above. 125216617Ssam */ 125316617Ssam 125416617Ssam private outto (filename) 125516617Ssam String filename; 125616617Ssam { 125716617Ssam Fileid out; 125816617Ssam 125916617Ssam out = creat(filename, 0666); 126016617Ssam if (out == -1) { 126116617Ssam write(2, "can't write ", 12); 126216617Ssam write(2, filename, strlen(filename)); 126316617Ssam write(2, "\n", 1); 126416617Ssam _exit(1); 126516617Ssam } 126616617Ssam fswap(1, out); 126716617Ssam } 126816617Ssam 126916617Ssam /* 127016617Ssam * Swap file numbers, useful for redirecting standard input or output. 127116617Ssam */ 127216617Ssam 12739677Slinton private fswap(oldfd, newfd) 127416617Ssam Fileid oldfd; 127516617Ssam Fileid newfd; 12769677Slinton { 12779677Slinton if (oldfd != newfd) { 12789677Slinton close(oldfd); 12799677Slinton dup(newfd); 12809677Slinton close(newfd); 12819677Slinton } 12829677Slinton } 1283*16928Ssam 1284*16928Ssam #define bit(i) (1 << ((i)-1)) 1285*16928Ssam /* 1286*16928Ssam * Signal manipulation routines. 1287*16928Ssam */ 1288*16928Ssam static String signames[NSIG] = { 1289*16928Ssam 0, 1290*16928Ssam "HUP", 1291*16928Ssam "INT", 1292*16928Ssam "QUIT", 1293*16928Ssam "ILL", 1294*16928Ssam "TRAP", 1295*16928Ssam "IOT", 1296*16928Ssam "EMT", 1297*16928Ssam "FPE", 1298*16928Ssam "KILL", 1299*16928Ssam "BUS", 1300*16928Ssam "SEGV", 1301*16928Ssam "SYS", 1302*16928Ssam "PIPE", 1303*16928Ssam "ALRM", 1304*16928Ssam "TERM", 1305*16928Ssam 0, 1306*16928Ssam "STOP", 1307*16928Ssam "TSTP", 1308*16928Ssam "CONT", 1309*16928Ssam "CHLD", 1310*16928Ssam "TTIN", 1311*16928Ssam "TTOU", 1312*16928Ssam "TINT", 1313*16928Ssam "XCPU", 1314*16928Ssam "XFSZ", 1315*16928Ssam }; 1316*16928Ssam 1317*16928Ssam /* 1318*16928Ssam * Map a signal name to a number. 1319*16928Ssam */ 1320*16928Ssam public signalname(s) 1321*16928Ssam String s; 1322*16928Ssam { 1323*16928Ssam register String *p; 1324*16928Ssam 1325*16928Ssam for (p = signames; p < &signames[NSIG]; p++) 1326*16928Ssam if (*p && streq(*p, s)) 1327*16928Ssam return (p - signames); 1328*16928Ssam error("%s: Unknown signal.", s); 1329*16928Ssam } 1330*16928Ssam 1331*16928Ssam /* 1332*16928Ssam * Print all signals being ignored by the 1333*16928Ssam * debugger. These signals are auotmatically 1334*16928Ssam * passed on to the debugged process. 1335*16928Ssam */ 1336*16928Ssam public printsigsignored(vec) 1337*16928Ssam long vec; 1338*16928Ssam { 1339*16928Ssam register Integer s; 1340*16928Ssam String sep = ""; 1341*16928Ssam 1342*16928Ssam for (s = 1; s < NSIG; s++) 1343*16928Ssam if ((vec & bit(s)) && signames[s]) { 1344*16928Ssam printf("%s%s", sep, signames[s]); 1345*16928Ssam sep = " "; 1346*16928Ssam } 1347*16928Ssam if (*sep != '\0') { 1348*16928Ssam putchar('\n'); 1349*16928Ssam fflush(stdout); 1350*16928Ssam } 1351*16928Ssam } 1352*16928Ssam 1353*16928Ssam /* 1354*16928Ssam * Print all signals being intercepted by 1355*16928Ssam * the debugger for the specified process. 1356*16928Ssam */ 1357*16928Ssam public printsigscaught(vec) 1358*16928Ssam long vec; 1359*16928Ssam { 1360*16928Ssam register Integer s; 1361*16928Ssam String sep = ""; 1362*16928Ssam 1363*16928Ssam for (s = 1; s < NSIG; s++) 1364*16928Ssam if ((vec & bit(s)) == 0 && signames[s]) { 1365*16928Ssam printf("%s%s", sep, signames[s]); 1366*16928Ssam sep = " "; 1367*16928Ssam } 1368*16928Ssam if (*sep != '\0') { 1369*16928Ssam putchar('\n'); 1370*16928Ssam fflush(stdout); 1371*16928Ssam } 1372*16928Ssam } 1373*16928Ssam 1374