19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*16931Ssam static char sccsid[] = "@(#)process.c 1.15 (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 */ 72*16931Ssam short sigcode; /* auxiliary signal info code */ 739677Slinton int exitval; /* return value from exit() */ 749677Slinton long sigset; /* bit array of traced signals */ 759677Slinton CacheWord word[CSIZE]; /* text segment cache */ 7611768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 7716617Ssam Address sigstatus; /* process' handler for current signal */ 789677Slinton }; 799677Slinton 809677Slinton /* 819677Slinton * These definitions are for the arguments to "pio". 829677Slinton */ 839677Slinton 849677Slinton typedef enum { PREAD, PWRITE } PioOp; 859677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 869677Slinton 879677Slinton private struct Process pbuf; 889677Slinton 8913841Slinton #define MAXNCMDARGS 100 /* maximum number of arguments to RUN */ 909677Slinton 9114395Slinton extern int errno; 9214395Slinton 939677Slinton private Boolean just_started; 949677Slinton private int argc; 959677Slinton private String argv[MAXNCMDARGS]; 969677Slinton private String infile, outfile; 979677Slinton 989677Slinton /* 999677Slinton * Initialize process information. 1009677Slinton */ 1019677Slinton 1029677Slinton public process_init() 1039677Slinton { 1049677Slinton register Integer i; 1059677Slinton Char buf[10]; 1069677Slinton 1079677Slinton process = &pbuf; 1089677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1099677Slinton setsigtrace(); 1109677Slinton for (i = 0; i < NREG; i++) { 1119677Slinton sprintf(buf, "$r%d", i); 1129677Slinton defregname(identname(buf, false), i); 1139677Slinton } 1149677Slinton defregname(identname("$ap", true), ARGP); 1159677Slinton defregname(identname("$fp", true), FRP); 1169677Slinton defregname(identname("$sp", true), STKP); 1179677Slinton defregname(identname("$pc", true), PROGCTR); 1189677Slinton if (coredump) { 1199677Slinton coredump_readin(process->mask, process->reg, process->signo); 12012484Slinton pc = process->reg[PROGCTR]; 12112484Slinton getsrcpos(); 1229677Slinton } 12312484Slinton arginit(); 1249677Slinton } 1259677Slinton 1269677Slinton /* 1279677Slinton * Routines to get at process information from outside this module. 1289677Slinton */ 1299677Slinton 1309677Slinton public Word reg(n) 1319677Slinton Integer n; 1329677Slinton { 1339677Slinton register Word w; 1349677Slinton 1359677Slinton if (n == NREG) { 1369677Slinton w = process->mask; 1379677Slinton } else { 1389677Slinton w = process->reg[n]; 1399677Slinton } 1409677Slinton return w; 1419677Slinton } 1429677Slinton 1439677Slinton public setreg(n, w) 1449677Slinton Integer n; 1459677Slinton Word w; 1469677Slinton { 1479677Slinton process->reg[n] = w; 1489677Slinton } 1499677Slinton 1509677Slinton /* 1519677Slinton * Begin execution. 1529677Slinton * 1539677Slinton * We set a breakpoint at the end of the code so that the 1549677Slinton * process data doesn't disappear after the program terminates. 1559677Slinton */ 1569677Slinton 1579677Slinton private Boolean remade(); 1589677Slinton 1599677Slinton public start(argv, infile, outfile) 1609677Slinton String argv[]; 1619677Slinton String infile, outfile; 1629677Slinton { 1639677Slinton String pargv[4]; 1649677Slinton Node cond; 1659677Slinton 1669677Slinton if (coredump) { 1679677Slinton coredump = false; 1689677Slinton fclose(corefile); 1699677Slinton coredump_close(); 1709677Slinton } 1719677Slinton if (argv == nil) { 1729677Slinton argv = pargv; 1739677Slinton pargv[0] = objname; 1749677Slinton pargv[1] = nil; 1759677Slinton } else { 1769677Slinton argv[argc] = nil; 1779677Slinton } 1789677Slinton if (remade(objname)) { 1799677Slinton reinit(argv, infile, outfile); 1809677Slinton } 1819677Slinton pstart(process, argv, infile, outfile); 1829677Slinton if (process->status == STOPPED) { 1839677Slinton pc = 0; 18416617Ssam setcurfunc(program); 1859677Slinton if (objsize != 0) { 1869677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1879677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1889677Slinton } 1899677Slinton } 1909677Slinton } 1919677Slinton 1929677Slinton /* 1939677Slinton * Check to see if the object file has changed since the symbolic 1949677Slinton * information last was read. 1959677Slinton */ 1969677Slinton 1979677Slinton private time_t modtime; 1989677Slinton 1999677Slinton private Boolean remade(filename) 2009677Slinton String filename; 2019677Slinton { 2029677Slinton struct stat s; 2039677Slinton Boolean b; 2049677Slinton 2059677Slinton stat(filename, &s); 2069677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2079677Slinton modtime = s.st_mtime; 2089677Slinton return b; 2099677Slinton } 2109677Slinton 2119677Slinton /* 2129677Slinton * Set up what signals we want to trace. 2139677Slinton */ 2149677Slinton 2159677Slinton private setsigtrace() 2169677Slinton { 2179677Slinton register Integer i; 2189677Slinton register Process p; 2199677Slinton 2209677Slinton p = process; 2219677Slinton for (i = 1; i <= NSIG; i++) { 2229677Slinton psigtrace(p, i, true); 2239677Slinton } 2249677Slinton psigtrace(p, SIGHUP, false); 2259677Slinton psigtrace(p, SIGKILL, false); 2269677Slinton psigtrace(p, SIGALRM, false); 2279677Slinton psigtrace(p, SIGTSTP, false); 2289677Slinton psigtrace(p, SIGCONT, false); 2299677Slinton psigtrace(p, SIGCHLD, false); 2309677Slinton } 2319677Slinton 2329677Slinton /* 2339677Slinton * Initialize the argument list. 2349677Slinton */ 2359677Slinton 2369677Slinton public arginit() 2379677Slinton { 2389677Slinton infile = nil; 2399677Slinton outfile = nil; 2409677Slinton argv[0] = objname; 2419677Slinton argc = 1; 2429677Slinton } 2439677Slinton 2449677Slinton /* 2459677Slinton * Add an argument to the list for the debuggee. 2469677Slinton */ 2479677Slinton 2489677Slinton public newarg(arg) 2499677Slinton String arg; 2509677Slinton { 2519677Slinton if (argc >= MAXNCMDARGS) { 2529677Slinton error("too many arguments"); 2539677Slinton } 2549677Slinton argv[argc++] = arg; 2559677Slinton } 2569677Slinton 2579677Slinton /* 2589677Slinton * Set the standard input for the debuggee. 2599677Slinton */ 2609677Slinton 2619677Slinton public inarg(filename) 2629677Slinton String filename; 2639677Slinton { 2649677Slinton if (infile != nil) { 2659677Slinton error("multiple input redirects"); 2669677Slinton } 2679677Slinton infile = filename; 2689677Slinton } 2699677Slinton 2709677Slinton /* 2719677Slinton * Set the standard output for the debuggee. 2729677Slinton * Probably should check to avoid overwriting an existing file. 2739677Slinton */ 2749677Slinton 2759677Slinton public outarg(filename) 2769677Slinton String filename; 2779677Slinton { 2789677Slinton if (outfile != nil) { 2799677Slinton error("multiple output redirect"); 2809677Slinton } 2819677Slinton outfile = filename; 2829677Slinton } 2839677Slinton 2849677Slinton /* 2859677Slinton * Start debuggee executing. 2869677Slinton */ 2879677Slinton 2889677Slinton public run() 2899677Slinton { 2909677Slinton process->status = STOPPED; 2919677Slinton fixbps(); 2929677Slinton curline = 0; 2939677Slinton start(argv, infile, outfile); 2949677Slinton just_started = true; 2959677Slinton isstopped = false; 29614757Slinton cont(0); 2979677Slinton } 2989677Slinton 2999677Slinton /* 3009677Slinton * Continue execution wherever we left off. 3019677Slinton * 3029677Slinton * Note that this routine never returns. Eventually bpact() will fail 3039677Slinton * and we'll call printstatus or step will call it. 3049677Slinton */ 3059677Slinton 3069677Slinton typedef int Intfunc(); 3079677Slinton 3089677Slinton private Intfunc *dbintr; 3099677Slinton private intr(); 3109677Slinton 3119677Slinton #define succeeds == true 3129677Slinton #define fails == false 3139677Slinton 31411867Slinton public cont(signo) 31516617Ssam integer signo; 3169677Slinton { 31716617Ssam integer s; 31816617Ssam 3199677Slinton dbintr = signal(SIGINT, intr); 3209677Slinton if (just_started) { 3219677Slinton just_started = false; 3229677Slinton } else { 3239677Slinton if (not isstopped) { 3249677Slinton error("can't continue execution"); 3259677Slinton } 3269677Slinton isstopped = false; 32711867Slinton stepover(); 3289677Slinton } 32916617Ssam s = signo; 3309677Slinton for (;;) { 3319677Slinton if (single_stepping) { 3329677Slinton printnews(); 3339677Slinton } else { 3349677Slinton setallbps(); 33516617Ssam resume(s); 3369677Slinton unsetallbps(); 33716617Ssam s = DEFSIG; 3389677Slinton if (bpact() fails) { 3399677Slinton printstatus(); 3409677Slinton } 3419677Slinton } 34211867Slinton stepover(); 3439677Slinton } 3449677Slinton /* NOTREACHED */ 3459677Slinton } 3469677Slinton 3479677Slinton /* 3489677Slinton * This routine is called if we get an interrupt while "running" px 3499677Slinton * but actually in the debugger. Could happen, for example, while 3509677Slinton * processing breakpoints. 3519677Slinton * 3529677Slinton * We basically just want to keep going; the assumption is 3539677Slinton * that when the process resumes it will get the interrupt 3549677Slinton * which will then be handled. 3559677Slinton */ 3569677Slinton 3579677Slinton private intr() 3589677Slinton { 3599677Slinton signal(SIGINT, intr); 3609677Slinton } 3619677Slinton 3629677Slinton public fixintr() 3639677Slinton { 3649677Slinton signal(SIGINT, dbintr); 3659677Slinton } 3669677Slinton 3679677Slinton /* 3689677Slinton * Resume execution. 3699677Slinton */ 3709677Slinton 37111867Slinton public resume(signo) 37211867Slinton int signo; 3739677Slinton { 3749677Slinton register Process p; 3759677Slinton 3769677Slinton p = process; 37711867Slinton pcont(p, signo); 3789677Slinton pc = process->reg[PROGCTR]; 37911832Slinton if (p->status != STOPPED) { 38011867Slinton if (p->signo != 0) { 38111867Slinton error("program terminated by signal %d", p->signo); 38214757Slinton } else if (not runfirst) { 38311867Slinton error("program unexpectedly exited with %d", p->exitval); 38411867Slinton } 38511832Slinton } 3869677Slinton } 3879677Slinton 3889677Slinton /* 3899677Slinton * Continue execution up to the next source line. 3909677Slinton * 3919677Slinton * There are two ways to define the next source line depending on what 3929677Slinton * is desired when a procedure or function call is encountered. Step 3939677Slinton * stops at the beginning of the procedure or call; next skips over it. 3949677Slinton */ 3959677Slinton 3969677Slinton /* 3979677Slinton * Stepc is what is called when the step command is given. 3989677Slinton * It has to play with the "isstopped" information. 3999677Slinton */ 4009677Slinton 4019677Slinton public stepc() 4029677Slinton { 4039677Slinton if (not isstopped) { 4049677Slinton error("can't continue execution"); 4059677Slinton } 4069677Slinton isstopped = false; 4079677Slinton dostep(false); 4089677Slinton isstopped = true; 4099677Slinton } 4109677Slinton 4119677Slinton public next() 4129677Slinton { 41316617Ssam Address oldfrp, newfrp; 41416617Ssam 4159677Slinton if (not isstopped) { 4169677Slinton error("can't continue execution"); 4179677Slinton } 4189677Slinton isstopped = false; 41916617Ssam oldfrp = reg(FRP); 42016617Ssam do { 42116617Ssam dostep(true); 42216617Ssam pc = reg(PROGCTR); 42316617Ssam newfrp = reg(FRP); 42416617Ssam } while (newfrp < oldfrp and newfrp != 0); 4259677Slinton isstopped = true; 4269677Slinton } 4279677Slinton 42811867Slinton /* 42916617Ssam * Continue execution until the current function returns, or, 43016617Ssam * if the given argument is non-nil, until execution returns to 43116617Ssam * somewhere within the given function. 43216617Ssam */ 43316617Ssam 43416617Ssam public rtnfunc (f) 43516617Ssam Symbol f; 43616617Ssam { 43716617Ssam Address addr; 43816617Ssam Symbol t; 43916617Ssam 44016617Ssam if (not isstopped) { 44116617Ssam error("can't continue execution"); 44216617Ssam } else if (f != nil and not isactive(f)) { 44316617Ssam error("%s is not active", symname(f)); 44416617Ssam } else { 44516617Ssam addr = return_addr(); 44616617Ssam if (addr == nil) { 44716617Ssam error("no place to return to"); 44816617Ssam } else { 44916617Ssam isstopped = false; 45016617Ssam contto(addr); 45116617Ssam if (f != nil) { 45216617Ssam for (;;) { 45316617Ssam t = whatblock(pc); 45416617Ssam addr = return_addr(); 45516617Ssam if (t == f or addr == nil) break; 45616617Ssam contto(addr); 45716617Ssam } 45816617Ssam } 45916617Ssam if (bpact() fails) { 46016617Ssam isstopped = true; 46116617Ssam printstatus(); 46216617Ssam } 46316617Ssam } 46416617Ssam } 46516617Ssam } 46616617Ssam 46716617Ssam /* 46811867Slinton * Single-step over the current machine instruction. 46911867Slinton * 47011867Slinton * If we're single-stepping by source line we want to step to the 47111867Slinton * next source line. Otherwise we're going to continue so there's 47211867Slinton * no reason to do all the work necessary to single-step to the next 47311867Slinton * source line. 47411867Slinton */ 47511867Slinton 47616617Ssam public stepover() 4779677Slinton { 47811867Slinton Boolean b; 47911867Slinton 48016617Ssam if (traceexec) { 48116617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); 48216617Ssam } 48311867Slinton if (single_stepping) { 48411867Slinton dostep(false); 48511867Slinton } else { 48611867Slinton b = inst_tracing; 48711867Slinton inst_tracing = true; 48811867Slinton dostep(false); 48911867Slinton inst_tracing = b; 49011867Slinton } 49116617Ssam if (traceexec) { 49216617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); 49316617Ssam } 4949677Slinton } 4959677Slinton 4969677Slinton /* 4979677Slinton * Resume execution up to the given address. It is assumed that 4989677Slinton * no breakpoints exist between the current address and the one 4999677Slinton * we're stepping to. This saves us from setting all the breakpoints. 5009677Slinton */ 5019677Slinton 5029677Slinton public stepto(addr) 5039677Slinton Address addr; 5049677Slinton { 50516617Ssam xto(addr, false); 50616617Ssam } 50716617Ssam 50816617Ssam private contto (addr) 50916617Ssam Address addr; 51016617Ssam { 51116617Ssam xto(addr, true); 51216617Ssam } 51316617Ssam 51416617Ssam private xto (addr, catchbps) 51516617Ssam Address addr; 51616617Ssam boolean catchbps; 51716617Ssam { 51816617Ssam Address curpc; 51916617Ssam 52016617Ssam if (catchbps) { 52116617Ssam stepover(); 5229677Slinton } 52316617Ssam curpc = process->reg[PROGCTR]; 52416617Ssam if (addr != curpc) { 52516617Ssam if (traceexec) { 52616617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); 52716617Ssam } 52816617Ssam if (catchbps) { 52916617Ssam setallbps(); 53016617Ssam } 53116617Ssam setbp(addr); 53216617Ssam resume(DEFSIG); 53316617Ssam unsetbp(addr); 53416617Ssam if (catchbps) { 53516617Ssam unsetallbps(); 53616617Ssam } 53716617Ssam if (not isbperr()) { 53816617Ssam printstatus(); 53916617Ssam } 54016617Ssam } 5419677Slinton } 5429677Slinton 5439677Slinton /* 5449677Slinton * Print the status of the process. 5459677Slinton * This routine does not return. 5469677Slinton */ 5479677Slinton 5489677Slinton public printstatus() 5499677Slinton { 55014395Slinton int status; 55114395Slinton 5529843Slinton if (process->status == FINISHED) { 5539843Slinton exit(0); 5549843Slinton } else { 55516617Ssam setcurfunc(whatblock(pc)); 5569677Slinton getsrcpos(); 5579843Slinton if (process->signo == SIGINT) { 5589843Slinton isstopped = true; 5599843Slinton printerror(); 5609843Slinton } else if (isbperr() and isstopped) { 5619843Slinton printf("stopped "); 56211172Slinton printloc(); 56311172Slinton putchar('\n'); 5649843Slinton if (curline > 0) { 5659843Slinton printlines(curline, curline); 5669843Slinton } else { 5679843Slinton printinst(pc, pc); 5689843Slinton } 5699843Slinton erecover(); 5709677Slinton } else { 5719843Slinton fixintr(); 5729677Slinton isstopped = true; 5739677Slinton printerror(); 5749677Slinton } 5759677Slinton } 5769677Slinton } 5779677Slinton 5789677Slinton /* 57911172Slinton * Print out the current location in the debuggee. 58011172Slinton */ 58111172Slinton 58211172Slinton public printloc() 58311172Slinton { 58411172Slinton printf("in "); 58511172Slinton printname(stdout, curfunc); 58611172Slinton putchar(' '); 58714757Slinton if (curline > 0 and not useInstLoc) { 58811172Slinton printsrcpos(); 58911172Slinton } else { 59014757Slinton useInstLoc = false; 59114757Slinton curline = 0; 59211172Slinton printf("at 0x%x", pc); 59311172Slinton } 59411172Slinton } 59511172Slinton 59611172Slinton /* 5979677Slinton * Some functions for testing the state of the process. 5989677Slinton */ 5999677Slinton 6009677Slinton public Boolean notstarted(p) 6019677Slinton Process p; 6029677Slinton { 6039677Slinton return (Boolean) (p->status == NOTSTARTED); 6049677Slinton } 6059677Slinton 6069677Slinton public Boolean isfinished(p) 6079677Slinton Process p; 6089677Slinton { 6099677Slinton return (Boolean) (p->status == FINISHED); 6109677Slinton } 6119677Slinton 6129677Slinton /* 6139677Slinton * Return the signal number which stopped the process. 6149677Slinton */ 6159677Slinton 6169677Slinton public Integer errnum(p) 6179677Slinton Process p; 6189677Slinton { 6199677Slinton return p->signo; 6209677Slinton } 6219677Slinton 622*16931Ssam public Integer errcode(p) 623*16931Ssam Process p; 624*16931Ssam { 625*16931Ssam return p->sigcode; 626*16931Ssam } 627*16931Ssam 6289677Slinton /* 6299677Slinton * Return the termination code of the process. 6309677Slinton */ 6319677Slinton 6329677Slinton public Integer exitcode(p) 6339677Slinton Process p; 6349677Slinton { 6359677Slinton return p->exitval; 6369677Slinton } 6379677Slinton 6389677Slinton /* 6399677Slinton * These routines are used to access the debuggee process from 6409677Slinton * outside this module. 6419677Slinton * 6429677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 64314757Slinton * The system generates an I/O error when a ptrace fails. During reads 64414757Slinton * these are ignored, during writes they are reported as an error, and 64514757Slinton * for anything else they cause a fatal error. 6469677Slinton */ 6479677Slinton 6489677Slinton extern Intfunc *onsyserr(); 6499677Slinton 6509677Slinton private badaddr; 65114757Slinton private read_err(), write_err(); 6529677Slinton 6539677Slinton /* 6549677Slinton * Read from the process' instruction area. 6559677Slinton */ 6569677Slinton 6579677Slinton public iread(buff, addr, nbytes) 6589677Slinton char *buff; 6599677Slinton Address addr; 6609677Slinton int nbytes; 6619677Slinton { 6629677Slinton Intfunc *f; 6639677Slinton 66414757Slinton f = onsyserr(EIO, read_err); 6659677Slinton badaddr = addr; 6669677Slinton if (coredump) { 6679677Slinton coredump_readtext(buff, addr, nbytes); 6689677Slinton } else { 6699677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 6709677Slinton } 6719677Slinton onsyserr(EIO, f); 6729677Slinton } 6739677Slinton 6749677Slinton /* 6759677Slinton * Write to the process' instruction area, usually in order to set 6769677Slinton * or unset a breakpoint. 6779677Slinton */ 6789677Slinton 6799677Slinton public iwrite(buff, addr, nbytes) 6809677Slinton char *buff; 6819677Slinton Address addr; 6829677Slinton int nbytes; 6839677Slinton { 6849677Slinton Intfunc *f; 6859677Slinton 6869677Slinton if (coredump) { 6879677Slinton error("no process to write to"); 6889677Slinton } 68914757Slinton f = onsyserr(EIO, write_err); 6909677Slinton badaddr = addr; 6919677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 6929677Slinton onsyserr(EIO, f); 6939677Slinton } 6949677Slinton 6959677Slinton /* 6969677Slinton * Read for the process' data area. 6979677Slinton */ 6989677Slinton 6999677Slinton public dread(buff, addr, nbytes) 7009677Slinton char *buff; 7019677Slinton Address addr; 7029677Slinton int nbytes; 7039677Slinton { 7049677Slinton Intfunc *f; 7059677Slinton 70614757Slinton f = onsyserr(EIO, read_err); 7079677Slinton badaddr = addr; 7089677Slinton if (coredump) { 7099677Slinton coredump_readdata(buff, addr, nbytes); 7109677Slinton } else { 7119677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 7129677Slinton } 7139677Slinton onsyserr(EIO, f); 7149677Slinton } 7159677Slinton 7169677Slinton /* 7179677Slinton * Write to the process' data area. 7189677Slinton */ 7199677Slinton 7209677Slinton public dwrite(buff, addr, nbytes) 7219677Slinton char *buff; 7229677Slinton Address addr; 7239677Slinton int nbytes; 7249677Slinton { 7259677Slinton Intfunc *f; 7269677Slinton 7279677Slinton if (coredump) { 7289677Slinton error("no process to write to"); 7299677Slinton } 73014757Slinton f = onsyserr(EIO, write_err); 7319677Slinton badaddr = addr; 7329677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 7339677Slinton onsyserr(EIO, f); 7349677Slinton } 7359677Slinton 7369677Slinton /* 73714757Slinton * Trap for errors in reading or writing to a process. 73814757Slinton * The current approach is to "ignore" read errors and complain 73914757Slinton * bitterly about write errors. 7409677Slinton */ 7419677Slinton 74214757Slinton private read_err() 7439677Slinton { 74411560Slinton /* 74514757Slinton * Ignore. 74611560Slinton */ 7479677Slinton } 7489677Slinton 74914757Slinton private write_err() 75014757Slinton { 75114757Slinton error("can't write to process (address 0x%x)", badaddr); 75214757Slinton } 75314757Slinton 7549677Slinton /* 7559677Slinton * Ptrace interface. 7569677Slinton */ 7579677Slinton 7589677Slinton /* 7599677Slinton * This magic macro enables us to look at the process' registers 76014757Slinton * in its user structure. 7619677Slinton */ 7629677Slinton 7639677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 7649677Slinton 7659677Slinton #define WMASK (~(sizeof(Word) - 1)) 7669677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 7679677Slinton 7689677Slinton #define FIRSTSIG SIGINT 7699677Slinton #define LASTSIG SIGQUIT 7709677Slinton #define ischild(pid) ((pid) == 0) 7719677Slinton #define traceme() ptrace(0, 0, 0, 0) 7729677Slinton #define setrep(n) (1 << ((n)-1)) 7739677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 7749677Slinton 7759677Slinton /* 7769677Slinton * Ptrace options (specified in first argument). 7779677Slinton */ 7789677Slinton 7799677Slinton #define UREAD 3 /* read from process's user structure */ 7809677Slinton #define UWRITE 6 /* write to process's user structure */ 7819677Slinton #define IREAD 1 /* read from process's instruction space */ 7829677Slinton #define IWRITE 4 /* write to process's instruction space */ 7839677Slinton #define DREAD 2 /* read from process's data space */ 7849677Slinton #define DWRITE 5 /* write to process's data space */ 7859677Slinton #define CONT 7 /* continue stopped process */ 7869677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 7879677Slinton #define PKILL 8 /* terminate the process */ 7889677Slinton 7899677Slinton /* 7909677Slinton * Start up a new process by forking and exec-ing the 7919677Slinton * given argument list, returning when the process is loaded 7929677Slinton * and ready to execute. The PROCESS information (pointed to 7939677Slinton * by the first argument) is appropriately filled. 7949677Slinton * 7959677Slinton * If the given PROCESS structure is associated with an already running 7969677Slinton * process, we terminate it. 7979677Slinton */ 7989677Slinton 7999677Slinton /* VARARGS2 */ 8009677Slinton private pstart(p, argv, infile, outfile) 8019677Slinton Process p; 8029677Slinton String argv[]; 8039677Slinton String infile; 8049677Slinton String outfile; 8059677Slinton { 8069677Slinton int status; 8079677Slinton 80816617Ssam if (p->pid != 0) { 80916617Ssam pterm(p); 8109677Slinton } 8119677Slinton psigtrace(p, SIGTRAP, true); 81214395Slinton p->pid = vfork(); 81314395Slinton if (p->pid == -1) { 8149677Slinton panic("can't fork"); 8159677Slinton } 8169677Slinton if (ischild(p->pid)) { 8179677Slinton traceme(); 8189677Slinton if (infile != nil) { 81916617Ssam infrom(infile); 8209677Slinton } 8219677Slinton if (outfile != nil) { 82216617Ssam outto(outfile); 8239677Slinton } 82411832Slinton execv(argv[0], argv); 82511172Slinton write(2, "can't exec ", 11); 82611172Slinton write(2, argv[0], strlen(argv[0])); 82711172Slinton write(2, "\n", 1); 82811172Slinton _exit(1); 8299677Slinton } 8309677Slinton pwait(p->pid, &status); 8319677Slinton getinfo(p, status); 8329677Slinton if (p->status != STOPPED) { 8339677Slinton error("program could not begin execution"); 8349677Slinton } 83514395Slinton ptraced(p->pid); 8369677Slinton } 8379677Slinton 8389677Slinton /* 83916617Ssam * Terminate a ptrace'd process. 84016617Ssam */ 84116617Ssam 84216617Ssam public pterm (p) 84316617Ssam Process p; 84416617Ssam { 84516617Ssam integer status; 84616617Ssam 84716617Ssam if (p != nil and p->pid != 0) { 84816617Ssam ptrace(PKILL, p->pid, 0, 0); 84916617Ssam pwait(p->pid, &status); 85016617Ssam unptraced(p->pid); 85116617Ssam } 85216617Ssam } 85316617Ssam 85416617Ssam /* 85511867Slinton * Continue a stopped process. The first argument points to a Process 85611867Slinton * structure. Before the process is restarted it's user area is modified 85711867Slinton * according to the values in the structure. When this routine finishes, 8589677Slinton * the structure has the new values from the process's user area. 8599677Slinton * 8609677Slinton * Pcont terminates when the process stops with a signal pending that 8619677Slinton * is being traced (via psigtrace), or when the process terminates. 8629677Slinton */ 8639677Slinton 86411867Slinton private pcont(p, signo) 8659677Slinton Process p; 86611867Slinton int signo; 8679677Slinton { 86816617Ssam int s, status; 8699677Slinton 8709677Slinton if (p->pid == 0) { 8719677Slinton error("program not active"); 8729677Slinton } 87316617Ssam s = signo; 8749677Slinton do { 87516617Ssam setinfo(p, s); 87616617Ssam if (traceexec) { 87716617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n", 87816617Ssam p->reg[PROGCTR], s, p->signo); 87916617Ssam fflush(stdout); 88016617Ssam } 8819677Slinton sigs_off(); 8829677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 88314395Slinton panic("error %d trying to continue process", errno); 8849677Slinton } 8859677Slinton pwait(p->pid, &status); 8869677Slinton sigs_on(); 8879677Slinton getinfo(p, status); 88816617Ssam if (traceexec and not istraced(p)) { 88916617Ssam printf("!! ignored signal %d at 0x%x\n", p->signo, p->reg[PROGCTR]); 89016617Ssam fflush(stdout); 89116617Ssam } 89216617Ssam s = p->signo; 8939677Slinton } while (p->status == STOPPED and not istraced(p)); 89416617Ssam if (traceexec) { 89516617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 89616617Ssam fflush(stdout); 89716617Ssam } 8989677Slinton } 8999677Slinton 9009677Slinton /* 9019677Slinton * Single step as best ptrace can. 9029677Slinton */ 9039677Slinton 90416617Ssam public pstep(p, signo) 9059677Slinton Process p; 90616617Ssam integer signo; 9079677Slinton { 9089677Slinton int status; 9099677Slinton 91016617Ssam setinfo(p, signo); 91116617Ssam if (traceexec) { 91216617Ssam printf("!! pstep from pc 0x%x with signal %d (%d)\n", 91316617Ssam p->reg[PROGCTR], signo, p->signo); 91416617Ssam fflush(stdout); 91516617Ssam } 9169677Slinton sigs_off(); 91716617Ssam if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { 91816617Ssam panic("error %d trying to step process", errno); 91916617Ssam } 9209677Slinton pwait(p->pid, &status); 9219677Slinton sigs_on(); 9229677Slinton getinfo(p, status); 92316617Ssam if (traceexec) { 92416617Ssam printf("!! pstep to pc 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 92516617Ssam fflush(stdout); 92616617Ssam } 92716617Ssam if (p->status != STOPPED) { 92816617Ssam error("program unexpectedly exited with %d\n", p->exitval); 92916617Ssam } 9309677Slinton } 9319677Slinton 9329677Slinton /* 9339677Slinton * Return from execution when the given signal is pending. 9349677Slinton */ 9359677Slinton 9369677Slinton public psigtrace(p, sig, sw) 9379677Slinton Process p; 9389677Slinton int sig; 9399677Slinton Boolean sw; 9409677Slinton { 9419677Slinton if (sw) { 9429677Slinton p->sigset |= setrep(sig); 9439677Slinton } else { 9449677Slinton p->sigset &= ~setrep(sig); 9459677Slinton } 9469677Slinton } 9479677Slinton 9489677Slinton /* 9499677Slinton * Don't catch any signals. 9509677Slinton * Particularly useful when letting a process finish uninhibited. 9519677Slinton */ 9529677Slinton 9539677Slinton public unsetsigtraces(p) 9549677Slinton Process p; 9559677Slinton { 9569677Slinton p->sigset = 0; 9579677Slinton } 9589677Slinton 9599677Slinton /* 9609677Slinton * Turn off attention to signals not being caught. 9619677Slinton */ 9629677Slinton 9639677Slinton private Intfunc *sigfunc[NSIG]; 9649677Slinton 9659677Slinton private sigs_off() 9669677Slinton { 9679677Slinton register int i; 9689677Slinton 9699677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 9709677Slinton if (i != SIGKILL) { 9719677Slinton sigfunc[i] = signal(i, SIG_IGN); 9729677Slinton } 9739677Slinton } 9749677Slinton } 9759677Slinton 9769677Slinton /* 9779677Slinton * Turn back on attention to signals. 9789677Slinton */ 9799677Slinton 9809677Slinton private sigs_on() 9819677Slinton { 9829677Slinton register int i; 9839677Slinton 9849677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 9859677Slinton if (i != SIGKILL) { 9869677Slinton signal(i, sigfunc[i]); 9879677Slinton } 9889677Slinton } 9899677Slinton } 9909677Slinton 9919677Slinton /* 9929677Slinton * Get process information from user area. 9939677Slinton */ 9949677Slinton 9959677Slinton private int rloc[] ={ 9969677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 9979677Slinton }; 9989677Slinton 9999677Slinton private getinfo(p, status) 10009677Slinton register Process p; 10019677Slinton register int status; 10029677Slinton { 10039677Slinton register int i; 100416617Ssam Address addr; 10059677Slinton 10069677Slinton p->signo = (status&0177); 10079677Slinton p->exitval = ((status >> 8)&0377); 10089677Slinton if (p->signo != STOPPED) { 10099677Slinton p->status = FINISHED; 101014757Slinton p->pid = 0; 101116617Ssam p->reg[PROGCTR] = 0; 10129677Slinton } else { 10139677Slinton p->status = p->signo; 10149677Slinton p->signo = p->exitval; 1015*16931Ssam p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0); 10169677Slinton p->exitval = 0; 10179677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 10189677Slinton for (i = 0; i < NREG; i++) { 10199677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 10209677Slinton p->oreg[i] = p->reg[i]; 10219677Slinton } 102211768Slinton savetty(stdout, &(p->ttyinfo)); 102316617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); 102416617Ssam p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); 10259677Slinton } 10269677Slinton } 10279677Slinton 10289677Slinton /* 10299677Slinton * Set process's user area information from given process structure. 10309677Slinton */ 10319677Slinton 103211867Slinton private setinfo(p, signo) 10339677Slinton register Process p; 103411867Slinton int signo; 10359677Slinton { 10369677Slinton register int i; 10379677Slinton register int r; 10389677Slinton 103914757Slinton if (signo == DEFSIG) { 104016617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { 104114757Slinton p->signo = 0; 104214757Slinton } 104314757Slinton } else { 104411867Slinton p->signo = signo; 10459677Slinton } 10469677Slinton for (i = 0; i < NREG; i++) { 10479677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 10489677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 10499677Slinton } 10509677Slinton } 105111768Slinton restoretty(stdout, &(p->ttyinfo)); 10529677Slinton } 10539677Slinton 10549677Slinton /* 105516617Ssam * Return the address associated with the current signal. 105616617Ssam * (Plus two since the address points to the beginning of a procedure). 105716617Ssam */ 105816617Ssam 105916617Ssam public Address usignal (p) 106016617Ssam Process p; 106116617Ssam { 106216617Ssam Address r; 106316617Ssam 106416617Ssam r = p->sigstatus; 106516617Ssam if (r != 0 and r != 1) { 106616617Ssam r += 2; 106716617Ssam } 106816617Ssam return r; 106916617Ssam } 107016617Ssam 107116617Ssam /* 10729677Slinton * Structure for reading and writing by words, but dealing with bytes. 10739677Slinton */ 10749677Slinton 10759677Slinton typedef union { 10769677Slinton Word pword; 10779677Slinton Byte pbyte[sizeof(Word)]; 10789677Slinton } Pword; 10799677Slinton 10809677Slinton /* 10819677Slinton * Read (write) from (to) the process' address space. 10829677Slinton * We must deal with ptrace's inability to look anywhere other 10839677Slinton * than at a word boundary. 10849677Slinton */ 10859677Slinton 10869677Slinton private Word fetch(); 10879677Slinton private store(); 10889677Slinton 10899677Slinton private pio(p, op, seg, buff, addr, nbytes) 10909677Slinton Process p; 10919677Slinton PioOp op; 10929677Slinton PioSeg seg; 10939677Slinton char *buff; 10949677Slinton Address addr; 10959677Slinton int nbytes; 10969677Slinton { 10979677Slinton register int i; 10989677Slinton register Address newaddr; 10999677Slinton register char *cp; 11009677Slinton char *bufend; 11019677Slinton Pword w; 11029677Slinton Address wordaddr; 11039677Slinton int byteoff; 11049677Slinton 11059677Slinton if (p->status != STOPPED) { 11069677Slinton error("program is not active"); 11079677Slinton } 11089677Slinton cp = buff; 11099677Slinton newaddr = addr; 11109677Slinton wordaddr = (newaddr&WMASK); 11119677Slinton if (wordaddr != newaddr) { 11129677Slinton w.pword = fetch(p, seg, wordaddr); 11139677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 11149677Slinton if (op == PREAD) { 11159677Slinton *cp++ = w.pbyte[i]; 11169677Slinton } else { 11179677Slinton w.pbyte[i] = *cp++; 11189677Slinton } 11199677Slinton nbytes--; 11209677Slinton } 11219677Slinton if (op == PWRITE) { 11229677Slinton store(p, seg, wordaddr, w.pword); 11239677Slinton } 11249677Slinton newaddr = wordaddr + sizeof(Word); 11259677Slinton } 11269677Slinton byteoff = (nbytes&(~WMASK)); 11279677Slinton nbytes -= byteoff; 11289677Slinton bufend = cp + nbytes; 11299677Slinton while (cp < bufend) { 11309677Slinton if (op == PREAD) { 11319677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 11329677Slinton } else { 11339677Slinton store(p, seg, newaddr, *((Word *) cp)); 11349677Slinton } 11359677Slinton cp += sizeof(Word); 11369677Slinton newaddr += sizeof(Word); 11379677Slinton } 11389677Slinton if (byteoff > 0) { 11399677Slinton w.pword = fetch(p, seg, newaddr); 11409677Slinton for (i = 0; i < byteoff; i++) { 11419677Slinton if (op == PREAD) { 11429677Slinton *cp++ = w.pbyte[i]; 11439677Slinton } else { 11449677Slinton w.pbyte[i] = *cp++; 11459677Slinton } 11469677Slinton } 11479677Slinton if (op == PWRITE) { 11489677Slinton store(p, seg, newaddr, w.pword); 11499677Slinton } 11509677Slinton } 11519677Slinton } 11529677Slinton 11539677Slinton /* 11549677Slinton * Get a word from a process at the given address. 11559677Slinton * The address is assumed to be on a word boundary. 11569677Slinton * 11579677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 11589677Slinton * to the instruction space since it is assumed to be pure. 11599677Slinton * 11609677Slinton * It is necessary to use a write-through scheme so that 11619677Slinton * breakpoints right next to each other don't interfere. 11629677Slinton */ 11639677Slinton 11649677Slinton private Integer nfetchs, nreads, nwrites; 11659677Slinton 11669677Slinton private Word fetch(p, seg, addr) 11679677Slinton Process p; 11689677Slinton PioSeg seg; 11699677Slinton register int addr; 11709677Slinton { 11719677Slinton register CacheWord *wp; 11729677Slinton register Word w; 11739677Slinton 11749677Slinton switch (seg) { 11759677Slinton case TEXTSEG: 11769677Slinton ++nfetchs; 11779677Slinton wp = &p->word[cachehash(addr)]; 11789677Slinton if (addr == 0 or wp->addr != addr) { 11799677Slinton ++nreads; 11809677Slinton w = ptrace(IREAD, p->pid, addr, 0); 11819677Slinton wp->addr = addr; 11829677Slinton wp->val = w; 11839677Slinton } else { 11849677Slinton w = wp->val; 11859677Slinton } 11869677Slinton break; 11879677Slinton 11889677Slinton case DATASEG: 11899677Slinton w = ptrace(DREAD, p->pid, addr, 0); 11909677Slinton break; 11919677Slinton 11929677Slinton default: 11939677Slinton panic("fetch: bad seg %d", seg); 11949677Slinton /* NOTREACHED */ 11959677Slinton } 11969677Slinton return w; 11979677Slinton } 11989677Slinton 11999677Slinton /* 12009677Slinton * Put a word into the process' address space at the given address. 12019677Slinton * The address is assumed to be on a word boundary. 12029677Slinton */ 12039677Slinton 12049677Slinton private store(p, seg, addr, data) 12059677Slinton Process p; 12069677Slinton PioSeg seg; 12079677Slinton int addr; 12089677Slinton Word data; 12099677Slinton { 12109677Slinton register CacheWord *wp; 12119677Slinton 12129677Slinton switch (seg) { 12139677Slinton case TEXTSEG: 12149677Slinton ++nwrites; 12159677Slinton wp = &p->word[cachehash(addr)]; 12169677Slinton wp->addr = addr; 12179677Slinton wp->val = data; 12189677Slinton ptrace(IWRITE, p->pid, addr, data); 12199677Slinton break; 12209677Slinton 12219677Slinton case DATASEG: 12229677Slinton ptrace(DWRITE, p->pid, addr, data); 12239677Slinton break; 12249677Slinton 12259677Slinton default: 12269677Slinton panic("store: bad seg %d", seg); 12279677Slinton /* NOTREACHED */ 12289677Slinton } 12299677Slinton } 12309677Slinton 12319677Slinton public printptraceinfo() 12329677Slinton { 12339677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 12349677Slinton } 12359677Slinton 12369677Slinton /* 123716617Ssam * Redirect input. 123816617Ssam * Assuming this is called from a child, we should be careful to avoid 123916617Ssam * (possibly) shared standard I/O buffers. 12409677Slinton */ 12419677Slinton 124216617Ssam private infrom (filename) 124316617Ssam String filename; 124416617Ssam { 124516617Ssam Fileid in; 124616617Ssam 124716617Ssam in = open(filename, 0); 124816617Ssam if (in == -1) { 124916617Ssam write(2, "can't read ", 11); 125016617Ssam write(2, filename, strlen(filename)); 125116617Ssam write(2, "\n", 1); 125216617Ssam _exit(1); 125316617Ssam } 125416617Ssam fswap(0, in); 125516617Ssam } 125616617Ssam 125716617Ssam /* 125816617Ssam * Redirect standard output. 125916617Ssam * Same assumptions as for "infrom" above. 126016617Ssam */ 126116617Ssam 126216617Ssam private outto (filename) 126316617Ssam String filename; 126416617Ssam { 126516617Ssam Fileid out; 126616617Ssam 126716617Ssam out = creat(filename, 0666); 126816617Ssam if (out == -1) { 126916617Ssam write(2, "can't write ", 12); 127016617Ssam write(2, filename, strlen(filename)); 127116617Ssam write(2, "\n", 1); 127216617Ssam _exit(1); 127316617Ssam } 127416617Ssam fswap(1, out); 127516617Ssam } 127616617Ssam 127716617Ssam /* 127816617Ssam * Swap file numbers, useful for redirecting standard input or output. 127916617Ssam */ 128016617Ssam 12819677Slinton private fswap(oldfd, newfd) 128216617Ssam Fileid oldfd; 128316617Ssam Fileid newfd; 12849677Slinton { 12859677Slinton if (oldfd != newfd) { 12869677Slinton close(oldfd); 12879677Slinton dup(newfd); 12889677Slinton close(newfd); 12899677Slinton } 12909677Slinton } 129116928Ssam 129216928Ssam #define bit(i) (1 << ((i)-1)) 129316928Ssam /* 129416928Ssam * Signal manipulation routines. 129516928Ssam */ 129616928Ssam static String signames[NSIG] = { 129716928Ssam 0, 129816928Ssam "HUP", 129916928Ssam "INT", 130016928Ssam "QUIT", 130116928Ssam "ILL", 130216928Ssam "TRAP", 130316928Ssam "IOT", 130416928Ssam "EMT", 130516928Ssam "FPE", 130616928Ssam "KILL", 130716928Ssam "BUS", 130816928Ssam "SEGV", 130916928Ssam "SYS", 131016928Ssam "PIPE", 131116928Ssam "ALRM", 131216928Ssam "TERM", 131316928Ssam 0, 131416928Ssam "STOP", 131516928Ssam "TSTP", 131616928Ssam "CONT", 131716928Ssam "CHLD", 131816928Ssam "TTIN", 131916928Ssam "TTOU", 132016928Ssam "TINT", 132116928Ssam "XCPU", 132216928Ssam "XFSZ", 132316928Ssam }; 132416928Ssam 132516928Ssam /* 132616928Ssam * Map a signal name to a number. 132716928Ssam */ 132816928Ssam public signalname(s) 132916928Ssam String s; 133016928Ssam { 133116928Ssam register String *p; 133216928Ssam 1333*16931Ssam if (strneq(s, "SIG", 3)) 1334*16931Ssam s += 3; 133516928Ssam for (p = signames; p < &signames[NSIG]; p++) 133616928Ssam if (*p && streq(*p, s)) 133716928Ssam return (p - signames); 133816928Ssam error("%s: Unknown signal.", s); 133916928Ssam } 134016928Ssam 134116928Ssam /* 134216928Ssam * Print all signals being ignored by the 134316928Ssam * debugger. These signals are auotmatically 134416928Ssam * passed on to the debugged process. 134516928Ssam */ 1346*16931Ssam public printsigsignored(p) 1347*16931Ssam Process p; 134816928Ssam { 134916928Ssam 1350*16931Ssam printsigs(~p->sigset); 135116928Ssam } 135216928Ssam 135316928Ssam /* 135416928Ssam * Print all signals being intercepted by 135516928Ssam * the debugger for the specified process. 135616928Ssam */ 1357*16931Ssam public printsigscaught(p) 1358*16931Ssam Process p; 135916928Ssam { 136016928Ssam 1361*16931Ssam printsigs(p->sigset); 1362*16931Ssam } 1363*16931Ssam 1364*16931Ssam private printsigs(vec) 1365*16931Ssam register Integer vec; 1366*16931Ssam { 1367*16931Ssam register Integer s; 1368*16931Ssam String sep = ""; 1369*16931Ssam 1370*16931Ssam for (s = 1; s < NSIG; s++) 1371*16931Ssam if (vec & bit(s) && signames[s]) { 1372*16931Ssam printf("%s%s", sep, signames[s]); 1373*16931Ssam sep = " "; 137416928Ssam } 1375*16931Ssam if (*sep != '\0') { 1376*16931Ssam putchar('\n'); 1377*16931Ssam fflush(stdout); 1378*16931Ssam } 137916928Ssam } 1380