19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*11560Slinton static char sccsid[] = "@(#)process.c 1.5 03/13/83"; 49677Slinton 59677Slinton /* 69677Slinton * Process management. 79677Slinton * 89677Slinton * This module contains the routines to manage the execution and 99677Slinton * tracing of the debuggee process. 109677Slinton */ 119677Slinton 129677Slinton #include "defs.h" 139677Slinton #include "process.h" 149677Slinton #include "machine.h" 159677Slinton #include "events.h" 169677Slinton #include "tree.h" 179677Slinton #include "operators.h" 189677Slinton #include "source.h" 199677Slinton #include "object.h" 209677Slinton #include "mappings.h" 219677Slinton #include "main.h" 229677Slinton #include "coredump.h" 239677Slinton #include <signal.h> 249677Slinton #include <errno.h> 259677Slinton #include <sys/param.h> 269843Slinton #include <machine/reg.h> 279677Slinton #include <sys/stat.h> 289677Slinton 299677Slinton #ifndef public 309677Slinton 319677Slinton typedef struct Process *Process; 329677Slinton 339677Slinton Process process; 349677Slinton 359677Slinton #include "machine.h" 369677Slinton 379677Slinton #endif 389677Slinton 399677Slinton #define NOTSTARTED 1 409677Slinton #define STOPPED 0177 419677Slinton #define FINISHED 0 429677Slinton 439677Slinton /* 449677Slinton * Cache-ing of instruction segment is done to reduce the number 459677Slinton * of system calls. 469677Slinton */ 479677Slinton 489677Slinton #define CSIZE 1003 /* size of instruction cache */ 499677Slinton 509677Slinton typedef struct { 519677Slinton Word addr; 529677Slinton Word val; 539677Slinton } CacheWord; 549677Slinton 559677Slinton /* 569677Slinton * This structure holds the information we need from the user structure. 579677Slinton */ 589677Slinton 599677Slinton struct Process { 609677Slinton int pid; /* process being traced */ 619677Slinton int mask; /* ps */ 629677Slinton Word reg[NREG]; /* process's registers */ 639677Slinton Word oreg[NREG]; /* registers when process last stopped */ 649677Slinton short status; /* either STOPPED or FINISHED */ 659677Slinton short signo; /* signal that stopped process */ 669677Slinton int exitval; /* return value from exit() */ 679677Slinton long sigset; /* bit array of traced signals */ 689677Slinton CacheWord word[CSIZE]; /* text segment cache */ 699677Slinton }; 709677Slinton 719677Slinton /* 729677Slinton * These definitions are for the arguments to "pio". 739677Slinton */ 749677Slinton 759677Slinton typedef enum { PREAD, PWRITE } PioOp; 769677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 779677Slinton 789677Slinton private struct Process pbuf; 799677Slinton 809677Slinton #define MAXNCMDARGS 10 /* maximum number of arguments to RUN */ 819677Slinton 829677Slinton private Boolean just_started; 839677Slinton private int argc; 849677Slinton private String argv[MAXNCMDARGS]; 859677Slinton private String infile, outfile; 869677Slinton 879677Slinton /* 889677Slinton * Initialize process information. 899677Slinton */ 909677Slinton 919677Slinton public process_init() 929677Slinton { 939677Slinton register Integer i; 949677Slinton Char buf[10]; 959677Slinton 969677Slinton process = &pbuf; 979677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 989677Slinton setsigtrace(); 999677Slinton for (i = 0; i < NREG; i++) { 1009677Slinton sprintf(buf, "$r%d", i); 1019677Slinton defregname(identname(buf, false), i); 1029677Slinton } 1039677Slinton defregname(identname("$ap", true), ARGP); 1049677Slinton defregname(identname("$fp", true), FRP); 1059677Slinton defregname(identname("$sp", true), STKP); 1069677Slinton defregname(identname("$pc", true), PROGCTR); 1079677Slinton if (coredump) { 1089677Slinton coredump_readin(process->mask, process->reg, process->signo); 1099677Slinton } 1109677Slinton } 1119677Slinton 1129677Slinton /* 1139677Slinton * Routines to get at process information from outside this module. 1149677Slinton */ 1159677Slinton 1169677Slinton public Word reg(n) 1179677Slinton Integer n; 1189677Slinton { 1199677Slinton register Word w; 1209677Slinton 1219677Slinton if (n == NREG) { 1229677Slinton w = process->mask; 1239677Slinton } else { 1249677Slinton w = process->reg[n]; 1259677Slinton } 1269677Slinton return w; 1279677Slinton } 1289677Slinton 1299677Slinton public setreg(n, w) 1309677Slinton Integer n; 1319677Slinton Word w; 1329677Slinton { 1339677Slinton process->reg[n] = w; 1349677Slinton } 1359677Slinton 1369677Slinton /* 1379677Slinton * Begin execution. 1389677Slinton * 1399677Slinton * We set a breakpoint at the end of the code so that the 1409677Slinton * process data doesn't disappear after the program terminates. 1419677Slinton */ 1429677Slinton 1439677Slinton private Boolean remade(); 1449677Slinton 1459677Slinton public start(argv, infile, outfile) 1469677Slinton String argv[]; 1479677Slinton String infile, outfile; 1489677Slinton { 1499677Slinton String pargv[4]; 1509677Slinton Node cond; 1519677Slinton 1529677Slinton if (coredump) { 1539677Slinton coredump = false; 1549677Slinton fclose(corefile); 1559677Slinton coredump_close(); 1569677Slinton } 1579677Slinton if (argv == nil) { 1589677Slinton argv = pargv; 1599677Slinton pargv[0] = objname; 1609677Slinton pargv[1] = nil; 1619677Slinton } else { 1629677Slinton argv[argc] = nil; 1639677Slinton } 1649677Slinton if (remade(objname)) { 1659677Slinton reinit(argv, infile, outfile); 1669677Slinton } 1679677Slinton pstart(process, argv, infile, outfile); 1689677Slinton if (process->status == STOPPED) { 1699677Slinton pc = 0; 1709677Slinton curfunc = program; 1719677Slinton if (objsize != 0) { 1729677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1739677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1749677Slinton } 1759677Slinton } 1769677Slinton } 1779677Slinton 1789677Slinton /* 1799677Slinton * Check to see if the object file has changed since the symbolic 1809677Slinton * information last was read. 1819677Slinton */ 1829677Slinton 1839677Slinton private time_t modtime; 1849677Slinton 1859677Slinton private Boolean remade(filename) 1869677Slinton String filename; 1879677Slinton { 1889677Slinton struct stat s; 1899677Slinton Boolean b; 1909677Slinton 1919677Slinton stat(filename, &s); 1929677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 1939677Slinton modtime = s.st_mtime; 1949677Slinton return b; 1959677Slinton } 1969677Slinton 1979677Slinton /* 1989677Slinton * Set up what signals we want to trace. 1999677Slinton */ 2009677Slinton 2019677Slinton private setsigtrace() 2029677Slinton { 2039677Slinton register Integer i; 2049677Slinton register Process p; 2059677Slinton 2069677Slinton p = process; 2079677Slinton for (i = 1; i <= NSIG; i++) { 2089677Slinton psigtrace(p, i, true); 2099677Slinton } 2109677Slinton psigtrace(p, SIGHUP, false); 2119677Slinton psigtrace(p, SIGKILL, false); 2129677Slinton psigtrace(p, SIGALRM, false); 2139677Slinton psigtrace(p, SIGTSTP, false); 2149677Slinton psigtrace(p, SIGCONT, false); 2159677Slinton psigtrace(p, SIGCHLD, false); 2169677Slinton } 2179677Slinton 2189677Slinton /* 2199677Slinton * Initialize the argument list. 2209677Slinton */ 2219677Slinton 2229677Slinton public arginit() 2239677Slinton { 2249677Slinton infile = nil; 2259677Slinton outfile = nil; 2269677Slinton argv[0] = objname; 2279677Slinton argc = 1; 2289677Slinton } 2299677Slinton 2309677Slinton /* 2319677Slinton * Add an argument to the list for the debuggee. 2329677Slinton */ 2339677Slinton 2349677Slinton public newarg(arg) 2359677Slinton String arg; 2369677Slinton { 2379677Slinton if (argc >= MAXNCMDARGS) { 2389677Slinton error("too many arguments"); 2399677Slinton } 2409677Slinton argv[argc++] = arg; 2419677Slinton } 2429677Slinton 2439677Slinton /* 2449677Slinton * Set the standard input for the debuggee. 2459677Slinton */ 2469677Slinton 2479677Slinton public inarg(filename) 2489677Slinton String filename; 2499677Slinton { 2509677Slinton if (infile != nil) { 2519677Slinton error("multiple input redirects"); 2529677Slinton } 2539677Slinton infile = filename; 2549677Slinton } 2559677Slinton 2569677Slinton /* 2579677Slinton * Set the standard output for the debuggee. 2589677Slinton * Probably should check to avoid overwriting an existing file. 2599677Slinton */ 2609677Slinton 2619677Slinton public outarg(filename) 2629677Slinton String filename; 2639677Slinton { 2649677Slinton if (outfile != nil) { 2659677Slinton error("multiple output redirect"); 2669677Slinton } 2679677Slinton outfile = filename; 2689677Slinton } 2699677Slinton 2709677Slinton /* 2719677Slinton * Start debuggee executing. 2729677Slinton */ 2739677Slinton 2749677Slinton public run() 2759677Slinton { 2769677Slinton process->status = STOPPED; 2779677Slinton fixbps(); 2789677Slinton curline = 0; 2799677Slinton start(argv, infile, outfile); 2809677Slinton just_started = true; 2819677Slinton isstopped = false; 2829677Slinton cont(); 2839677Slinton } 2849677Slinton 2859677Slinton /* 2869677Slinton * Continue execution wherever we left off. 2879677Slinton * 2889677Slinton * Note that this routine never returns. Eventually bpact() will fail 2899677Slinton * and we'll call printstatus or step will call it. 2909677Slinton */ 2919677Slinton 2929677Slinton typedef int Intfunc(); 2939677Slinton 2949677Slinton private Intfunc *dbintr; 2959677Slinton private intr(); 2969677Slinton 2979677Slinton #define succeeds == true 2989677Slinton #define fails == false 2999677Slinton 3009677Slinton public cont() 3019677Slinton { 3029677Slinton dbintr = signal(SIGINT, intr); 3039677Slinton if (just_started) { 3049677Slinton just_started = false; 3059677Slinton } else { 3069677Slinton if (not isstopped) { 3079677Slinton error("can't continue execution"); 3089677Slinton } 3099677Slinton isstopped = false; 3109677Slinton step(); 3119677Slinton } 3129677Slinton for (;;) { 3139677Slinton if (single_stepping) { 3149677Slinton printnews(); 3159677Slinton } else { 3169677Slinton setallbps(); 3179677Slinton resume(); 3189677Slinton unsetallbps(); 3199677Slinton if (bpact() fails) { 3209677Slinton printstatus(); 3219677Slinton } 3229677Slinton } 3239677Slinton step(); 3249677Slinton } 3259677Slinton /* NOTREACHED */ 3269677Slinton } 3279677Slinton 3289677Slinton /* 3299677Slinton * This routine is called if we get an interrupt while "running" px 3309677Slinton * but actually in the debugger. Could happen, for example, while 3319677Slinton * processing breakpoints. 3329677Slinton * 3339677Slinton * We basically just want to keep going; the assumption is 3349677Slinton * that when the process resumes it will get the interrupt 3359677Slinton * which will then be handled. 3369677Slinton */ 3379677Slinton 3389677Slinton private intr() 3399677Slinton { 3409677Slinton signal(SIGINT, intr); 3419677Slinton } 3429677Slinton 3439677Slinton public fixintr() 3449677Slinton { 3459677Slinton signal(SIGINT, dbintr); 3469677Slinton } 3479677Slinton 3489677Slinton /* 3499677Slinton * Resume execution. 3509677Slinton */ 3519677Slinton 3529677Slinton public resume() 3539677Slinton { 3549677Slinton register Process p; 3559677Slinton 3569677Slinton p = process; 3579677Slinton if (traceexec) { 3589677Slinton printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]); 3599677Slinton fflush(stdout); 3609677Slinton } 3619677Slinton pcont(p); 3629677Slinton pc = process->reg[PROGCTR]; 3639677Slinton if (traceexec) { 3649677Slinton printf("execution stops at pc 0x%x on sig %d\n", 3659677Slinton process->reg[PROGCTR], p->signo); 3669677Slinton fflush(stdout); 3679677Slinton } 3689677Slinton } 3699677Slinton 3709677Slinton /* 3719677Slinton * Continue execution up to the next source line. 3729677Slinton * 3739677Slinton * There are two ways to define the next source line depending on what 3749677Slinton * is desired when a procedure or function call is encountered. Step 3759677Slinton * stops at the beginning of the procedure or call; next skips over it. 3769677Slinton */ 3779677Slinton 3789677Slinton /* 3799677Slinton * Stepc is what is called when the step command is given. 3809677Slinton * It has to play with the "isstopped" information. 3819677Slinton */ 3829677Slinton 3839677Slinton public stepc() 3849677Slinton { 3859677Slinton if (not isstopped) { 3869677Slinton error("can't continue execution"); 3879677Slinton } 3889677Slinton isstopped = false; 3899677Slinton dostep(false); 3909677Slinton isstopped = true; 3919677Slinton } 3929677Slinton 3939677Slinton public next() 3949677Slinton { 3959677Slinton if (not isstopped) { 3969677Slinton error("can't continue execution"); 3979677Slinton } 3989677Slinton isstopped = false; 3999677Slinton dostep(true); 4009677Slinton isstopped = true; 4019677Slinton } 4029677Slinton 4039677Slinton public step() 4049677Slinton { 4059677Slinton dostep(false); 4069677Slinton } 4079677Slinton 4089677Slinton /* 4099677Slinton * Resume execution up to the given address. It is assumed that 4109677Slinton * no breakpoints exist between the current address and the one 4119677Slinton * we're stepping to. This saves us from setting all the breakpoints. 4129677Slinton */ 4139677Slinton 4149677Slinton public stepto(addr) 4159677Slinton Address addr; 4169677Slinton { 4179677Slinton setbp(addr); 4189677Slinton resume(); 4199677Slinton unsetbp(addr); 4209677Slinton if (not isbperr()) { 4219677Slinton printstatus(); 4229677Slinton } 4239677Slinton } 4249677Slinton 4259677Slinton /* 4269677Slinton * Print the status of the process. 4279677Slinton * This routine does not return. 4289677Slinton */ 4299677Slinton 4309677Slinton public printstatus() 4319677Slinton { 4329843Slinton if (process->status == FINISHED) { 4339843Slinton exit(0); 4349843Slinton } else { 4359843Slinton curfunc = whatblock(pc); 4369677Slinton getsrcpos(); 4379843Slinton if (process->signo == SIGINT) { 4389843Slinton isstopped = true; 4399843Slinton printerror(); 4409843Slinton } else if (isbperr() and isstopped) { 4419843Slinton printf("stopped "); 44211172Slinton printloc(); 44311172Slinton putchar('\n'); 4449843Slinton if (curline > 0) { 4459843Slinton printlines(curline, curline); 4469843Slinton } else { 4479843Slinton printinst(pc, pc); 4489843Slinton } 4499843Slinton erecover(); 4509677Slinton } else { 4519843Slinton fixbps(); 4529843Slinton fixintr(); 4539677Slinton isstopped = true; 4549677Slinton printerror(); 4559677Slinton } 4569677Slinton } 4579677Slinton } 4589677Slinton 4599677Slinton /* 46011172Slinton * Print out the current location in the debuggee. 46111172Slinton */ 46211172Slinton 46311172Slinton public printloc() 46411172Slinton { 46511172Slinton printf("in "); 46611172Slinton printname(stdout, curfunc); 46711172Slinton putchar(' '); 46811172Slinton if (curline > 0) { 46911172Slinton printsrcpos(); 47011172Slinton } else { 47111172Slinton printf("at 0x%x", pc); 47211172Slinton } 47311172Slinton } 47411172Slinton 47511172Slinton /* 4769677Slinton * Some functions for testing the state of the process. 4779677Slinton */ 4789677Slinton 4799677Slinton public Boolean notstarted(p) 4809677Slinton Process p; 4819677Slinton { 4829677Slinton return (Boolean) (p->status == NOTSTARTED); 4839677Slinton } 4849677Slinton 4859677Slinton public Boolean isfinished(p) 4869677Slinton Process p; 4879677Slinton { 4889677Slinton return (Boolean) (p->status == FINISHED); 4899677Slinton } 4909677Slinton 4919677Slinton /* 4929677Slinton * Return the signal number which stopped the process. 4939677Slinton */ 4949677Slinton 4959677Slinton public Integer errnum(p) 4969677Slinton Process p; 4979677Slinton { 4989677Slinton return p->signo; 4999677Slinton } 5009677Slinton 5019677Slinton /* 5029677Slinton * Return the termination code of the process. 5039677Slinton */ 5049677Slinton 5059677Slinton public Integer exitcode(p) 5069677Slinton Process p; 5079677Slinton { 5089677Slinton return p->exitval; 5099677Slinton } 5109677Slinton 5119677Slinton /* 5129677Slinton * These routines are used to access the debuggee process from 5139677Slinton * outside this module. 5149677Slinton * 5159677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 516*11560Slinton * The system generates an I/O error when a ptrace fails, we assume 517*11560Slinton * during a read/write to the process that such an error is due to 518*11560Slinton * a misguided address and ignore it. 5199677Slinton */ 5209677Slinton 5219677Slinton extern Intfunc *onsyserr(); 5229677Slinton 5239677Slinton private badaddr; 5249677Slinton private rwerr(); 5259677Slinton 5269677Slinton /* 5279677Slinton * Read from the process' instruction area. 5289677Slinton */ 5299677Slinton 5309677Slinton public iread(buff, addr, nbytes) 5319677Slinton char *buff; 5329677Slinton Address addr; 5339677Slinton int nbytes; 5349677Slinton { 5359677Slinton Intfunc *f; 5369677Slinton 5379677Slinton f = onsyserr(EIO, rwerr); 5389677Slinton badaddr = addr; 5399677Slinton if (coredump) { 5409677Slinton coredump_readtext(buff, addr, nbytes); 5419677Slinton } else { 5429677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 5439677Slinton } 5449677Slinton onsyserr(EIO, f); 5459677Slinton } 5469677Slinton 5479677Slinton /* 5489677Slinton * Write to the process' instruction area, usually in order to set 5499677Slinton * or unset a breakpoint. 5509677Slinton */ 5519677Slinton 5529677Slinton public iwrite(buff, addr, nbytes) 5539677Slinton char *buff; 5549677Slinton Address addr; 5559677Slinton int nbytes; 5569677Slinton { 5579677Slinton Intfunc *f; 5589677Slinton 5599677Slinton if (coredump) { 5609677Slinton error("no process to write to"); 5619677Slinton } 5629677Slinton f = onsyserr(EIO, rwerr); 5639677Slinton badaddr = addr; 5649677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 5659677Slinton onsyserr(EIO, f); 5669677Slinton } 5679677Slinton 5689677Slinton /* 5699677Slinton * Read for the process' data area. 5709677Slinton */ 5719677Slinton 5729677Slinton public dread(buff, addr, nbytes) 5739677Slinton char *buff; 5749677Slinton Address addr; 5759677Slinton int nbytes; 5769677Slinton { 5779677Slinton Intfunc *f; 5789677Slinton 5799677Slinton f = onsyserr(EIO, rwerr); 5809677Slinton badaddr = addr; 5819677Slinton if (coredump) { 5829677Slinton coredump_readdata(buff, addr, nbytes); 5839677Slinton } else { 5849677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 5859677Slinton } 5869677Slinton onsyserr(EIO, f); 5879677Slinton } 5889677Slinton 5899677Slinton /* 5909677Slinton * Write to the process' data area. 5919677Slinton */ 5929677Slinton 5939677Slinton public dwrite(buff, addr, nbytes) 5949677Slinton char *buff; 5959677Slinton Address addr; 5969677Slinton int nbytes; 5979677Slinton { 5989677Slinton Intfunc *f; 5999677Slinton 6009677Slinton if (coredump) { 6019677Slinton error("no process to write to"); 6029677Slinton } 6039677Slinton f = onsyserr(EIO, rwerr); 6049677Slinton badaddr = addr; 6059677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 6069677Slinton onsyserr(EIO, f); 6079677Slinton } 6089677Slinton 6099677Slinton /* 6109677Slinton * Error handler. 6119677Slinton */ 6129677Slinton 6139677Slinton private rwerr() 6149677Slinton { 615*11560Slinton /* 616*11560Slinton * Current response is to ignore the error and let the result 617*11560Slinton * (-1) ripple back up to the process. 618*11560Slinton * 6199677Slinton error("bad read/write process address 0x%x", badaddr); 620*11560Slinton */ 6219677Slinton } 6229677Slinton 6239677Slinton /* 6249677Slinton * Ptrace interface. 6259677Slinton */ 6269677Slinton 6279677Slinton /* 6289677Slinton * This magic macro enables us to look at the process' registers 6299677Slinton * in its user structure. Very gross. 6309677Slinton */ 6319677Slinton 6329677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 6339677Slinton 6349677Slinton #define WMASK (~(sizeof(Word) - 1)) 6359677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 6369677Slinton 6379677Slinton #define FIRSTSIG SIGINT 6389677Slinton #define LASTSIG SIGQUIT 6399677Slinton #define ischild(pid) ((pid) == 0) 6409677Slinton #define traceme() ptrace(0, 0, 0, 0) 6419677Slinton #define setrep(n) (1 << ((n)-1)) 6429677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 6439677Slinton 6449677Slinton /* 6459677Slinton * Ptrace options (specified in first argument). 6469677Slinton */ 6479677Slinton 6489677Slinton #define UREAD 3 /* read from process's user structure */ 6499677Slinton #define UWRITE 6 /* write to process's user structure */ 6509677Slinton #define IREAD 1 /* read from process's instruction space */ 6519677Slinton #define IWRITE 4 /* write to process's instruction space */ 6529677Slinton #define DREAD 2 /* read from process's data space */ 6539677Slinton #define DWRITE 5 /* write to process's data space */ 6549677Slinton #define CONT 7 /* continue stopped process */ 6559677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 6569677Slinton #define PKILL 8 /* terminate the process */ 6579677Slinton 6589677Slinton /* 6599677Slinton * Start up a new process by forking and exec-ing the 6609677Slinton * given argument list, returning when the process is loaded 6619677Slinton * and ready to execute. The PROCESS information (pointed to 6629677Slinton * by the first argument) is appropriately filled. 6639677Slinton * 6649677Slinton * If the given PROCESS structure is associated with an already running 6659677Slinton * process, we terminate it. 6669677Slinton */ 6679677Slinton 6689677Slinton /* VARARGS2 */ 6699677Slinton private pstart(p, argv, infile, outfile) 6709677Slinton Process p; 6719677Slinton String argv[]; 6729677Slinton String infile; 6739677Slinton String outfile; 6749677Slinton { 6759677Slinton int status; 6769677Slinton 6779677Slinton if (p->pid != 0) { /* child already running? */ 6789677Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 6799677Slinton } 6809677Slinton psigtrace(p, SIGTRAP, true); 68111172Slinton if ((p->pid = vfork()) == -1) { 6829677Slinton panic("can't fork"); 6839677Slinton } 6849677Slinton if (ischild(p->pid)) { 68511172Slinton Fileid in, out; 68611172Slinton 6879677Slinton traceme(); 6889677Slinton if (infile != nil) { 68911172Slinton in = open(infile, 0); 69011172Slinton if (in == -1) { 69111172Slinton write(2, "can't read ", 11); 69211172Slinton write(2, infile, strlen(infile)); 69311172Slinton write(2, "\n", 1); 69411172Slinton _exit(1); 6959677Slinton } 69611172Slinton fswap(0, in); 6979677Slinton } 6989677Slinton if (outfile != nil) { 69911172Slinton out = creat(outfile, 0666); 70011172Slinton if (out == -1) { 70111172Slinton write(2, "can't write ", 12); 70211172Slinton write(2, outfile, strlen(outfile)); 70311172Slinton write(2, "\n", 1); 70411172Slinton _exit(1); 7059677Slinton } 70611172Slinton fswap(1, out); 7079677Slinton } 7089677Slinton execvp(argv[0], argv); 70911172Slinton write(2, "can't exec ", 11); 71011172Slinton write(2, argv[0], strlen(argv[0])); 71111172Slinton write(2, "\n", 1); 71211172Slinton _exit(1); 7139677Slinton } 7149677Slinton pwait(p->pid, &status); 7159677Slinton getinfo(p, status); 7169677Slinton if (p->status != STOPPED) { 7179677Slinton error("program could not begin execution"); 7189677Slinton } 7199677Slinton } 7209677Slinton 7219677Slinton /* 7229677Slinton * Continue a stopped process. The argument points to a PROCESS structure. 7239677Slinton * Before the process is restarted it's user area is modified according to 7249677Slinton * the values in the structure. When this routine finishes, 7259677Slinton * the structure has the new values from the process's user area. 7269677Slinton * 7279677Slinton * Pcont terminates when the process stops with a signal pending that 7289677Slinton * is being traced (via psigtrace), or when the process terminates. 7299677Slinton */ 7309677Slinton 7319677Slinton private pcont(p) 7329677Slinton Process p; 7339677Slinton { 7349677Slinton int status; 7359677Slinton 7369677Slinton if (p->pid == 0) { 7379677Slinton error("program not active"); 7389677Slinton } 7399677Slinton do { 7409677Slinton setinfo(p); 7419677Slinton sigs_off(); 7429677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 7439677Slinton panic("can't continue process"); 7449677Slinton } 7459677Slinton pwait(p->pid, &status); 7469677Slinton sigs_on(); 7479677Slinton getinfo(p, status); 7489677Slinton } while (p->status == STOPPED and not istraced(p)); 7499677Slinton } 7509677Slinton 7519677Slinton /* 7529677Slinton * Single step as best ptrace can. 7539677Slinton */ 7549677Slinton 7559677Slinton public pstep(p) 7569677Slinton Process p; 7579677Slinton { 7589677Slinton int status; 7599677Slinton 7609677Slinton setinfo(p); 7619677Slinton sigs_off(); 7629677Slinton ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 7639677Slinton pwait(p->pid, &status); 7649677Slinton sigs_on(); 7659677Slinton getinfo(p, status); 7669677Slinton } 7679677Slinton 7689677Slinton /* 7699677Slinton * Return from execution when the given signal is pending. 7709677Slinton */ 7719677Slinton 7729677Slinton public psigtrace(p, sig, sw) 7739677Slinton Process p; 7749677Slinton int sig; 7759677Slinton Boolean sw; 7769677Slinton { 7779677Slinton if (sw) { 7789677Slinton p->sigset |= setrep(sig); 7799677Slinton } else { 7809677Slinton p->sigset &= ~setrep(sig); 7819677Slinton } 7829677Slinton } 7839677Slinton 7849677Slinton /* 7859677Slinton * Don't catch any signals. 7869677Slinton * Particularly useful when letting a process finish uninhibited. 7879677Slinton */ 7889677Slinton 7899677Slinton public unsetsigtraces(p) 7909677Slinton Process p; 7919677Slinton { 7929677Slinton p->sigset = 0; 7939677Slinton } 7949677Slinton 7959677Slinton /* 7969677Slinton * Turn off attention to signals not being caught. 7979677Slinton */ 7989677Slinton 7999677Slinton private Intfunc *sigfunc[NSIG]; 8009677Slinton 8019677Slinton private sigs_off() 8029677Slinton { 8039677Slinton register int i; 8049677Slinton 8059677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8069677Slinton if (i != SIGKILL) { 8079677Slinton sigfunc[i] = signal(i, SIG_IGN); 8089677Slinton } 8099677Slinton } 8109677Slinton } 8119677Slinton 8129677Slinton /* 8139677Slinton * Turn back on attention to signals. 8149677Slinton */ 8159677Slinton 8169677Slinton private sigs_on() 8179677Slinton { 8189677Slinton register int i; 8199677Slinton 8209677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8219677Slinton if (i != SIGKILL) { 8229677Slinton signal(i, sigfunc[i]); 8239677Slinton } 8249677Slinton } 8259677Slinton } 8269677Slinton 8279677Slinton /* 8289677Slinton * Get process information from user area. 8299677Slinton */ 8309677Slinton 8319677Slinton private int rloc[] ={ 8329677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 8339677Slinton }; 8349677Slinton 8359677Slinton private getinfo(p, status) 8369677Slinton register Process p; 8379677Slinton register int status; 8389677Slinton { 8399677Slinton register int i; 8409677Slinton 8419677Slinton p->signo = (status&0177); 8429677Slinton p->exitval = ((status >> 8)&0377); 8439677Slinton if (p->signo != STOPPED) { 8449677Slinton p->status = FINISHED; 8459677Slinton } else { 8469677Slinton p->status = p->signo; 8479677Slinton p->signo = p->exitval; 8489677Slinton p->exitval = 0; 8499677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 8509677Slinton for (i = 0; i < NREG; i++) { 8519677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 8529677Slinton p->oreg[i] = p->reg[i]; 8539677Slinton } 8549677Slinton } 8559677Slinton } 8569677Slinton 8579677Slinton /* 8589677Slinton * Set process's user area information from given process structure. 8599677Slinton */ 8609677Slinton 8619677Slinton private setinfo(p) 8629677Slinton register Process p; 8639677Slinton { 8649677Slinton register int i; 8659677Slinton register int r; 8669677Slinton 8679677Slinton if (istraced(p)) { 8689677Slinton p->signo = 0; 8699677Slinton } 8709677Slinton for (i = 0; i < NREG; i++) { 8719677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 8729677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 8739677Slinton } 8749677Slinton } 8759677Slinton } 8769677Slinton 8779677Slinton /* 8789677Slinton * Structure for reading and writing by words, but dealing with bytes. 8799677Slinton */ 8809677Slinton 8819677Slinton typedef union { 8829677Slinton Word pword; 8839677Slinton Byte pbyte[sizeof(Word)]; 8849677Slinton } Pword; 8859677Slinton 8869677Slinton /* 8879677Slinton * Read (write) from (to) the process' address space. 8889677Slinton * We must deal with ptrace's inability to look anywhere other 8899677Slinton * than at a word boundary. 8909677Slinton */ 8919677Slinton 8929677Slinton private Word fetch(); 8939677Slinton private store(); 8949677Slinton 8959677Slinton private pio(p, op, seg, buff, addr, nbytes) 8969677Slinton Process p; 8979677Slinton PioOp op; 8989677Slinton PioSeg seg; 8999677Slinton char *buff; 9009677Slinton Address addr; 9019677Slinton int nbytes; 9029677Slinton { 9039677Slinton register int i; 9049677Slinton register Address newaddr; 9059677Slinton register char *cp; 9069677Slinton char *bufend; 9079677Slinton Pword w; 9089677Slinton Address wordaddr; 9099677Slinton int byteoff; 9109677Slinton 9119677Slinton if (p->status != STOPPED) { 9129677Slinton error("program is not active"); 9139677Slinton } 9149677Slinton cp = buff; 9159677Slinton newaddr = addr; 9169677Slinton wordaddr = (newaddr&WMASK); 9179677Slinton if (wordaddr != newaddr) { 9189677Slinton w.pword = fetch(p, seg, wordaddr); 9199677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 9209677Slinton if (op == PREAD) { 9219677Slinton *cp++ = w.pbyte[i]; 9229677Slinton } else { 9239677Slinton w.pbyte[i] = *cp++; 9249677Slinton } 9259677Slinton nbytes--; 9269677Slinton } 9279677Slinton if (op == PWRITE) { 9289677Slinton store(p, seg, wordaddr, w.pword); 9299677Slinton } 9309677Slinton newaddr = wordaddr + sizeof(Word); 9319677Slinton } 9329677Slinton byteoff = (nbytes&(~WMASK)); 9339677Slinton nbytes -= byteoff; 9349677Slinton bufend = cp + nbytes; 9359677Slinton while (cp < bufend) { 9369677Slinton if (op == PREAD) { 9379677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 9389677Slinton } else { 9399677Slinton store(p, seg, newaddr, *((Word *) cp)); 9409677Slinton } 9419677Slinton cp += sizeof(Word); 9429677Slinton newaddr += sizeof(Word); 9439677Slinton } 9449677Slinton if (byteoff > 0) { 9459677Slinton w.pword = fetch(p, seg, newaddr); 9469677Slinton for (i = 0; i < byteoff; i++) { 9479677Slinton if (op == PREAD) { 9489677Slinton *cp++ = w.pbyte[i]; 9499677Slinton } else { 9509677Slinton w.pbyte[i] = *cp++; 9519677Slinton } 9529677Slinton } 9539677Slinton if (op == PWRITE) { 9549677Slinton store(p, seg, newaddr, w.pword); 9559677Slinton } 9569677Slinton } 9579677Slinton } 9589677Slinton 9599677Slinton /* 9609677Slinton * Get a word from a process at the given address. 9619677Slinton * The address is assumed to be on a word boundary. 9629677Slinton * 9639677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 9649677Slinton * to the instruction space since it is assumed to be pure. 9659677Slinton * 9669677Slinton * It is necessary to use a write-through scheme so that 9679677Slinton * breakpoints right next to each other don't interfere. 9689677Slinton */ 9699677Slinton 9709677Slinton private Integer nfetchs, nreads, nwrites; 9719677Slinton 9729677Slinton private Word fetch(p, seg, addr) 9739677Slinton Process p; 9749677Slinton PioSeg seg; 9759677Slinton register int addr; 9769677Slinton { 9779677Slinton register CacheWord *wp; 9789677Slinton register Word w; 9799677Slinton 9809677Slinton switch (seg) { 9819677Slinton case TEXTSEG: 9829677Slinton ++nfetchs; 9839677Slinton wp = &p->word[cachehash(addr)]; 9849677Slinton if (addr == 0 or wp->addr != addr) { 9859677Slinton ++nreads; 9869677Slinton w = ptrace(IREAD, p->pid, addr, 0); 9879677Slinton wp->addr = addr; 9889677Slinton wp->val = w; 9899677Slinton } else { 9909677Slinton w = wp->val; 9919677Slinton } 9929677Slinton break; 9939677Slinton 9949677Slinton case DATASEG: 9959677Slinton w = ptrace(DREAD, p->pid, addr, 0); 9969677Slinton break; 9979677Slinton 9989677Slinton default: 9999677Slinton panic("fetch: bad seg %d", seg); 10009677Slinton /* NOTREACHED */ 10019677Slinton } 10029677Slinton return w; 10039677Slinton } 10049677Slinton 10059677Slinton /* 10069677Slinton * Put a word into the process' address space at the given address. 10079677Slinton * The address is assumed to be on a word boundary. 10089677Slinton */ 10099677Slinton 10109677Slinton private store(p, seg, addr, data) 10119677Slinton Process p; 10129677Slinton PioSeg seg; 10139677Slinton int addr; 10149677Slinton Word data; 10159677Slinton { 10169677Slinton register CacheWord *wp; 10179677Slinton 10189677Slinton switch (seg) { 10199677Slinton case TEXTSEG: 10209677Slinton ++nwrites; 10219677Slinton wp = &p->word[cachehash(addr)]; 10229677Slinton wp->addr = addr; 10239677Slinton wp->val = data; 10249677Slinton ptrace(IWRITE, p->pid, addr, data); 10259677Slinton break; 10269677Slinton 10279677Slinton case DATASEG: 10289677Slinton ptrace(DWRITE, p->pid, addr, data); 10299677Slinton break; 10309677Slinton 10319677Slinton default: 10329677Slinton panic("store: bad seg %d", seg); 10339677Slinton /* NOTREACHED */ 10349677Slinton } 10359677Slinton } 10369677Slinton 10379677Slinton public printptraceinfo() 10389677Slinton { 10399677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 10409677Slinton } 10419677Slinton 10429677Slinton /* 10439677Slinton * Swap file numbers so as to redirect standard input and output. 10449677Slinton */ 10459677Slinton 10469677Slinton private fswap(oldfd, newfd) 10479677Slinton int oldfd; 10489677Slinton int newfd; 10499677Slinton { 10509677Slinton if (oldfd != newfd) { 10519677Slinton close(oldfd); 10529677Slinton dup(newfd); 10539677Slinton close(newfd); 10549677Slinton } 10559677Slinton } 1056