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