121620Sdist /* 221620Sdist * Copyright (c) 1983 Regents of the University of California. 321620Sdist * All rights reserved. The Berkeley software License Agreement 421620Sdist * specifies the terms and conditions for redistribution. 521620Sdist */ 69677Slinton 721620Sdist #ifndef lint 8*26333Ssam static char sccsid[] = "@(#)process.c 5.2 (Berkeley) 02/23/86"; 921620Sdist #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/stat.h> 359677Slinton 369677Slinton #ifndef public 379677Slinton 389677Slinton typedef struct Process *Process; 399677Slinton 409677Slinton Process process; 419677Slinton 4214757Slinton #define DEFSIG -1 4314757Slinton 449677Slinton #include "machine.h" 459677Slinton 469677Slinton #endif 479677Slinton 489677Slinton #define NOTSTARTED 1 499677Slinton #define STOPPED 0177 509677Slinton #define FINISHED 0 519677Slinton 529677Slinton /* 5316617Ssam * A cache of the instruction segment is kept to reduce the number 5416617Ssam * of system calls. Might be better just to read the entire 5516617Ssam * code space into memory. 569677Slinton */ 579677Slinton 589677Slinton #define CSIZE 1003 /* size of instruction cache */ 599677Slinton 609677Slinton typedef struct { 619677Slinton Word addr; 629677Slinton Word val; 639677Slinton } CacheWord; 649677Slinton 659677Slinton /* 669677Slinton * This structure holds the information we need from the user structure. 679677Slinton */ 689677Slinton 699677Slinton struct Process { 709677Slinton int pid; /* process being traced */ 7111768Slinton int mask; /* process status word */ 7211768Slinton Word reg[NREG]; /* process' registers */ 739677Slinton Word oreg[NREG]; /* registers when process last stopped */ 749677Slinton short status; /* either STOPPED or FINISHED */ 759677Slinton short signo; /* signal that stopped process */ 7618230Slinton short sigcode; /* extra signal information */ 779677Slinton int exitval; /* return value from exit() */ 789677Slinton long sigset; /* bit array of traced signals */ 799677Slinton CacheWord word[CSIZE]; /* text segment cache */ 8011768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 8116617Ssam Address sigstatus; /* process' handler for current signal */ 829677Slinton }; 839677Slinton 849677Slinton /* 859677Slinton * These definitions are for the arguments to "pio". 869677Slinton */ 879677Slinton 889677Slinton typedef enum { PREAD, PWRITE } PioOp; 899677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 909677Slinton 919677Slinton private struct Process pbuf; 929677Slinton 9318230Slinton #define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */ 949677Slinton 9514395Slinton extern int errno; 9614395Slinton 979677Slinton private Boolean just_started; 989677Slinton private int argc; 999677Slinton private String argv[MAXNCMDARGS]; 1009677Slinton private String infile, outfile; 1019677Slinton 1029677Slinton /* 1039677Slinton * Initialize process information. 1049677Slinton */ 1059677Slinton 1069677Slinton public process_init() 1079677Slinton { 1089677Slinton register Integer i; 1099677Slinton Char buf[10]; 1109677Slinton 1119677Slinton process = &pbuf; 1129677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1139677Slinton setsigtrace(); 1149677Slinton for (i = 0; i < NREG; i++) { 1159677Slinton sprintf(buf, "$r%d", i); 1169677Slinton defregname(identname(buf, false), i); 1179677Slinton } 118*26333Ssam #ifdef vax 1199677Slinton defregname(identname("$ap", true), ARGP); 120*26333Ssam #endif 1219677Slinton defregname(identname("$fp", true), FRP); 1229677Slinton defregname(identname("$sp", true), STKP); 1239677Slinton defregname(identname("$pc", true), PROGCTR); 1249677Slinton if (coredump) { 1259677Slinton coredump_readin(process->mask, process->reg, process->signo); 12612484Slinton pc = process->reg[PROGCTR]; 12712484Slinton getsrcpos(); 1289677Slinton } 12912484Slinton arginit(); 1309677Slinton } 1319677Slinton 1329677Slinton /* 1339677Slinton * Routines to get at process information from outside this module. 1349677Slinton */ 1359677Slinton 1369677Slinton public Word reg(n) 1379677Slinton Integer n; 1389677Slinton { 1399677Slinton register Word w; 1409677Slinton 1419677Slinton if (n == NREG) { 1429677Slinton w = process->mask; 1439677Slinton } else { 1449677Slinton w = process->reg[n]; 1459677Slinton } 1469677Slinton return w; 1479677Slinton } 1489677Slinton 1499677Slinton public setreg(n, w) 1509677Slinton Integer n; 1519677Slinton Word w; 1529677Slinton { 1539677Slinton process->reg[n] = w; 1549677Slinton } 1559677Slinton 1569677Slinton /* 1579677Slinton * Begin execution. 1589677Slinton * 1599677Slinton * We set a breakpoint at the end of the code so that the 1609677Slinton * process data doesn't disappear after the program terminates. 1619677Slinton */ 1629677Slinton 1639677Slinton private Boolean remade(); 1649677Slinton 1659677Slinton public start(argv, infile, outfile) 1669677Slinton String argv[]; 1679677Slinton String infile, outfile; 1689677Slinton { 1699677Slinton String pargv[4]; 1709677Slinton Node cond; 1719677Slinton 1729677Slinton if (coredump) { 1739677Slinton coredump = false; 1749677Slinton fclose(corefile); 1759677Slinton coredump_close(); 1769677Slinton } 1779677Slinton if (argv == nil) { 1789677Slinton argv = pargv; 1799677Slinton pargv[0] = objname; 1809677Slinton pargv[1] = nil; 1819677Slinton } else { 1829677Slinton argv[argc] = nil; 1839677Slinton } 18418230Slinton pstart(process, argv, infile, outfile); 1859677Slinton if (remade(objname)) { 1869677Slinton reinit(argv, infile, outfile); 1879677Slinton } 1889677Slinton if (process->status == STOPPED) { 1899677Slinton pc = 0; 19016617Ssam setcurfunc(program); 1919677Slinton if (objsize != 0) { 1929677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1939677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1949677Slinton } 1959677Slinton } 1969677Slinton } 1979677Slinton 1989677Slinton /* 1999677Slinton * Check to see if the object file has changed since the symbolic 2009677Slinton * information last was read. 2019677Slinton */ 2029677Slinton 2039677Slinton private time_t modtime; 2049677Slinton 2059677Slinton private Boolean remade(filename) 2069677Slinton String filename; 2079677Slinton { 2089677Slinton struct stat s; 2099677Slinton Boolean b; 2109677Slinton 2119677Slinton stat(filename, &s); 2129677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2139677Slinton modtime = s.st_mtime; 2149677Slinton return b; 2159677Slinton } 2169677Slinton 2179677Slinton /* 2189677Slinton * Set up what signals we want to trace. 2199677Slinton */ 2209677Slinton 2219677Slinton private setsigtrace() 2229677Slinton { 2239677Slinton register Integer i; 2249677Slinton register Process p; 2259677Slinton 2269677Slinton p = process; 2279677Slinton for (i = 1; i <= NSIG; i++) { 2289677Slinton psigtrace(p, i, true); 2299677Slinton } 2309677Slinton psigtrace(p, SIGHUP, false); 2319677Slinton psigtrace(p, SIGKILL, false); 2329677Slinton psigtrace(p, SIGALRM, false); 2339677Slinton psigtrace(p, SIGTSTP, false); 2349677Slinton psigtrace(p, SIGCONT, false); 2359677Slinton psigtrace(p, SIGCHLD, false); 236*26333Ssam psigtrace(p, SIGWINCH, false); 2379677Slinton } 2389677Slinton 2399677Slinton /* 2409677Slinton * Initialize the argument list. 2419677Slinton */ 2429677Slinton 2439677Slinton public arginit() 2449677Slinton { 2459677Slinton infile = nil; 2469677Slinton outfile = nil; 2479677Slinton argv[0] = objname; 2489677Slinton argc = 1; 2499677Slinton } 2509677Slinton 2519677Slinton /* 2529677Slinton * Add an argument to the list for the debuggee. 2539677Slinton */ 2549677Slinton 2559677Slinton public newarg(arg) 2569677Slinton String arg; 2579677Slinton { 2589677Slinton if (argc >= MAXNCMDARGS) { 2599677Slinton error("too many arguments"); 2609677Slinton } 2619677Slinton argv[argc++] = arg; 2629677Slinton } 2639677Slinton 2649677Slinton /* 2659677Slinton * Set the standard input for the debuggee. 2669677Slinton */ 2679677Slinton 2689677Slinton public inarg(filename) 2699677Slinton String filename; 2709677Slinton { 2719677Slinton if (infile != nil) { 2729677Slinton error("multiple input redirects"); 2739677Slinton } 2749677Slinton infile = filename; 2759677Slinton } 2769677Slinton 2779677Slinton /* 2789677Slinton * Set the standard output for the debuggee. 2799677Slinton * Probably should check to avoid overwriting an existing file. 2809677Slinton */ 2819677Slinton 2829677Slinton public outarg(filename) 2839677Slinton String filename; 2849677Slinton { 2859677Slinton if (outfile != nil) { 2869677Slinton error("multiple output redirect"); 2879677Slinton } 2889677Slinton outfile = filename; 2899677Slinton } 2909677Slinton 2919677Slinton /* 2929677Slinton * Start debuggee executing. 2939677Slinton */ 2949677Slinton 2959677Slinton public run() 2969677Slinton { 2979677Slinton process->status = STOPPED; 2989677Slinton fixbps(); 2999677Slinton curline = 0; 3009677Slinton start(argv, infile, outfile); 3019677Slinton just_started = true; 3029677Slinton isstopped = false; 30314757Slinton cont(0); 3049677Slinton } 3059677Slinton 3069677Slinton /* 3079677Slinton * Continue execution wherever we left off. 3089677Slinton * 3099677Slinton * Note that this routine never returns. Eventually bpact() will fail 3109677Slinton * and we'll call printstatus or step will call it. 3119677Slinton */ 3129677Slinton 3139677Slinton typedef int Intfunc(); 3149677Slinton 3159677Slinton private Intfunc *dbintr; 3169677Slinton private intr(); 3179677Slinton 31811867Slinton public cont(signo) 31916617Ssam integer signo; 3209677Slinton { 32116617Ssam integer s; 32216617Ssam 3239677Slinton dbintr = signal(SIGINT, intr); 3249677Slinton if (just_started) { 3259677Slinton just_started = false; 3269677Slinton } else { 3279677Slinton if (not isstopped) { 3289677Slinton error("can't continue execution"); 3299677Slinton } 3309677Slinton isstopped = false; 33111867Slinton stepover(); 3329677Slinton } 33316617Ssam s = signo; 3349677Slinton for (;;) { 3359677Slinton if (single_stepping) { 3369677Slinton printnews(); 3379677Slinton } else { 3389677Slinton setallbps(); 33916617Ssam resume(s); 3409677Slinton unsetallbps(); 34116617Ssam s = DEFSIG; 34218230Slinton if (not isbperr() or not bpact()) { 3439677Slinton printstatus(); 3449677Slinton } 3459677Slinton } 34611867Slinton stepover(); 3479677Slinton } 3489677Slinton /* NOTREACHED */ 3499677Slinton } 3509677Slinton 3519677Slinton /* 35218230Slinton * This routine is called if we get an interrupt while "running" 3539677Slinton * but actually in the debugger. Could happen, for example, while 3549677Slinton * processing breakpoints. 3559677Slinton * 3569677Slinton * We basically just want to keep going; the assumption is 35718230Slinton * that when the process resumes it will get the interrupt, 3589677Slinton * which will then be handled. 3599677Slinton */ 3609677Slinton 3619677Slinton private intr() 3629677Slinton { 3639677Slinton signal(SIGINT, intr); 3649677Slinton } 3659677Slinton 3669677Slinton public fixintr() 3679677Slinton { 3689677Slinton signal(SIGINT, dbintr); 3699677Slinton } 3709677Slinton 3719677Slinton /* 3729677Slinton * Resume execution. 3739677Slinton */ 3749677Slinton 37511867Slinton public resume(signo) 37611867Slinton int signo; 3779677Slinton { 3789677Slinton register Process p; 3799677Slinton 3809677Slinton p = process; 38111867Slinton pcont(p, signo); 3829677Slinton pc = process->reg[PROGCTR]; 38311832Slinton if (p->status != STOPPED) { 38411867Slinton if (p->signo != 0) { 38511867Slinton error("program terminated by signal %d", p->signo); 38614757Slinton } else if (not runfirst) { 38718230Slinton if (p->exitval == 0) { 38818230Slinton error("program exited"); 38918230Slinton } else { 39018230Slinton error("program exited with code %d", p->exitval); 39118230Slinton } 39211867Slinton } 39311832Slinton } 3949677Slinton } 3959677Slinton 3969677Slinton /* 3979677Slinton * Continue execution up to the next source line. 3989677Slinton * 3999677Slinton * There are two ways to define the next source line depending on what 4009677Slinton * is desired when a procedure or function call is encountered. Step 4019677Slinton * stops at the beginning of the procedure or call; next skips over it. 4029677Slinton */ 4039677Slinton 4049677Slinton /* 4059677Slinton * Stepc is what is called when the step command is given. 4069677Slinton * It has to play with the "isstopped" information. 4079677Slinton */ 4089677Slinton 4099677Slinton public stepc() 4109677Slinton { 4119677Slinton if (not isstopped) { 4129677Slinton error("can't continue execution"); 4139677Slinton } 4149677Slinton isstopped = false; 4159677Slinton dostep(false); 4169677Slinton isstopped = true; 4179677Slinton } 4189677Slinton 4199677Slinton public next() 4209677Slinton { 42116617Ssam Address oldfrp, newfrp; 42216617Ssam 4239677Slinton if (not isstopped) { 4249677Slinton error("can't continue execution"); 4259677Slinton } 4269677Slinton isstopped = false; 42716617Ssam oldfrp = reg(FRP); 42816617Ssam do { 42916617Ssam dostep(true); 43016617Ssam pc = reg(PROGCTR); 43116617Ssam newfrp = reg(FRP); 43216617Ssam } while (newfrp < oldfrp and newfrp != 0); 4339677Slinton isstopped = true; 4349677Slinton } 4359677Slinton 43611867Slinton /* 43716617Ssam * Continue execution until the current function returns, or, 43816617Ssam * if the given argument is non-nil, until execution returns to 43916617Ssam * somewhere within the given function. 44016617Ssam */ 44116617Ssam 44216617Ssam public rtnfunc (f) 44316617Ssam Symbol f; 44416617Ssam { 44516617Ssam Address addr; 44616617Ssam Symbol t; 44716617Ssam 44816617Ssam if (not isstopped) { 44916617Ssam error("can't continue execution"); 45016617Ssam } else if (f != nil and not isactive(f)) { 45116617Ssam error("%s is not active", symname(f)); 45216617Ssam } else { 45316617Ssam addr = return_addr(); 45416617Ssam if (addr == nil) { 45516617Ssam error("no place to return to"); 45616617Ssam } else { 45716617Ssam isstopped = false; 45816617Ssam contto(addr); 45916617Ssam if (f != nil) { 46016617Ssam for (;;) { 46116617Ssam t = whatblock(pc); 46216617Ssam addr = return_addr(); 46316617Ssam if (t == f or addr == nil) break; 46416617Ssam contto(addr); 46516617Ssam } 46616617Ssam } 46718230Slinton if (not bpact()) { 46816617Ssam isstopped = true; 46916617Ssam printstatus(); 47016617Ssam } 47116617Ssam } 47216617Ssam } 47316617Ssam } 47416617Ssam 47516617Ssam /* 47611867Slinton * Single-step over the current machine instruction. 47711867Slinton * 47811867Slinton * If we're single-stepping by source line we want to step to the 47911867Slinton * next source line. Otherwise we're going to continue so there's 48011867Slinton * no reason to do all the work necessary to single-step to the next 48111867Slinton * source line. 48211867Slinton */ 48311867Slinton 48416617Ssam public stepover() 4859677Slinton { 48611867Slinton Boolean b; 48711867Slinton 48816617Ssam if (traceexec) { 48916617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]); 49016617Ssam } 49111867Slinton if (single_stepping) { 49211867Slinton dostep(false); 49311867Slinton } else { 49411867Slinton b = inst_tracing; 49511867Slinton inst_tracing = true; 49611867Slinton dostep(false); 49711867Slinton inst_tracing = b; 49811867Slinton } 49916617Ssam if (traceexec) { 50016617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]); 50116617Ssam } 5029677Slinton } 5039677Slinton 5049677Slinton /* 50518230Slinton * Resume execution up to the given address. We can either ignore 50618230Slinton * breakpoints (stepto) or catch them (contto). 5079677Slinton */ 5089677Slinton 5099677Slinton public stepto(addr) 5109677Slinton Address addr; 5119677Slinton { 51216617Ssam xto(addr, false); 51316617Ssam } 51416617Ssam 51516617Ssam private contto (addr) 51616617Ssam Address addr; 51716617Ssam { 51816617Ssam xto(addr, true); 51916617Ssam } 52016617Ssam 52116617Ssam private xto (addr, catchbps) 52216617Ssam Address addr; 52316617Ssam boolean catchbps; 52416617Ssam { 52516617Ssam Address curpc; 52616617Ssam 52716617Ssam if (catchbps) { 52816617Ssam stepover(); 5299677Slinton } 53016617Ssam curpc = process->reg[PROGCTR]; 53116617Ssam if (addr != curpc) { 53216617Ssam if (traceexec) { 53316617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr); 53416617Ssam } 53516617Ssam if (catchbps) { 53616617Ssam setallbps(); 53716617Ssam } 53816617Ssam setbp(addr); 53916617Ssam resume(DEFSIG); 54016617Ssam unsetbp(addr); 54116617Ssam if (catchbps) { 54216617Ssam unsetallbps(); 54316617Ssam } 54416617Ssam if (not isbperr()) { 54516617Ssam printstatus(); 54616617Ssam } 54716617Ssam } 5489677Slinton } 5499677Slinton 5509677Slinton /* 5519677Slinton * Print the status of the process. 5529677Slinton * This routine does not return. 5539677Slinton */ 5549677Slinton 5559677Slinton public printstatus() 5569677Slinton { 55714395Slinton int status; 55814395Slinton 5599843Slinton if (process->status == FINISHED) { 5609843Slinton exit(0); 5619843Slinton } else { 56216617Ssam setcurfunc(whatblock(pc)); 5639677Slinton getsrcpos(); 5649843Slinton if (process->signo == SIGINT) { 5659843Slinton isstopped = true; 5669843Slinton printerror(); 5679843Slinton } else if (isbperr() and isstopped) { 5689843Slinton printf("stopped "); 56911172Slinton printloc(); 57011172Slinton putchar('\n'); 5719843Slinton if (curline > 0) { 5729843Slinton printlines(curline, curline); 5739843Slinton } else { 5749843Slinton printinst(pc, pc); 5759843Slinton } 5769843Slinton erecover(); 5779677Slinton } else { 5789843Slinton fixintr(); 5799677Slinton isstopped = true; 5809677Slinton printerror(); 5819677Slinton } 5829677Slinton } 5839677Slinton } 5849677Slinton 5859677Slinton /* 58611172Slinton * Print out the current location in the debuggee. 58711172Slinton */ 58811172Slinton 58911172Slinton public printloc() 59011172Slinton { 59111172Slinton printf("in "); 59211172Slinton printname(stdout, curfunc); 59311172Slinton putchar(' '); 59414757Slinton if (curline > 0 and not useInstLoc) { 59511172Slinton printsrcpos(); 59611172Slinton } else { 59714757Slinton useInstLoc = false; 59814757Slinton curline = 0; 59911172Slinton printf("at 0x%x", pc); 60011172Slinton } 60111172Slinton } 60211172Slinton 60311172Slinton /* 6049677Slinton * Some functions for testing the state of the process. 6059677Slinton */ 6069677Slinton 6079677Slinton public Boolean notstarted(p) 6089677Slinton Process p; 6099677Slinton { 6109677Slinton return (Boolean) (p->status == NOTSTARTED); 6119677Slinton } 6129677Slinton 6139677Slinton public Boolean isfinished(p) 6149677Slinton Process p; 6159677Slinton { 6169677Slinton return (Boolean) (p->status == FINISHED); 6179677Slinton } 6189677Slinton 6199677Slinton /* 62018230Slinton * Predicate to test if the reason the process stopped was because 62118230Slinton * of a breakpoint. If so, as a side effect clear the local copy of 62218230Slinton * signal handler associated with process. We must do this so as to 62318230Slinton * not confuse future stepping or continuing by possibly concluding 62418230Slinton * the process should continue with a SIGTRAP handler. 6259677Slinton */ 6269677Slinton 62718230Slinton public boolean isbperr() 62818230Slinton { 62918230Slinton Process p; 63018230Slinton boolean b; 63118230Slinton 63218230Slinton p = process; 63318230Slinton if (p->status == STOPPED and p->signo == SIGTRAP) { 63418230Slinton b = true; 63518230Slinton p->sigstatus = 0; 63618230Slinton } else { 63718230Slinton b = false; 63818230Slinton } 63918230Slinton return b; 64018230Slinton } 64118230Slinton 64218230Slinton /* 64318230Slinton * Return the signal number that stopped the process. 64418230Slinton */ 64518230Slinton 64618230Slinton public integer errnum (p) 6479677Slinton Process p; 6489677Slinton { 6499677Slinton return p->signo; 6509677Slinton } 6519677Slinton 65218230Slinton /* 65318230Slinton * Return the signal code associated with the signal. 65418230Slinton */ 65518230Slinton 65618230Slinton public integer errcode (p) 65716931Ssam Process p; 65816931Ssam { 65916931Ssam return p->sigcode; 66016931Ssam } 66116931Ssam 6629677Slinton /* 6639677Slinton * Return the termination code of the process. 6649677Slinton */ 6659677Slinton 66618230Slinton public integer exitcode (p) 6679677Slinton Process p; 6689677Slinton { 6699677Slinton return p->exitval; 6709677Slinton } 6719677Slinton 6729677Slinton /* 6739677Slinton * These routines are used to access the debuggee process from 6749677Slinton * outside this module. 6759677Slinton * 6769677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 67714757Slinton * The system generates an I/O error when a ptrace fails. During reads 67814757Slinton * these are ignored, during writes they are reported as an error, and 67914757Slinton * for anything else they cause a fatal error. 6809677Slinton */ 6819677Slinton 6829677Slinton extern Intfunc *onsyserr(); 6839677Slinton 6849677Slinton private badaddr; 68514757Slinton private read_err(), write_err(); 6869677Slinton 6879677Slinton /* 6889677Slinton * Read from the process' instruction area. 6899677Slinton */ 6909677Slinton 6919677Slinton public iread(buff, addr, nbytes) 6929677Slinton char *buff; 6939677Slinton Address addr; 6949677Slinton int nbytes; 6959677Slinton { 6969677Slinton Intfunc *f; 6979677Slinton 69814757Slinton f = onsyserr(EIO, read_err); 6999677Slinton badaddr = addr; 7009677Slinton if (coredump) { 7019677Slinton coredump_readtext(buff, addr, nbytes); 7029677Slinton } else { 7039677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 7049677Slinton } 7059677Slinton onsyserr(EIO, f); 7069677Slinton } 7079677Slinton 7089677Slinton /* 7099677Slinton * Write to the process' instruction area, usually in order to set 7109677Slinton * or unset a breakpoint. 7119677Slinton */ 7129677Slinton 7139677Slinton public iwrite(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, TEXTSEG, buff, addr, nbytes); 7269677Slinton onsyserr(EIO, f); 7279677Slinton } 7289677Slinton 7299677Slinton /* 7309677Slinton * Read for the process' data area. 7319677Slinton */ 7329677Slinton 7339677Slinton public dread(buff, addr, nbytes) 7349677Slinton char *buff; 7359677Slinton Address addr; 7369677Slinton int nbytes; 7379677Slinton { 7389677Slinton Intfunc *f; 7399677Slinton 7409677Slinton badaddr = addr; 7419677Slinton if (coredump) { 74218230Slinton f = onsyserr(EFAULT, read_err); 7439677Slinton coredump_readdata(buff, addr, nbytes); 74418230Slinton onsyserr(EFAULT, f); 7459677Slinton } else { 74618230Slinton f = onsyserr(EIO, read_err); 7479677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 74818230Slinton onsyserr(EIO, f); 7499677Slinton } 7509677Slinton } 7519677Slinton 7529677Slinton /* 7539677Slinton * Write to the process' data area. 7549677Slinton */ 7559677Slinton 7569677Slinton public dwrite(buff, addr, nbytes) 7579677Slinton char *buff; 7589677Slinton Address addr; 7599677Slinton int nbytes; 7609677Slinton { 7619677Slinton Intfunc *f; 7629677Slinton 7639677Slinton if (coredump) { 7649677Slinton error("no process to write to"); 7659677Slinton } 76614757Slinton f = onsyserr(EIO, write_err); 7679677Slinton badaddr = addr; 7689677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 7699677Slinton onsyserr(EIO, f); 7709677Slinton } 7719677Slinton 7729677Slinton /* 77314757Slinton * Trap for errors in reading or writing to a process. 77414757Slinton * The current approach is to "ignore" read errors and complain 77514757Slinton * bitterly about write errors. 7769677Slinton */ 7779677Slinton 77814757Slinton private read_err() 7799677Slinton { 78011560Slinton /* 78114757Slinton * Ignore. 78211560Slinton */ 7839677Slinton } 7849677Slinton 78514757Slinton private write_err() 78614757Slinton { 78714757Slinton error("can't write to process (address 0x%x)", badaddr); 78814757Slinton } 78914757Slinton 7909677Slinton /* 7919677Slinton * Ptrace interface. 7929677Slinton */ 7939677Slinton 7949677Slinton /* 7959677Slinton * This magic macro enables us to look at the process' registers 79614757Slinton * in its user structure. 7979677Slinton */ 7989677Slinton 7999677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 8009677Slinton 8019677Slinton #define WMASK (~(sizeof(Word) - 1)) 8029677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 8039677Slinton 8049677Slinton #define FIRSTSIG SIGINT 8059677Slinton #define LASTSIG SIGQUIT 8069677Slinton #define ischild(pid) ((pid) == 0) 80718230Slinton #define traceme() ptrace(0, 0, 0, 0) 8089677Slinton #define setrep(n) (1 << ((n)-1)) 8099677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 8109677Slinton 8119677Slinton /* 81218230Slinton * Ptrace options (specified in first argument). 81318230Slinton */ 81418230Slinton 81518230Slinton #define UREAD 3 /* read from process's user structure */ 81618230Slinton #define UWRITE 6 /* write to process's user structure */ 81718230Slinton #define IREAD 1 /* read from process's instruction space */ 81818230Slinton #define IWRITE 4 /* write to process's instruction space */ 81918230Slinton #define DREAD 2 /* read from process's data space */ 82018230Slinton #define DWRITE 5 /* write to process's data space */ 82118230Slinton #define CONT 7 /* continue stopped process */ 82218230Slinton #define SSTEP 9 /* continue for approximately one instruction */ 82318230Slinton #define PKILL 8 /* terminate the process */ 82418230Slinton 82518230Slinton /* 8269677Slinton * Start up a new process by forking and exec-ing the 8279677Slinton * given argument list, returning when the process is loaded 8289677Slinton * and ready to execute. The PROCESS information (pointed to 8299677Slinton * by the first argument) is appropriately filled. 8309677Slinton * 8319677Slinton * If the given PROCESS structure is associated with an already running 8329677Slinton * process, we terminate it. 8339677Slinton */ 8349677Slinton 8359677Slinton /* VARARGS2 */ 8369677Slinton private pstart(p, argv, infile, outfile) 8379677Slinton Process p; 8389677Slinton String argv[]; 8399677Slinton String infile; 8409677Slinton String outfile; 8419677Slinton { 8429677Slinton int status; 8439677Slinton 84416617Ssam if (p->pid != 0) { 84516617Ssam pterm(p); 84618230Slinton cacheflush(p); 8479677Slinton } 84818230Slinton fflush(stdout); 8499677Slinton psigtrace(p, SIGTRAP, true); 85014395Slinton p->pid = vfork(); 85114395Slinton if (p->pid == -1) { 8529677Slinton panic("can't fork"); 8539677Slinton } 8549677Slinton if (ischild(p->pid)) { 85518230Slinton nocatcherrs(); 8569677Slinton traceme(); 8579677Slinton if (infile != nil) { 85816617Ssam infrom(infile); 8599677Slinton } 8609677Slinton if (outfile != nil) { 86116617Ssam outto(outfile); 8629677Slinton } 86311832Slinton execv(argv[0], argv); 86411172Slinton _exit(1); 8659677Slinton } 8669677Slinton pwait(p->pid, &status); 8679677Slinton getinfo(p, status); 8689677Slinton if (p->status != STOPPED) { 86918230Slinton beginerrmsg(); 87018230Slinton fprintf(stderr, "warning: cannot execute %s\n", argv[0]); 87118230Slinton } else { 87218230Slinton ptraced(p->pid); 8739677Slinton } 8749677Slinton } 8759677Slinton 8769677Slinton /* 87716617Ssam * Terminate a ptrace'd process. 87816617Ssam */ 87916617Ssam 88016617Ssam public pterm (p) 88116617Ssam Process p; 88216617Ssam { 88316617Ssam integer status; 88416617Ssam 88516617Ssam if (p != nil and p->pid != 0) { 88618230Slinton ptrace(PKILL, p->pid, 0, 0); 88716617Ssam pwait(p->pid, &status); 88816617Ssam unptraced(p->pid); 88916617Ssam } 89016617Ssam } 89116617Ssam 89216617Ssam /* 89311867Slinton * Continue a stopped process. The first argument points to a Process 89411867Slinton * structure. Before the process is restarted it's user area is modified 89511867Slinton * according to the values in the structure. When this routine finishes, 8969677Slinton * the structure has the new values from the process's user area. 8979677Slinton * 8989677Slinton * Pcont terminates when the process stops with a signal pending that 8999677Slinton * is being traced (via psigtrace), or when the process terminates. 9009677Slinton */ 9019677Slinton 90211867Slinton private pcont(p, signo) 9039677Slinton Process p; 90411867Slinton int signo; 9059677Slinton { 90616617Ssam int s, status; 9079677Slinton 9089677Slinton if (p->pid == 0) { 90918230Slinton error("program is not active"); 9109677Slinton } 91116617Ssam s = signo; 9129677Slinton do { 91316617Ssam setinfo(p, s); 91416617Ssam if (traceexec) { 91516617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n", 91616617Ssam p->reg[PROGCTR], s, p->signo); 91716617Ssam fflush(stdout); 91816617Ssam } 9199677Slinton sigs_off(); 92018230Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 92114395Slinton panic("error %d trying to continue process", errno); 9229677Slinton } 9239677Slinton pwait(p->pid, &status); 9249677Slinton sigs_on(); 9259677Slinton getinfo(p, status); 92618230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 92718230Slinton printf("!! ignored signal %d at 0x%x\n", 92818230Slinton p->signo, p->reg[PROGCTR]); 92916617Ssam fflush(stdout); 93016617Ssam } 93116617Ssam s = p->signo; 9329677Slinton } while (p->status == STOPPED and not istraced(p)); 93316617Ssam if (traceexec) { 93416617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo); 93516617Ssam fflush(stdout); 93616617Ssam } 9379677Slinton } 9389677Slinton 9399677Slinton /* 9409677Slinton * Single step as best ptrace can. 9419677Slinton */ 9429677Slinton 94316617Ssam public pstep(p, signo) 9449677Slinton Process p; 94516617Ssam integer signo; 9469677Slinton { 94718230Slinton int s, status; 9489677Slinton 94918230Slinton s = signo; 95018230Slinton do { 95118230Slinton setinfo(p, s); 95218230Slinton if (traceexec) { 95318230Slinton printf("!! pstep from 0x%x with signal %d (%d)\n", 95418230Slinton p->reg[PROGCTR], s, p->signo); 95518230Slinton fflush(stdout); 95618230Slinton } 95718230Slinton sigs_off(); 95818230Slinton if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) { 95918230Slinton panic("error %d trying to step process", errno); 96018230Slinton } 96118230Slinton pwait(p->pid, &status); 96218230Slinton sigs_on(); 96318230Slinton getinfo(p, status); 96418230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) { 96518230Slinton printf("!! pstep ignored signal %d at 0x%x\n", 96618230Slinton p->signo, p->reg[PROGCTR]); 96718230Slinton fflush(stdout); 96818230Slinton } 96918230Slinton s = p->signo; 97018230Slinton } while (p->status == STOPPED and not istraced(p)); 97116617Ssam if (traceexec) { 97218230Slinton printf("!! pstep to 0x%x on signal %d\n", 97318230Slinton p->reg[PROGCTR], p->signo); 97416617Ssam fflush(stdout); 97516617Ssam } 97616617Ssam if (p->status != STOPPED) { 97718230Slinton if (p->exitval == 0) { 97818230Slinton error("program exited\n"); 97918230Slinton } else { 98018230Slinton error("program exited with code %d\n", p->exitval); 98118230Slinton } 98216617Ssam } 9839677Slinton } 9849677Slinton 9859677Slinton /* 9869677Slinton * Return from execution when the given signal is pending. 9879677Slinton */ 9889677Slinton 9899677Slinton public psigtrace(p, sig, sw) 9909677Slinton Process p; 9919677Slinton int sig; 9929677Slinton Boolean sw; 9939677Slinton { 9949677Slinton if (sw) { 9959677Slinton p->sigset |= setrep(sig); 9969677Slinton } else { 9979677Slinton p->sigset &= ~setrep(sig); 9989677Slinton } 9999677Slinton } 10009677Slinton 10019677Slinton /* 10029677Slinton * Don't catch any signals. 10039677Slinton * Particularly useful when letting a process finish uninhibited. 10049677Slinton */ 10059677Slinton 10069677Slinton public unsetsigtraces(p) 10079677Slinton Process p; 10089677Slinton { 10099677Slinton p->sigset = 0; 10109677Slinton } 10119677Slinton 10129677Slinton /* 10139677Slinton * Turn off attention to signals not being caught. 10149677Slinton */ 10159677Slinton 10169677Slinton private Intfunc *sigfunc[NSIG]; 10179677Slinton 10189677Slinton private sigs_off() 10199677Slinton { 10209677Slinton register int i; 10219677Slinton 10229677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10239677Slinton if (i != SIGKILL) { 10249677Slinton sigfunc[i] = signal(i, SIG_IGN); 10259677Slinton } 10269677Slinton } 10279677Slinton } 10289677Slinton 10299677Slinton /* 10309677Slinton * Turn back on attention to signals. 10319677Slinton */ 10329677Slinton 10339677Slinton private sigs_on() 10349677Slinton { 10359677Slinton register int i; 10369677Slinton 10379677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 10389677Slinton if (i != SIGKILL) { 10399677Slinton signal(i, sigfunc[i]); 10409677Slinton } 10419677Slinton } 10429677Slinton } 10439677Slinton 10449677Slinton /* 10459677Slinton * Get process information from user area. 10469677Slinton */ 10479677Slinton 10489677Slinton private getinfo(p, status) 10499677Slinton register Process p; 10509677Slinton register int status; 10519677Slinton { 10529677Slinton register int i; 105316617Ssam Address addr; 10549677Slinton 10559677Slinton p->signo = (status&0177); 10569677Slinton p->exitval = ((status >> 8)&0377); 10579677Slinton if (p->signo != STOPPED) { 10589677Slinton p->status = FINISHED; 105914757Slinton p->pid = 0; 106016617Ssam p->reg[PROGCTR] = 0; 10619677Slinton } else { 10629677Slinton p->status = p->signo; 10639677Slinton p->signo = p->exitval; 106418230Slinton p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0); 10659677Slinton p->exitval = 0; 106618230Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 10679677Slinton for (i = 0; i < NREG; i++) { 106818230Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 10699677Slinton p->oreg[i] = p->reg[i]; 10709677Slinton } 107111768Slinton savetty(stdout, &(p->ttyinfo)); 107216617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]); 107318230Slinton p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0); 10749677Slinton } 10759677Slinton } 10769677Slinton 10779677Slinton /* 10789677Slinton * Set process's user area information from given process structure. 10799677Slinton */ 10809677Slinton 108111867Slinton private setinfo(p, signo) 10829677Slinton register Process p; 108311867Slinton int signo; 10849677Slinton { 10859677Slinton register int i; 10869677Slinton register int r; 10879677Slinton 108814757Slinton if (signo == DEFSIG) { 108916617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) { 109014757Slinton p->signo = 0; 109114757Slinton } 109214757Slinton } else { 109311867Slinton p->signo = signo; 10949677Slinton } 10959677Slinton for (i = 0; i < NREG; i++) { 10969677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 109718230Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 10989677Slinton } 10999677Slinton } 110011768Slinton restoretty(stdout, &(p->ttyinfo)); 11019677Slinton } 11029677Slinton 11039677Slinton /* 110416617Ssam * Return the address associated with the current signal. 110516617Ssam * (Plus two since the address points to the beginning of a procedure). 110616617Ssam */ 110716617Ssam 110816617Ssam public Address usignal (p) 110916617Ssam Process p; 111016617Ssam { 111116617Ssam Address r; 111216617Ssam 111316617Ssam r = p->sigstatus; 111416617Ssam if (r != 0 and r != 1) { 111516617Ssam r += 2; 111616617Ssam } 111716617Ssam return r; 111816617Ssam } 111916617Ssam 112016617Ssam /* 11219677Slinton * Structure for reading and writing by words, but dealing with bytes. 11229677Slinton */ 11239677Slinton 11249677Slinton typedef union { 11259677Slinton Word pword; 11269677Slinton Byte pbyte[sizeof(Word)]; 11279677Slinton } Pword; 11289677Slinton 11299677Slinton /* 11309677Slinton * Read (write) from (to) the process' address space. 11319677Slinton * We must deal with ptrace's inability to look anywhere other 11329677Slinton * than at a word boundary. 11339677Slinton */ 11349677Slinton 11359677Slinton private Word fetch(); 11369677Slinton private store(); 11379677Slinton 11389677Slinton private pio(p, op, seg, buff, addr, nbytes) 11399677Slinton Process p; 11409677Slinton PioOp op; 11419677Slinton PioSeg seg; 11429677Slinton char *buff; 11439677Slinton Address addr; 11449677Slinton int nbytes; 11459677Slinton { 11469677Slinton register int i; 11479677Slinton register Address newaddr; 11489677Slinton register char *cp; 11499677Slinton char *bufend; 11509677Slinton Pword w; 11519677Slinton Address wordaddr; 11529677Slinton int byteoff; 11539677Slinton 11549677Slinton if (p->status != STOPPED) { 11559677Slinton error("program is not active"); 11569677Slinton } 11579677Slinton cp = buff; 11589677Slinton newaddr = addr; 11599677Slinton wordaddr = (newaddr&WMASK); 11609677Slinton if (wordaddr != newaddr) { 11619677Slinton w.pword = fetch(p, seg, wordaddr); 11629677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 11639677Slinton if (op == PREAD) { 11649677Slinton *cp++ = w.pbyte[i]; 11659677Slinton } else { 11669677Slinton w.pbyte[i] = *cp++; 11679677Slinton } 11689677Slinton nbytes--; 11699677Slinton } 11709677Slinton if (op == PWRITE) { 11719677Slinton store(p, seg, wordaddr, w.pword); 11729677Slinton } 11739677Slinton newaddr = wordaddr + sizeof(Word); 11749677Slinton } 11759677Slinton byteoff = (nbytes&(~WMASK)); 11769677Slinton nbytes -= byteoff; 11779677Slinton bufend = cp + nbytes; 1178*26333Ssam #ifdef tahoe 1179*26333Ssam if (((int)cp)&WMASK) { 1180*26333Ssam /* 1181*26333Ssam * Must copy a byte at a time, buffer not word addressable. 1182*26333Ssam */ 1183*26333Ssam while (cp < bufend) { 1184*26333Ssam if (op == PREAD) { 1185*26333Ssam w.pword = fetch(p, seg, newaddr); 1186*26333Ssam for (i = 0; i < sizeof(Word); i++) 1187*26333Ssam *cp++ = w.pbyte[i]; 1188*26333Ssam } else { 1189*26333Ssam for (i = 0; i < sizeof(Word); i++) 1190*26333Ssam w.pbyte[i] = *cp++; 1191*26333Ssam store(p, seg, newaddr, w.pword); 1192*26333Ssam } 1193*26333Ssam newaddr += sizeof(Word); 1194*26333Ssam } 1195*26333Ssam } else { 1196*26333Ssam /* 1197*26333Ssam * Buffer, word aligned, act normally... 1198*26333Ssam */ 1199*26333Ssam #endif 12009677Slinton while (cp < bufend) { 12019677Slinton if (op == PREAD) { 12029677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 12039677Slinton } else { 12049677Slinton store(p, seg, newaddr, *((Word *) cp)); 12059677Slinton } 12069677Slinton cp += sizeof(Word); 12079677Slinton newaddr += sizeof(Word); 12089677Slinton } 1209*26333Ssam #ifdef tahoe 1210*26333Ssam } 1211*26333Ssam #endif 12129677Slinton if (byteoff > 0) { 12139677Slinton w.pword = fetch(p, seg, newaddr); 12149677Slinton for (i = 0; i < byteoff; i++) { 12159677Slinton if (op == PREAD) { 12169677Slinton *cp++ = w.pbyte[i]; 12179677Slinton } else { 12189677Slinton w.pbyte[i] = *cp++; 12199677Slinton } 12209677Slinton } 12219677Slinton if (op == PWRITE) { 12229677Slinton store(p, seg, newaddr, w.pword); 12239677Slinton } 12249677Slinton } 12259677Slinton } 12269677Slinton 12279677Slinton /* 12289677Slinton * Get a word from a process at the given address. 12299677Slinton * The address is assumed to be on a word boundary. 12309677Slinton * 12319677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 12329677Slinton * to the instruction space since it is assumed to be pure. 12339677Slinton * 12349677Slinton * It is necessary to use a write-through scheme so that 12359677Slinton * breakpoints right next to each other don't interfere. 12369677Slinton */ 12379677Slinton 12389677Slinton private Integer nfetchs, nreads, nwrites; 12399677Slinton 12409677Slinton private Word fetch(p, seg, addr) 12419677Slinton Process p; 12429677Slinton PioSeg seg; 12439677Slinton register int addr; 12449677Slinton { 12459677Slinton register CacheWord *wp; 12469677Slinton register Word w; 12479677Slinton 12489677Slinton switch (seg) { 12499677Slinton case TEXTSEG: 12509677Slinton ++nfetchs; 12519677Slinton wp = &p->word[cachehash(addr)]; 12529677Slinton if (addr == 0 or wp->addr != addr) { 12539677Slinton ++nreads; 125418230Slinton w = ptrace(IREAD, p->pid, addr, 0); 12559677Slinton wp->addr = addr; 12569677Slinton wp->val = w; 12579677Slinton } else { 12589677Slinton w = wp->val; 12599677Slinton } 12609677Slinton break; 12619677Slinton 12629677Slinton case DATASEG: 126318230Slinton w = ptrace(DREAD, p->pid, addr, 0); 12649677Slinton break; 12659677Slinton 12669677Slinton default: 12679677Slinton panic("fetch: bad seg %d", seg); 12689677Slinton /* NOTREACHED */ 12699677Slinton } 12709677Slinton return w; 12719677Slinton } 12729677Slinton 12739677Slinton /* 12749677Slinton * Put a word into the process' address space at the given address. 12759677Slinton * The address is assumed to be on a word boundary. 12769677Slinton */ 12779677Slinton 12789677Slinton private store(p, seg, addr, data) 12799677Slinton Process p; 12809677Slinton PioSeg seg; 12819677Slinton int addr; 12829677Slinton Word data; 12839677Slinton { 12849677Slinton register CacheWord *wp; 12859677Slinton 12869677Slinton switch (seg) { 12879677Slinton case TEXTSEG: 12889677Slinton ++nwrites; 12899677Slinton wp = &p->word[cachehash(addr)]; 12909677Slinton wp->addr = addr; 12919677Slinton wp->val = data; 129218230Slinton ptrace(IWRITE, p->pid, addr, data); 12939677Slinton break; 12949677Slinton 12959677Slinton case DATASEG: 129618230Slinton ptrace(DWRITE, p->pid, addr, data); 12979677Slinton break; 12989677Slinton 12999677Slinton default: 13009677Slinton panic("store: bad seg %d", seg); 13019677Slinton /* NOTREACHED */ 13029677Slinton } 13039677Slinton } 13049677Slinton 130518230Slinton /* 130618230Slinton * Flush the instruction cache associated with a process. 130718230Slinton */ 130818230Slinton 130918230Slinton private cacheflush (p) 131018230Slinton Process p; 131118230Slinton { 131218230Slinton bzero(p->word, sizeof(p->word)); 131318230Slinton } 131418230Slinton 13159677Slinton public printptraceinfo() 13169677Slinton { 13179677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 13189677Slinton } 13199677Slinton 13209677Slinton /* 132116617Ssam * Redirect input. 132216617Ssam * Assuming this is called from a child, we should be careful to avoid 132316617Ssam * (possibly) shared standard I/O buffers. 13249677Slinton */ 13259677Slinton 132616617Ssam private infrom (filename) 132716617Ssam String filename; 132816617Ssam { 132916617Ssam Fileid in; 133016617Ssam 133116617Ssam in = open(filename, 0); 133216617Ssam if (in == -1) { 133316617Ssam write(2, "can't read ", 11); 133416617Ssam write(2, filename, strlen(filename)); 133516617Ssam write(2, "\n", 1); 133616617Ssam _exit(1); 133716617Ssam } 133816617Ssam fswap(0, in); 133916617Ssam } 134016617Ssam 134116617Ssam /* 134216617Ssam * Redirect standard output. 134316617Ssam * Same assumptions as for "infrom" above. 134416617Ssam */ 134516617Ssam 134616617Ssam private outto (filename) 134716617Ssam String filename; 134816617Ssam { 134916617Ssam Fileid out; 135016617Ssam 135116617Ssam out = creat(filename, 0666); 135216617Ssam if (out == -1) { 135316617Ssam write(2, "can't write ", 12); 135416617Ssam write(2, filename, strlen(filename)); 135516617Ssam write(2, "\n", 1); 135616617Ssam _exit(1); 135716617Ssam } 135816617Ssam fswap(1, out); 135916617Ssam } 136016617Ssam 136116617Ssam /* 136216617Ssam * Swap file numbers, useful for redirecting standard input or output. 136316617Ssam */ 136416617Ssam 13659677Slinton private fswap(oldfd, newfd) 136616617Ssam Fileid oldfd; 136716617Ssam Fileid newfd; 13689677Slinton { 13699677Slinton if (oldfd != newfd) { 13709677Slinton close(oldfd); 13719677Slinton dup(newfd); 13729677Slinton close(newfd); 13739677Slinton } 13749677Slinton } 137516928Ssam 137616928Ssam /* 137718230Slinton * Signal name manipulation. 137816928Ssam */ 137918230Slinton 138018230Slinton private String signames[NSIG] = { 138118230Slinton 0, 138218230Slinton "HUP", "INT", "QUIT", "ILL", "TRAP", 138318230Slinton "IOT", "EMT", "FPE", "KILL", "BUS", 138418230Slinton "SEGV", "SYS", "PIPE", "ALRM", "TERM", 138518230Slinton 0, "STOP", "TSTP", "CONT", "CHLD", 138618230Slinton "TTIN", "TTOU", "TINT", "XCPU", "XFSZ", 1387*26333Ssam "VTALRM", "PROF", "WINCH", "USR1", "USR2" 138816928Ssam }; 138916928Ssam 139016928Ssam /* 139118230Slinton * Get the signal number associated with a given name. 139218230Slinton * The name is first translated to upper case if necessary. 139316928Ssam */ 139418230Slinton 139518230Slinton public integer siglookup (s) 139616928Ssam String s; 139716928Ssam { 139818230Slinton register char *p, *q; 139918230Slinton char buf[100]; 140018230Slinton integer i; 140116928Ssam 140218230Slinton p = s; 140318230Slinton q = buf; 140418230Slinton while (*p != '\0') { 140518230Slinton if (*p >= 'a' and *p <= 'z') { 140618230Slinton *q = (*p - 'a') + 'A'; 140718230Slinton } else { 140818230Slinton *q = *p; 140918230Slinton } 141018230Slinton ++p; 141118230Slinton ++q; 141218230Slinton } 141318230Slinton *q = '\0'; 141418230Slinton p = buf; 141518230Slinton if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') { 141618230Slinton p += 3; 141718230Slinton } 141818230Slinton i = 1; 141918230Slinton for (;;) { 142018230Slinton if (i >= sizeof(signames) div sizeof(signames[0])) { 142118230Slinton error("signal \"%s\" unknown", s); 142218230Slinton i = 0; 142318230Slinton break; 142418230Slinton } 142518230Slinton if (signames[i] != nil and streq(signames[i], p)) { 142618230Slinton break; 142718230Slinton } 142818230Slinton ++i; 142918230Slinton } 143018230Slinton return i; 143116928Ssam } 143216928Ssam 143316928Ssam /* 143418230Slinton * Print all signals being ignored by the debugger. 143518230Slinton * These signals are auotmatically 143616928Ssam * passed on to the debugged process. 143716928Ssam */ 143818230Slinton 143918230Slinton public printsigsignored (p) 144016931Ssam Process p; 144116928Ssam { 144216931Ssam printsigs(~p->sigset); 144316928Ssam } 144416928Ssam 144516928Ssam /* 144616928Ssam * Print all signals being intercepted by 144716928Ssam * the debugger for the specified process. 144816928Ssam */ 144918230Slinton 145016931Ssam public printsigscaught(p) 145116931Ssam Process p; 145216928Ssam { 145316931Ssam printsigs(p->sigset); 145416931Ssam } 145516931Ssam 145618230Slinton private printsigs (set) 145718230Slinton integer set; 145816931Ssam { 145918230Slinton integer s; 146018230Slinton char separator[2]; 146116931Ssam 146218230Slinton separator[0] = '\0'; 146318230Slinton for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) { 146418230Slinton if (set & setrep(s)) { 146518230Slinton if (signames[s] != nil) { 146618230Slinton printf("%s%s", separator, signames[s]); 146718230Slinton separator[0] = ' '; 146818230Slinton separator[1] = '\0'; 146918230Slinton } 147016928Ssam } 147118230Slinton } 147218230Slinton if (separator[0] == ' ') { 147316931Ssam putchar('\n'); 147416931Ssam } 147516928Ssam } 1476