1*21620Sdist /* 2*21620Sdist * Copyright (c) 1983 Regents of the University of California. 3*21620Sdist * All rights reserved. The Berkeley software License Agreement 4*21620Sdist * specifies the terms and conditions for redistribution. 5*21620Sdist */ 69677Slinton 7*21620Sdist #ifndef lint 8*21620Sdist static char sccsid[] = "@(#)process.c 5.1 (Berkeley) 05/31/85"; 9*21620Sdist #endif not lint 109677Slinton 1118230Slinton static char rcsid[] = "$Header: process.c,v 1.5 84/12/26 10:41:37 linton Exp $"; 1218230Slinton 139677Slinton /* 149677Slinton * Process management. 159677Slinton * 169677Slinton * This module contains the routines to manage the execution and 179677Slinton * tracing of the debuggee process. 189677Slinton */ 199677Slinton 209677Slinton #include "defs.h" 219677Slinton #include "process.h" 229677Slinton #include "machine.h" 239677Slinton #include "events.h" 249677Slinton #include "tree.h" 2514757Slinton #include "eval.h" 269677Slinton #include "operators.h" 279677Slinton #include "source.h" 289677Slinton #include "object.h" 299677Slinton #include "mappings.h" 309677Slinton #include "main.h" 319677Slinton #include "coredump.h" 329677Slinton #include <signal.h> 339677Slinton #include <errno.h> 349677Slinton #include <sys/param.h> 3516617Ssam #include <sys/dir.h> 3616617Ssam #include <sys/user.h> 379843Slinton #include <machine/reg.h> 389677Slinton #include <sys/stat.h> 399677Slinton 409677Slinton #ifndef public 419677Slinton 429677Slinton typedef struct Process *Process; 439677Slinton 449677Slinton Process process; 459677Slinton 4614757Slinton #define DEFSIG -1 4714757Slinton 489677Slinton #include "machine.h" 499677Slinton 509677Slinton #endif 519677Slinton 529677Slinton #define NOTSTARTED 1 539677Slinton #define STOPPED 0177 549677Slinton #define FINISHED 0 559677Slinton 569677Slinton /* 5716617Ssam * A cache of the instruction segment is kept to reduce the number 5816617Ssam * of system calls. Might be better just to read the entire 5916617Ssam * code space into memory. 609677Slinton */ 619677Slinton 629677Slinton #define CSIZE 1003 /* size of instruction cache */ 639677Slinton 649677Slinton typedef struct { 659677Slinton Word addr; 669677Slinton Word val; 679677Slinton } CacheWord; 689677Slinton 699677Slinton /* 709677Slinton * This structure holds the information we need from the user structure. 719677Slinton */ 729677Slinton 739677Slinton struct Process { 749677Slinton int pid; /* process being traced */ 7511768Slinton int mask; /* process status word */ 7611768Slinton Word reg[NREG]; /* process' registers */ 779677Slinton Word oreg[NREG]; /* registers when process last stopped */ 789677Slinton short status; /* either STOPPED or FINISHED */ 799677Slinton short signo; /* signal that stopped process */ 8018230Slinton short sigcode; /* extra signal information */ 819677Slinton int exitval; /* return value from exit() */ 829677Slinton long sigset; /* bit array of traced signals */ 839677Slinton CacheWord word[CSIZE]; /* text segment cache */ 8411768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 8516617Ssam Address sigstatus; /* process' handler for current signal */ 869677Slinton }; 879677Slinton 889677Slinton /* 899677Slinton * These definitions are for the arguments to "pio". 909677Slinton */ 919677Slinton 929677Slinton typedef enum { PREAD, PWRITE } PioOp; 939677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 949677Slinton 959677Slinton private struct Process pbuf; 969677Slinton 9718230Slinton #define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */ 989677Slinton 9914395Slinton extern int errno; 10014395Slinton 1019677Slinton private Boolean just_started; 1029677Slinton private int argc; 1039677Slinton private String argv[MAXNCMDARGS]; 1049677Slinton private String infile, outfile; 1059677Slinton 1069677Slinton /* 1079677Slinton * Initialize process information. 1089677Slinton */ 1099677Slinton 1109677Slinton public process_init() 1119677Slinton { 1129677Slinton register Integer i; 1139677Slinton Char buf[10]; 1149677Slinton 1159677Slinton process = &pbuf; 1169677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1179677Slinton setsigtrace(); 1189677Slinton for (i = 0; i < NREG; i++) { 1199677Slinton sprintf(buf, "$r%d", i); 1209677Slinton defregname(identname(buf, false), i); 1219677Slinton } 1229677Slinton defregname(identname("$ap", true), ARGP); 1239677Slinton defregname(identname("$fp", true), FRP); 1249677Slinton defregname(identname("$sp", true), STKP); 1259677Slinton defregname(identname("$pc", true), PROGCTR); 1269677Slinton if (coredump) { 1279677Slinton coredump_readin(process->mask, process->reg, process->signo); 12812484Slinton pc = process->reg[PROGCTR]; 12912484Slinton getsrcpos(); 1309677Slinton } 13112484Slinton arginit(); 1329677Slinton } 1339677Slinton 1349677Slinton /* 1359677Slinton * Routines to get at process information from outside this module. 1369677Slinton */ 1379677Slinton 1389677Slinton public Word reg(n) 1399677Slinton Integer n; 1409677Slinton { 1419677Slinton register Word w; 1429677Slinton 1439677Slinton if (n == NREG) { 1449677Slinton w = process->mask; 1459677Slinton } else { 1469677Slinton w = process->reg[n]; 1479677Slinton } 1489677Slinton return w; 1499677Slinton } 1509677Slinton 1519677Slinton public setreg(n, w) 1529677Slinton Integer n; 1539677Slinton Word w; 1549677Slinton { 1559677Slinton process->reg[n] = w; 1569677Slinton } 1579677Slinton 1589677Slinton /* 1599677Slinton * Begin execution. 1609677Slinton * 1619677Slinton * We set a breakpoint at the end of the code so that the 1629677Slinton * process data doesn't disappear after the program terminates. 1639677Slinton */ 1649677Slinton 1659677Slinton private Boolean remade(); 1669677Slinton 1679677Slinton public start(argv, infile, outfile) 1689677Slinton String argv[]; 1699677Slinton String infile, outfile; 1709677Slinton { 1719677Slinton String pargv[4]; 1729677Slinton Node cond; 1739677Slinton 1749677Slinton if (coredump) { 1759677Slinton coredump = false; 1769677Slinton fclose(corefile); 1779677Slinton coredump_close(); 1789677Slinton } 1799677Slinton if (argv == nil) { 1809677Slinton argv = pargv; 1819677Slinton pargv[0] = objname; 1829677Slinton pargv[1] = nil; 1839677Slinton } else { 1849677Slinton argv[argc] = nil; 1859677Slinton } 18618230Slinton pstart(process, argv, infile, outfile); 1879677Slinton if (remade(objname)) { 1889677Slinton reinit(argv, infile, outfile); 1899677Slinton } 1909677Slinton if (process->status == STOPPED) { 1919677Slinton pc = 0; 19216617Ssam setcurfunc(program); 1939677Slinton if (objsize != 0) { 1949677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1959677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1969677Slinton } 1979677Slinton } 1989677Slinton } 1999677Slinton 2009677Slinton /* 2019677Slinton * Check to see if the object file has changed since the symbolic 2029677Slinton * information last was read. 2039677Slinton */ 2049677Slinton 2059677Slinton private time_t modtime; 2069677Slinton 2079677Slinton private Boolean remade(filename) 2089677Slinton String filename; 2099677Slinton { 2109677Slinton struct stat s; 2119677Slinton Boolean b; 2129677Slinton 2139677Slinton stat(filename, &s); 2149677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2159677Slinton modtime = s.st_mtime; 2169677Slinton return b; 2179677Slinton } 2189677Slinton 2199677Slinton /* 2209677Slinton * Set up what signals we want to trace. 2219677Slinton */ 2229677Slinton 2239677Slinton private setsigtrace() 2249677Slinton { 2259677Slinton register Integer i; 2269677Slinton register Process p; 2279677Slinton 2289677Slinton p = process; 2299677Slinton for (i = 1; i <= NSIG; i++) { 2309677Slinton psigtrace(p, i, true); 2319677Slinton } 2329677Slinton psigtrace(p, SIGHUP, false); 2339677Slinton psigtrace(p, SIGKILL, false); 2349677Slinton psigtrace(p, SIGALRM, false); 2359677Slinton psigtrace(p, SIGTSTP, false); 2369677Slinton psigtrace(p, SIGCONT, false); 2379677Slinton psigtrace(p, SIGCHLD, false); 2389677Slinton } 2399677Slinton 2409677Slinton /* 2419677Slinton * Initialize the argument list. 2429677Slinton */ 2439677Slinton 2449677Slinton public arginit() 2459677Slinton { 2469677Slinton infile = nil; 2479677Slinton outfile = nil; 2489677Slinton argv[0] = objname; 2499677Slinton argc = 1; 2509677Slinton } 2519677Slinton 2529677Slinton /* 2539677Slinton * Add an argument to the list for the debuggee. 2549677Slinton */ 2559677Slinton 2569677Slinton public newarg(arg) 2579677Slinton String arg; 2589677Slinton { 2599677Slinton if (argc >= MAXNCMDARGS) { 2609677Slinton error("too many arguments"); 2619677Slinton } 2629677Slinton argv[argc++] = arg; 2639677Slinton } 2649677Slinton 2659677Slinton /* 2669677Slinton * Set the standard input for the debuggee. 2679677Slinton */ 2689677Slinton 2699677Slinton public inarg(filename) 2709677Slinton String filename; 2719677Slinton { 2729677Slinton if (infile != nil) { 2739677Slinton error("multiple input redirects"); 2749677Slinton } 2759677Slinton infile = filename; 2769677Slinton } 2779677Slinton 2789677Slinton /* 2799677Slinton * Set the standard output for the debuggee. 2809677Slinton * Probably should check to avoid overwriting an existing file. 2819677Slinton */ 2829677Slinton 2839677Slinton public outarg(filename) 2849677Slinton String filename; 2859677Slinton { 2869677Slinton if (outfile != nil) { 2879677Slinton error("multiple output redirect"); 2889677Slinton } 2899677Slinton outfile = filename; 2909677Slinton } 2919677Slinton 2929677Slinton /* 2939677Slinton * Start debuggee executing. 2949677Slinton */ 2959677Slinton 2969677Slinton public run() 2979677Slinton { 2989677Slinton process->status = STOPPED; 2999677Slinton fixbps(); 3009677Slinton curline = 0; 3019677Slinton start(argv, infile, outfile); 3029677Slinton just_started = true; 3039677Slinton isstopped = false; 30414757Slinton cont(0); 3059677Slinton } 3069677Slinton 3079677Slinton /* 3089677Slinton * Continue execution wherever we left off. 3099677Slinton * 3109677Slinton * Note that this routine never returns. Eventually bpact() will fail 3119677Slinton * and we'll call printstatus or step will call it. 3129677Slinton */ 3139677Slinton 3149677Slinton typedef int Intfunc(); 3159677Slinton 3169677Slinton private Intfunc *dbintr; 3179677Slinton private intr(); 3189677Slinton 31911867Slinton public cont(signo) 32016617Ssam integer signo; 3219677Slinton { 32216617Ssam integer s; 32316617Ssam 3249677Slinton dbintr = signal(SIGINT, intr); 3259677Slinton if (just_started) { 3269677Slinton just_started = false; 3279677Slinton } else { 3289677Slinton if (not isstopped) { 3299677Slinton error("can't continue execution"); 3309677Slinton } 3319677Slinton isstopped = false; 33211867Slinton stepover(); 3339677Slinton } 33416617Ssam s = signo; 3359677Slinton for (;;) { 3369677Slinton if (single_stepping) { 3379677Slinton printnews(); 3389677Slinton } else { 3399677Slinton setallbps(); 34016617Ssam resume(s); 3419677Slinton unsetallbps(); 34216617Ssam s = DEFSIG; 34318230Slinton if (not isbperr() or not bpact()) { 3449677Slinton printstatus(); 3459677Slinton } 3469677Slinton } 34711867Slinton stepover(); 3489677Slinton } 3499677Slinton /* NOTREACHED */ 3509677Slinton } 3519677Slinton 3529677Slinton /* 35318230Slinton * This routine is called if we get an interrupt while "running" 3549677Slinton * but actually in the debugger. Could happen, for example, while 3559677Slinton * processing breakpoints. 3569677Slinton * 3579677Slinton * We basically just want to keep going; the assumption is 35818230Slinton * that when the process resumes it will get the interrupt, 3599677Slinton * which will then be handled. 3609677Slinton */ 3619677Slinton 3629677Slinton private intr() 3639677Slinton { 3649677Slinton signal(SIGINT, intr); 3659677Slinton } 3669677Slinton 3679677Slinton public fixintr() 3689677Slinton { 3699677Slinton signal(SIGINT, dbintr); 3709677Slinton } 3719677Slinton 3729677Slinton /* 3739677Slinton * Resume execution. 3749677Slinton */ 3759677Slinton 37611867Slinton public resume(signo) 37711867Slinton int signo; 3789677Slinton { 3799677Slinton register Process p; 3809677Slinton 3819677Slinton p = process; 38211867Slinton pcont(p, signo); 3839677Slinton pc = process->reg[PROGCTR]; 38411832Slinton if (p->status != STOPPED) { 38511867Slinton if (p->signo != 0) { 38611867Slinton error("program terminated by signal %d", p->signo); 38714757Slinton } else if (not runfirst) { 38818230Slinton if (p->exitval == 0) { 38918230Slinton error("program exited"); 39018230Slinton } else { 39118230Slinton error("program exited with code %d", p->exitval); 39218230Slinton } 39311867Slinton } 39411832Slinton } 3959677Slinton } 3969677Slinton 3979677Slinton /* 3989677Slinton * Continue execution up to the next source line. 3999677Slinton * 4009677Slinton * There are two ways to define the next source line depending on what 4019677Slinton * is desired when a procedure or function call is encountered. Step 4029677Slinton * stops at the beginning of the procedure or call; next skips over it. 4039677Slinton */ 4049677Slinton 4059677Slinton /* 4069677Slinton * Stepc is what is called when the step command is given. 4079677Slinton * It has to play with the "isstopped" information. 4089677Slinton */ 4099677Slinton 4109677Slinton public stepc() 4119677Slinton { 4129677Slinton if (not isstopped) { 4139677Slinton error("can't continue execution"); 4149677Slinton } 4159677Slinton isstopped = false; 4169677Slinton dostep(false); 4179677Slinton isstopped = true; 4189677Slinton } 4199677Slinton 4209677Slinton public next() 4219677Slinton { 42216617Ssam Address oldfrp, newfrp; 42316617Ssam 4249677Slinton if (not isstopped) { 4259677Slinton error("can't continue execution"); 4269677Slinton } 4279677Slinton isstopped = false; 42816617Ssam oldfrp = reg(FRP); 42916617Ssam do { 43016617Ssam dostep(true); 43116617Ssam pc = reg(PROGCTR); 43216617Ssam newfrp = reg(FRP); 43316617Ssam } while (newfrp < oldfrp and newfrp != 0); 4349677Slinton isstopped = true; 4359677Slinton } 4369677Slinton 43711867Slinton /* 43816617Ssam * Continue execution until the current function returns, or, 43916617Ssam * if the given argument is non-nil, until execution returns to 44016617Ssam * somewhere within the given function. 44116617Ssam */ 44216617Ssam 44316617Ssam public rtnfunc (f) 44416617Ssam Symbol f; 44516617Ssam { 44616617Ssam Address addr; 44716617Ssam Symbol t; 44816617Ssam 44916617Ssam if (not isstopped) { 45016617Ssam error("can't continue execution"); 45116617Ssam } else if (f != nil and not isactive(f)) { 45216617Ssam error("%s is not active", symname(f)); 45316617Ssam } else { 45416617Ssam addr = return_addr(); 45516617Ssam if (addr == nil) { 45616617Ssam error("no place to return to"); 45716617Ssam } else { 45816617Ssam isstopped = false; 45916617Ssam contto(addr); 46016617Ssam if (f != nil) { 46116617Ssam for (;;) { 46216617Ssam t = whatblock(pc); 46316617Ssam addr = return_addr(); 46416617Ssam if (t == f or addr == nil) break; 46516617Ssam contto(addr); 46616617Ssam } 46716617Ssam } 46818230Slinton if (not bpact()) { 46916617Ssam isstopped = true; 47016617Ssam printstatus(); 47116617Ssam } 47216617Ssam } 47316617Ssam } 47416617Ssam } 47516617Ssam 47616617Ssam /* 47711867Slinton * Single-step over the current machine instruction. 47811867Slinton * 47911867Slinton * If we're single-stepping by source line we want to step to the 48011867Slinton * next source line. Otherwise we're going to continue so there's 48111867Slinton * no reason to do all the work necessary to single-step to the next 48211867Slinton * source line. 48311867Slinton */ 48411867Slinton 48516617Ssam public stepover() 4869677Slinton { 48711867Slinton Boolean b; 48811867Slinton 48916617Ssam if (traceexec) { 49016617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); 49116617Ssam } 49211867Slinton if (single_stepping) { 49311867Slinton dostep(false); 49411867Slinton } else { 49511867Slinton b = inst_tracing; 49611867Slinton inst_tracing = true; 49711867Slinton dostep(false); 49811867Slinton inst_tracing = b; 49911867Slinton } 50016617Ssam if (traceexec) { 50116617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); 50216617Ssam } 5039677Slinton } 5049677Slinton 5059677Slinton /* 50618230Slinton * Resume execution up to the given address. We can either ignore 50718230Slinton * breakpoints (stepto) or catch them (contto). 5089677Slinton */ 5099677Slinton 5109677Slinton public stepto(addr) 5119677Slinton Address addr; 5129677Slinton { 51316617Ssam xto(addr, false); 51416617Ssam } 51516617Ssam 51616617Ssam private contto (addr) 51716617Ssam Address addr; 51816617Ssam { 51916617Ssam xto(addr, true); 52016617Ssam } 52116617Ssam 52216617Ssam private xto (addr, catchbps) 52316617Ssam Address addr; 52416617Ssam boolean catchbps; 52516617Ssam { 52616617Ssam Address curpc; 52716617Ssam 52816617Ssam if (catchbps) { 52916617Ssam stepover(); 5309677Slinton } 53116617Ssam curpc = process->reg[PROGCTR]; 53216617Ssam if (addr != curpc) { 53316617Ssam if (traceexec) { 53416617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); 53516617Ssam } 53616617Ssam if (catchbps) { 53716617Ssam setallbps(); 53816617Ssam } 53916617Ssam setbp(addr); 54016617Ssam resume(DEFSIG); 54116617Ssam unsetbp(addr); 54216617Ssam if (catchbps) { 54316617Ssam unsetallbps(); 54416617Ssam } 54516617Ssam if (not isbperr()) { 54616617Ssam printstatus(); 54716617Ssam } 54816617Ssam } 5499677Slinton } 5509677Slinton 5519677Slinton /* 5529677Slinton * Print the status of the process. 5539677Slinton * This routine does not return. 5549677Slinton */ 5559677Slinton 5569677Slinton public printstatus() 5579677Slinton { 55814395Slinton int status; 55914395Slinton 5609843Slinton if (process->status == FINISHED) { 5619843Slinton exit(0); 5629843Slinton } else { 56316617Ssam setcurfunc(whatblock(pc)); 5649677Slinton getsrcpos(); 5659843Slinton if (process->signo == SIGINT) { 5669843Slinton isstopped = true; 5679843Slinton printerror(); 5689843Slinton } else if (isbperr() and isstopped) { 5699843Slinton printf("stopped "); 57011172Slinton printloc(); 57111172Slinton putchar('\n'); 5729843Slinton if (curline > 0) { 5739843Slinton printlines(curline, curline); 5749843Slinton } else { 5759843Slinton printinst(pc, pc); 5769843Slinton } 5779843Slinton erecover(); 5789677Slinton } else { 5799843Slinton fixintr(); 5809677Slinton isstopped = true; 5819677Slinton printerror(); 5829677Slinton } 5839677Slinton } 5849677Slinton } 5859677Slinton 5869677Slinton /* 58711172Slinton * Print out the current location in the debuggee. 58811172Slinton */ 58911172Slinton 59011172Slinton public printloc() 59111172Slinton { 59211172Slinton printf("in "); 59311172Slinton printname(stdout, curfunc); 59411172Slinton putchar(' '); 59514757Slinton if (curline > 0 and not useInstLoc) { 59611172Slinton printsrcpos(); 59711172Slinton } else { 59814757Slinton useInstLoc = false; 59914757Slinton curline = 0; 60011172Slinton printf("at 0x%x", pc); 60111172Slinton } 60211172Slinton } 60311172Slinton 60411172Slinton /* 6059677Slinton * Some functions for testing the state of the process. 6069677Slinton */ 6079677Slinton 6089677Slinton public Boolean notstarted(p) 6099677Slinton Process p; 6109677Slinton { 6119677Slinton return (Boolean) (p->status == NOTSTARTED); 6129677Slinton } 6139677Slinton 6149677Slinton public Boolean isfinished(p) 6159677Slinton Process p; 6169677Slinton { 6179677Slinton return (Boolean) (p->status == FINISHED); 6189677Slinton } 6199677Slinton 6209677Slinton /* 62118230Slinton * Predicate to test if the reason the process stopped was because 62218230Slinton * of a breakpoint. If so, as a side effect clear the local copy of 62318230Slinton * signal handler associated with process. We must do this so as to 62418230Slinton * not confuse future stepping or continuing by possibly concluding 62518230Slinton * the process should continue with a SIGTRAP handler. 6269677Slinton */ 6279677Slinton 62818230Slinton public boolean isbperr() 62918230Slinton { 63018230Slinton Process p; 63118230Slinton boolean b; 63218230Slinton 63318230Slinton p = process; 63418230Slinton if (p->status == STOPPED and p->signo == SIGTRAP) { 63518230Slinton b = true; 63618230Slinton p->sigstatus = 0; 63718230Slinton } else { 63818230Slinton b = false; 63918230Slinton } 64018230Slinton return b; 64118230Slinton } 64218230Slinton 64318230Slinton /* 64418230Slinton * Return the signal number that stopped the process. 64518230Slinton */ 64618230Slinton 64718230Slinton public integer errnum (p) 6489677Slinton Process p; 6499677Slinton { 6509677Slinton return p->signo; 6519677Slinton } 6529677Slinton 65318230Slinton /* 65418230Slinton * Return the signal code associated with the signal. 65518230Slinton */ 65618230Slinton 65718230Slinton public integer errcode (p) 65816931Ssam Process p; 65916931Ssam { 66016931Ssam return p->sigcode; 66116931Ssam } 66216931Ssam 6639677Slinton /* 6649677Slinton * Return the termination code of the process. 6659677Slinton */ 6669677Slinton 66718230Slinton public integer exitcode (p) 6689677Slinton Process p; 6699677Slinton { 6709677Slinton return p->exitval; 6719677Slinton } 6729677Slinton 6739677Slinton /* 6749677Slinton * These routines are used to access the debuggee process from 6759677Slinton * outside this module. 6769677Slinton * 6779677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 67814757Slinton * The system generates an I/O error when a ptrace fails. During reads 67914757Slinton * these are ignored, during writes they are reported as an error, and 68014757Slinton * for anything else they cause a fatal error. 6819677Slinton */ 6829677Slinton 6839677Slinton extern Intfunc *onsyserr(); 6849677Slinton 6859677Slinton private badaddr; 68614757Slinton private read_err(), write_err(); 6879677Slinton 6889677Slinton /* 6899677Slinton * Read from the process' instruction area. 6909677Slinton */ 6919677Slinton 6929677Slinton public iread(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_readtext(buff, addr, nbytes); 7039677Slinton } else { 7049677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 7059677Slinton } 7069677Slinton onsyserr(EIO, f); 7079677Slinton } 7089677Slinton 7099677Slinton /* 7109677Slinton * Write to the process' instruction area, usually in order to set 7119677Slinton * or unset a breakpoint. 7129677Slinton */ 7139677Slinton 7149677Slinton public iwrite(buff, addr, nbytes) 7159677Slinton char *buff; 7169677Slinton Address addr; 7179677Slinton int nbytes; 7189677Slinton { 7199677Slinton Intfunc *f; 7209677Slinton 7219677Slinton if (coredump) { 7229677Slinton error("no process to write to"); 7239677Slinton } 72414757Slinton f = onsyserr(EIO, write_err); 7259677Slinton badaddr = addr; 7269677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 7279677Slinton onsyserr(EIO, f); 7289677Slinton } 7299677Slinton 7309677Slinton /* 7319677Slinton * Read for the process' data area. 7329677Slinton */ 7339677Slinton 7349677Slinton public dread(buff, addr, nbytes) 7359677Slinton char *buff; 7369677Slinton Address addr; 7379677Slinton int nbytes; 7389677Slinton { 7399677Slinton Intfunc *f; 7409677Slinton 7419677Slinton badaddr = addr; 7429677Slinton if (coredump) { 74318230Slinton f = onsyserr(EFAULT, read_err); 7449677Slinton coredump_readdata(buff, addr, nbytes); 74518230Slinton onsyserr(EFAULT, f); 7469677Slinton } else { 74718230Slinton f = onsyserr(EIO, read_err); 7489677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 74918230Slinton onsyserr(EIO, f); 7509677Slinton } 7519677Slinton } 7529677Slinton 7539677Slinton /* 7549677Slinton * Write to the process' data area. 7559677Slinton */ 7569677Slinton 7579677Slinton public dwrite(buff, addr, nbytes) 7589677Slinton char *buff; 7599677Slinton Address addr; 7609677Slinton int nbytes; 7619677Slinton { 7629677Slinton Intfunc *f; 7639677Slinton 7649677Slinton if (coredump) { 7659677Slinton error("no process to write to"); 7669677Slinton } 76714757Slinton f = onsyserr(EIO, write_err); 7689677Slinton badaddr = addr; 7699677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 7709677Slinton onsyserr(EIO, f); 7719677Slinton } 7729677Slinton 7739677Slinton /* 77414757Slinton * Trap for errors in reading or writing to a process. 77514757Slinton * The current approach is to "ignore" read errors and complain 77614757Slinton * bitterly about write errors. 7779677Slinton */ 7789677Slinton 77914757Slinton private read_err() 7809677Slinton { 78111560Slinton /* 78214757Slinton * Ignore. 78311560Slinton */ 7849677Slinton } 7859677Slinton 78614757Slinton private write_err() 78714757Slinton { 78814757Slinton error("can't write to process (address 0x%x)", badaddr); 78914757Slinton } 79014757Slinton 7919677Slinton /* 7929677Slinton * Ptrace interface. 7939677Slinton */ 7949677Slinton 7959677Slinton /* 7969677Slinton * This magic macro enables us to look at the process' registers 79714757Slinton * in its user structure. 7989677Slinton */ 7999677Slinton 8009677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 8019677Slinton 8029677Slinton #define WMASK (~(sizeof(Word) - 1)) 8039677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 8049677Slinton 8059677Slinton #define FIRSTSIG SIGINT 8069677Slinton #define LASTSIG SIGQUIT 8079677Slinton #define ischild(pid) ((pid) == 0) 80818230Slinton #define traceme() ptrace(0, 0, 0, 0) 8099677Slinton #define setrep(n) (1 << ((n)-1)) 8109677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 8119677Slinton 8129677Slinton /* 81318230Slinton * Ptrace options (specified in first argument). 81418230Slinton */ 81518230Slinton 81618230Slinton #define UREAD 3 /* read from process's user structure */ 81718230Slinton #define UWRITE 6 /* write to process's user structure */ 81818230Slinton #define IREAD 1 /* read from process's instruction space */ 81918230Slinton #define IWRITE 4 /* write to process's instruction space */ 82018230Slinton #define DREAD 2 /* read from process's data space */ 82118230Slinton #define DWRITE 5 /* write to process's data space */ 82218230Slinton #define CONT 7 /* continue stopped process */ 82318230Slinton #define SSTEP 9 /* continue for approximately one instruction */ 82418230Slinton #define PKILL 8 /* terminate the process */ 82518230Slinton 82618230Slinton /* 8279677Slinton * Start up a new process by forking and exec-ing the 8289677Slinton * given argument list, returning when the process is loaded 8299677Slinton * and ready to execute. The PROCESS information (pointed to 8309677Slinton * by the first argument) is appropriately filled. 8319677Slinton * 8329677Slinton * If the given PROCESS structure is associated with an already running 8339677Slinton * process, we terminate it. 8349677Slinton */ 8359677Slinton 8369677Slinton /* VARARGS2 */ 8379677Slinton private pstart(p, argv, infile, outfile) 8389677Slinton Process p; 8399677Slinton String argv[]; 8409677Slinton String infile; 8419677Slinton String outfile; 8429677Slinton { 8439677Slinton int status; 8449677Slinton 84516617Ssam if (p->pid != 0) { 84616617Ssam pterm(p); 84718230Slinton cacheflush(p); 8489677Slinton } 84918230Slinton fflush(stdout); 8509677Slinton psigtrace(p, SIGTRAP, true); 85114395Slinton p->pid = vfork(); 85214395Slinton if (p->pid == -1) { 8539677Slinton panic("can't fork"); 8549677Slinton } 8559677Slinton if (ischild(p->pid)) { 85618230Slinton nocatcherrs(); 8579677Slinton traceme(); 8589677Slinton if (infile != nil) { 85916617Ssam infrom(infile); 8609677Slinton } 8619677Slinton if (outfile != nil) { 86216617Ssam outto(outfile); 8639677Slinton } 86411832Slinton execv(argv[0], argv); 86511172Slinton _exit(1); 8669677Slinton } 8679677Slinton pwait(p->pid, &status); 8689677Slinton getinfo(p, status); 8699677Slinton if (p->status != STOPPED) { 87018230Slinton beginerrmsg(); 87118230Slinton fprintf(stderr, "warning: cannot execute %s\n", argv[0]); 87218230Slinton } else { 87318230Slinton ptraced(p->pid); 8749677Slinton } 8759677Slinton } 8769677Slinton 8779677Slinton /* 87816617Ssam * Terminate a ptrace'd process. 87916617Ssam */ 88016617Ssam 88116617Ssam public pterm (p) 88216617Ssam Process p; 88316617Ssam { 88416617Ssam integer status; 88516617Ssam 88616617Ssam if (p != nil and p->pid != 0) { 88718230Slinton ptrace(PKILL, p->pid, 0, 0); 88816617Ssam pwait(p->pid, &status); 88916617Ssam unptraced(p->pid); 89016617Ssam } 89116617Ssam } 89216617Ssam 89316617Ssam /* 89411867Slinton * Continue a stopped process. The first argument points to a Process 89511867Slinton * structure. Before the process is restarted it's user area is modified 89611867Slinton * according to the values in the structure. When this routine finishes, 8979677Slinton * the structure has the new values from the process's user area. 8989677Slinton * 8999677Slinton * Pcont terminates when the process stops with a signal pending that 9009677Slinton * is being traced (via psigtrace), or when the process terminates. 9019677Slinton */ 9029677Slinton 90311867Slinton private pcont(p, signo) 9049677Slinton Process p; 90511867Slinton int signo; 9069677Slinton { 90716617Ssam int s, status; 9089677Slinton 9099677Slinton if (p->pid == 0) { 91018230Slinton error("program is not active"); 9119677Slinton } 91216617Ssam s = signo; 9139677Slinton do { 91416617Ssam setinfo(p, s); 91516617Ssam if (traceexec) { 91616617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n", 91716617Ssam p->reg[PROGCTR], s, p->signo); 91816617Ssam fflush(stdout); 91916617Ssam } 9209677Slinton sigs_off(); 92118230Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 92214395Slinton panic("error %d trying to continue process", errno); 9239677Slinton } 9249677Slinton pwait(p->pid, &status); 9259677Slinton sigs_on(); 9269677Slinton getinfo(p, status); 92718230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 92818230Slinton printf("!! ignored signal %d at 0x%x\n", 92918230Slinton p->signo, p->reg[PROGCTR]); 93016617Ssam fflush(stdout); 93116617Ssam } 93216617Ssam s = p->signo; 9339677Slinton } while (p->status == STOPPED and not istraced(p)); 93416617Ssam if (traceexec) { 93516617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 93616617Ssam fflush(stdout); 93716617Ssam } 9389677Slinton } 9399677Slinton 9409677Slinton /* 9419677Slinton * Single step as best ptrace can. 9429677Slinton */ 9439677Slinton 94416617Ssam public pstep(p, signo) 9459677Slinton Process p; 94616617Ssam integer signo; 9479677Slinton { 94818230Slinton int s, status; 9499677Slinton 95018230Slinton s = signo; 95118230Slinton do { 95218230Slinton setinfo(p, s); 95318230Slinton if (traceexec) { 95418230Slinton printf("!! pstep from 0x%x with signal %d (%d)\n", 95518230Slinton p->reg[PROGCTR], s, p->signo); 95618230Slinton fflush(stdout); 95718230Slinton } 95818230Slinton sigs_off(); 95918230Slinton if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { 96018230Slinton panic("error %d trying to step process", errno); 96118230Slinton } 96218230Slinton pwait(p->pid, &status); 96318230Slinton sigs_on(); 96418230Slinton getinfo(p, status); 96518230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 96618230Slinton printf("!! pstep ignored signal %d at 0x%x\n", 96718230Slinton p->signo, p->reg[PROGCTR]); 96818230Slinton fflush(stdout); 96918230Slinton } 97018230Slinton s = p->signo; 97118230Slinton } while (p->status == STOPPED and not istraced(p)); 97216617Ssam if (traceexec) { 97318230Slinton printf("!! pstep to 0x%x on signal %d\n", 97418230Slinton p->reg[PROGCTR], p->signo); 97516617Ssam fflush(stdout); 97616617Ssam } 97716617Ssam if (p->status != STOPPED) { 97818230Slinton if (p->exitval == 0) { 97918230Slinton error("program exited\n"); 98018230Slinton } else { 98118230Slinton error("program exited with code %d\n", p->exitval); 98218230Slinton } 98316617Ssam } 9849677Slinton } 9859677Slinton 9869677Slinton /* 9879677Slinton * Return from execution when the given signal is pending. 9889677Slinton */ 9899677Slinton 9909677Slinton public psigtrace(p, sig, sw) 9919677Slinton Process p; 9929677Slinton int sig; 9939677Slinton Boolean sw; 9949677Slinton { 9959677Slinton if (sw) { 9969677Slinton p->sigset |= setrep(sig); 9979677Slinton } else { 9989677Slinton p->sigset &= ~setrep(sig); 9999677Slinton } 10009677Slinton } 10019677Slinton 10029677Slinton /* 10039677Slinton * Don't catch any signals. 10049677Slinton * Particularly useful when letting a process finish uninhibited. 10059677Slinton */ 10069677Slinton 10079677Slinton public unsetsigtraces(p) 10089677Slinton Process p; 10099677Slinton { 10109677Slinton p->sigset = 0; 10119677Slinton } 10129677Slinton 10139677Slinton /* 10149677Slinton * Turn off attention to signals not being caught. 10159677Slinton */ 10169677Slinton 10179677Slinton private Intfunc *sigfunc[NSIG]; 10189677Slinton 10199677Slinton private sigs_off() 10209677Slinton { 10219677Slinton register int i; 10229677Slinton 10239677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10249677Slinton if (i != SIGKILL) { 10259677Slinton sigfunc[i] = signal(i, SIG_IGN); 10269677Slinton } 10279677Slinton } 10289677Slinton } 10299677Slinton 10309677Slinton /* 10319677Slinton * Turn back on attention to signals. 10329677Slinton */ 10339677Slinton 10349677Slinton private sigs_on() 10359677Slinton { 10369677Slinton register int i; 10379677Slinton 10389677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10399677Slinton if (i != SIGKILL) { 10409677Slinton signal(i, sigfunc[i]); 10419677Slinton } 10429677Slinton } 10439677Slinton } 10449677Slinton 10459677Slinton /* 10469677Slinton * Get process information from user area. 10479677Slinton */ 10489677Slinton 10499677Slinton private int rloc[] ={ 10509677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 10519677Slinton }; 10529677Slinton 10539677Slinton private getinfo(p, status) 10549677Slinton register Process p; 10559677Slinton register int status; 10569677Slinton { 10579677Slinton register int i; 105816617Ssam Address addr; 10599677Slinton 10609677Slinton p->signo = (status&0177); 10619677Slinton p->exitval = ((status >> 8)&0377); 10629677Slinton if (p->signo != STOPPED) { 10639677Slinton p->status = FINISHED; 106414757Slinton p->pid = 0; 106516617Ssam p->reg[PROGCTR] = 0; 10669677Slinton } else { 10679677Slinton p->status = p->signo; 10689677Slinton p->signo = p->exitval; 106918230Slinton p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0); 10709677Slinton p->exitval = 0; 107118230Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 10729677Slinton for (i = 0; i < NREG; i++) { 107318230Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 10749677Slinton p->oreg[i] = p->reg[i]; 10759677Slinton } 107611768Slinton savetty(stdout, &(p->ttyinfo)); 107716617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); 107818230Slinton p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); 10799677Slinton } 10809677Slinton } 10819677Slinton 10829677Slinton /* 10839677Slinton * Set process's user area information from given process structure. 10849677Slinton */ 10859677Slinton 108611867Slinton private setinfo(p, signo) 10879677Slinton register Process p; 108811867Slinton int signo; 10899677Slinton { 10909677Slinton register int i; 10919677Slinton register int r; 10929677Slinton 109314757Slinton if (signo == DEFSIG) { 109416617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { 109514757Slinton p->signo = 0; 109614757Slinton } 109714757Slinton } else { 109811867Slinton p->signo = signo; 10999677Slinton } 11009677Slinton for (i = 0; i < NREG; i++) { 11019677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 110218230Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 11039677Slinton } 11049677Slinton } 110511768Slinton restoretty(stdout, &(p->ttyinfo)); 11069677Slinton } 11079677Slinton 11089677Slinton /* 110916617Ssam * Return the address associated with the current signal. 111016617Ssam * (Plus two since the address points to the beginning of a procedure). 111116617Ssam */ 111216617Ssam 111316617Ssam public Address usignal (p) 111416617Ssam Process p; 111516617Ssam { 111616617Ssam Address r; 111716617Ssam 111816617Ssam r = p->sigstatus; 111916617Ssam if (r != 0 and r != 1) { 112016617Ssam r += 2; 112116617Ssam } 112216617Ssam return r; 112316617Ssam } 112416617Ssam 112516617Ssam /* 11269677Slinton * Structure for reading and writing by words, but dealing with bytes. 11279677Slinton */ 11289677Slinton 11299677Slinton typedef union { 11309677Slinton Word pword; 11319677Slinton Byte pbyte[sizeof(Word)]; 11329677Slinton } Pword; 11339677Slinton 11349677Slinton /* 11359677Slinton * Read (write) from (to) the process' address space. 11369677Slinton * We must deal with ptrace's inability to look anywhere other 11379677Slinton * than at a word boundary. 11389677Slinton */ 11399677Slinton 11409677Slinton private Word fetch(); 11419677Slinton private store(); 11429677Slinton 11439677Slinton private pio(p, op, seg, buff, addr, nbytes) 11449677Slinton Process p; 11459677Slinton PioOp op; 11469677Slinton PioSeg seg; 11479677Slinton char *buff; 11489677Slinton Address addr; 11499677Slinton int nbytes; 11509677Slinton { 11519677Slinton register int i; 11529677Slinton register Address newaddr; 11539677Slinton register char *cp; 11549677Slinton char *bufend; 11559677Slinton Pword w; 11569677Slinton Address wordaddr; 11579677Slinton int byteoff; 11589677Slinton 11599677Slinton if (p->status != STOPPED) { 11609677Slinton error("program is not active"); 11619677Slinton } 11629677Slinton cp = buff; 11639677Slinton newaddr = addr; 11649677Slinton wordaddr = (newaddr&WMASK); 11659677Slinton if (wordaddr != newaddr) { 11669677Slinton w.pword = fetch(p, seg, wordaddr); 11679677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 11689677Slinton if (op == PREAD) { 11699677Slinton *cp++ = w.pbyte[i]; 11709677Slinton } else { 11719677Slinton w.pbyte[i] = *cp++; 11729677Slinton } 11739677Slinton nbytes--; 11749677Slinton } 11759677Slinton if (op == PWRITE) { 11769677Slinton store(p, seg, wordaddr, w.pword); 11779677Slinton } 11789677Slinton newaddr = wordaddr + sizeof(Word); 11799677Slinton } 11809677Slinton byteoff = (nbytes&(~WMASK)); 11819677Slinton nbytes -= byteoff; 11829677Slinton bufend = cp + nbytes; 11839677Slinton while (cp < bufend) { 11849677Slinton if (op == PREAD) { 11859677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 11869677Slinton } else { 11879677Slinton store(p, seg, newaddr, *((Word *) cp)); 11889677Slinton } 11899677Slinton cp += sizeof(Word); 11909677Slinton newaddr += sizeof(Word); 11919677Slinton } 11929677Slinton if (byteoff > 0) { 11939677Slinton w.pword = fetch(p, seg, newaddr); 11949677Slinton for (i = 0; i < byteoff; i++) { 11959677Slinton if (op == PREAD) { 11969677Slinton *cp++ = w.pbyte[i]; 11979677Slinton } else { 11989677Slinton w.pbyte[i] = *cp++; 11999677Slinton } 12009677Slinton } 12019677Slinton if (op == PWRITE) { 12029677Slinton store(p, seg, newaddr, w.pword); 12039677Slinton } 12049677Slinton } 12059677Slinton } 12069677Slinton 12079677Slinton /* 12089677Slinton * Get a word from a process at the given address. 12099677Slinton * The address is assumed to be on a word boundary. 12109677Slinton * 12119677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 12129677Slinton * to the instruction space since it is assumed to be pure. 12139677Slinton * 12149677Slinton * It is necessary to use a write-through scheme so that 12159677Slinton * breakpoints right next to each other don't interfere. 12169677Slinton */ 12179677Slinton 12189677Slinton private Integer nfetchs, nreads, nwrites; 12199677Slinton 12209677Slinton private Word fetch(p, seg, addr) 12219677Slinton Process p; 12229677Slinton PioSeg seg; 12239677Slinton register int addr; 12249677Slinton { 12259677Slinton register CacheWord *wp; 12269677Slinton register Word w; 12279677Slinton 12289677Slinton switch (seg) { 12299677Slinton case TEXTSEG: 12309677Slinton ++nfetchs; 12319677Slinton wp = &p->word[cachehash(addr)]; 12329677Slinton if (addr == 0 or wp->addr != addr) { 12339677Slinton ++nreads; 123418230Slinton w = ptrace(IREAD, p->pid, addr, 0); 12359677Slinton wp->addr = addr; 12369677Slinton wp->val = w; 12379677Slinton } else { 12389677Slinton w = wp->val; 12399677Slinton } 12409677Slinton break; 12419677Slinton 12429677Slinton case DATASEG: 124318230Slinton w = ptrace(DREAD, p->pid, addr, 0); 12449677Slinton break; 12459677Slinton 12469677Slinton default: 12479677Slinton panic("fetch: bad seg %d", seg); 12489677Slinton /* NOTREACHED */ 12499677Slinton } 12509677Slinton return w; 12519677Slinton } 12529677Slinton 12539677Slinton /* 12549677Slinton * Put a word into the process' address space at the given address. 12559677Slinton * The address is assumed to be on a word boundary. 12569677Slinton */ 12579677Slinton 12589677Slinton private store(p, seg, addr, data) 12599677Slinton Process p; 12609677Slinton PioSeg seg; 12619677Slinton int addr; 12629677Slinton Word data; 12639677Slinton { 12649677Slinton register CacheWord *wp; 12659677Slinton 12669677Slinton switch (seg) { 12679677Slinton case TEXTSEG: 12689677Slinton ++nwrites; 12699677Slinton wp = &p->word[cachehash(addr)]; 12709677Slinton wp->addr = addr; 12719677Slinton wp->val = data; 127218230Slinton ptrace(IWRITE, p->pid, addr, data); 12739677Slinton break; 12749677Slinton 12759677Slinton case DATASEG: 127618230Slinton ptrace(DWRITE, p->pid, addr, data); 12779677Slinton break; 12789677Slinton 12799677Slinton default: 12809677Slinton panic("store: bad seg %d", seg); 12819677Slinton /* NOTREACHED */ 12829677Slinton } 12839677Slinton } 12849677Slinton 128518230Slinton /* 128618230Slinton * Flush the instruction cache associated with a process. 128718230Slinton */ 128818230Slinton 128918230Slinton private cacheflush (p) 129018230Slinton Process p; 129118230Slinton { 129218230Slinton bzero(p->word, sizeof(p->word)); 129318230Slinton } 129418230Slinton 12959677Slinton public printptraceinfo() 12969677Slinton { 12979677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 12989677Slinton } 12999677Slinton 13009677Slinton /* 130116617Ssam * Redirect input. 130216617Ssam * Assuming this is called from a child, we should be careful to avoid 130316617Ssam * (possibly) shared standard I/O buffers. 13049677Slinton */ 13059677Slinton 130616617Ssam private infrom (filename) 130716617Ssam String filename; 130816617Ssam { 130916617Ssam Fileid in; 131016617Ssam 131116617Ssam in = open(filename, 0); 131216617Ssam if (in == -1) { 131316617Ssam write(2, "can't read ", 11); 131416617Ssam write(2, filename, strlen(filename)); 131516617Ssam write(2, "\n", 1); 131616617Ssam _exit(1); 131716617Ssam } 131816617Ssam fswap(0, in); 131916617Ssam } 132016617Ssam 132116617Ssam /* 132216617Ssam * Redirect standard output. 132316617Ssam * Same assumptions as for "infrom" above. 132416617Ssam */ 132516617Ssam 132616617Ssam private outto (filename) 132716617Ssam String filename; 132816617Ssam { 132916617Ssam Fileid out; 133016617Ssam 133116617Ssam out = creat(filename, 0666); 133216617Ssam if (out == -1) { 133316617Ssam write(2, "can't write ", 12); 133416617Ssam write(2, filename, strlen(filename)); 133516617Ssam write(2, "\n", 1); 133616617Ssam _exit(1); 133716617Ssam } 133816617Ssam fswap(1, out); 133916617Ssam } 134016617Ssam 134116617Ssam /* 134216617Ssam * Swap file numbers, useful for redirecting standard input or output. 134316617Ssam */ 134416617Ssam 13459677Slinton private fswap(oldfd, newfd) 134616617Ssam Fileid oldfd; 134716617Ssam Fileid newfd; 13489677Slinton { 13499677Slinton if (oldfd != newfd) { 13509677Slinton close(oldfd); 13519677Slinton dup(newfd); 13529677Slinton close(newfd); 13539677Slinton } 13549677Slinton } 135516928Ssam 135616928Ssam /* 135718230Slinton * Signal name manipulation. 135816928Ssam */ 135918230Slinton 136018230Slinton private String signames[NSIG] = { 136118230Slinton 0, 136218230Slinton "HUP", "INT", "QUIT", "ILL", "TRAP", 136318230Slinton "IOT", "EMT", "FPE", "KILL", "BUS", 136418230Slinton "SEGV", "SYS", "PIPE", "ALRM", "TERM", 136518230Slinton 0, "STOP", "TSTP", "CONT", "CHLD", 136618230Slinton "TTIN", "TTOU", "TINT", "XCPU", "XFSZ", 136716928Ssam }; 136816928Ssam 136916928Ssam /* 137018230Slinton * Get the signal number associated with a given name. 137118230Slinton * The name is first translated to upper case if necessary. 137216928Ssam */ 137318230Slinton 137418230Slinton public integer siglookup (s) 137516928Ssam String s; 137616928Ssam { 137718230Slinton register char *p, *q; 137818230Slinton char buf[100]; 137918230Slinton integer i; 138016928Ssam 138118230Slinton p = s; 138218230Slinton q = buf; 138318230Slinton while (*p != '\0') { 138418230Slinton if (*p >= 'a' and *p <= 'z') { 138518230Slinton *q = (*p - 'a') + 'A'; 138618230Slinton } else { 138718230Slinton *q = *p; 138818230Slinton } 138918230Slinton ++p; 139018230Slinton ++q; 139118230Slinton } 139218230Slinton *q = '\0'; 139318230Slinton p = buf; 139418230Slinton if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') { 139518230Slinton p += 3; 139618230Slinton } 139718230Slinton i = 1; 139818230Slinton for (;;) { 139918230Slinton if (i >= sizeof(signames) div sizeof(signames[0])) { 140018230Slinton error("signal \"%s\" unknown", s); 140118230Slinton i = 0; 140218230Slinton break; 140318230Slinton } 140418230Slinton if (signames[i] != nil and streq(signames[i], p)) { 140518230Slinton break; 140618230Slinton } 140718230Slinton ++i; 140818230Slinton } 140918230Slinton return i; 141016928Ssam } 141116928Ssam 141216928Ssam /* 141318230Slinton * Print all signals being ignored by the debugger. 141418230Slinton * These signals are auotmatically 141516928Ssam * passed on to the debugged process. 141616928Ssam */ 141718230Slinton 141818230Slinton public printsigsignored (p) 141916931Ssam Process p; 142016928Ssam { 142116931Ssam printsigs(~p->sigset); 142216928Ssam } 142316928Ssam 142416928Ssam /* 142516928Ssam * Print all signals being intercepted by 142616928Ssam * the debugger for the specified process. 142716928Ssam */ 142818230Slinton 142916931Ssam public printsigscaught(p) 143016931Ssam Process p; 143116928Ssam { 143216931Ssam printsigs(p->sigset); 143316931Ssam } 143416931Ssam 143518230Slinton private printsigs (set) 143618230Slinton integer set; 143716931Ssam { 143818230Slinton integer s; 143918230Slinton char separator[2]; 144016931Ssam 144118230Slinton separator[0] = '\0'; 144218230Slinton for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) { 144318230Slinton if (set & setrep(s)) { 144418230Slinton if (signames[s] != nil) { 144518230Slinton printf("%s%s", separator, signames[s]); 144618230Slinton separator[0] = ' '; 144718230Slinton separator[1] = '\0'; 144818230Slinton } 144916928Ssam } 145018230Slinton } 145118230Slinton if (separator[0] == ' ') { 145216931Ssam putchar('\n'); 145316931Ssam } 145416928Ssam } 1455