19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*9843Slinton static char sccsid[] = "@(#)process.c 1.3 12/18/82"; 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> 26*9843Slinton #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 { 432*9843Slinton if (process->status == FINISHED) { 433*9843Slinton exit(0); 434*9843Slinton } else { 435*9843Slinton curfunc = whatblock(pc); 4369677Slinton getsrcpos(); 437*9843Slinton if (process->signo == SIGINT) { 438*9843Slinton isstopped = true; 439*9843Slinton printerror(); 440*9843Slinton } else if (isbperr() and isstopped) { 441*9843Slinton printf("stopped "); 442*9843Slinton if (curline > 0) { 443*9843Slinton printsrcpos(); 444*9843Slinton putchar('\n'); 445*9843Slinton printlines(curline, curline); 446*9843Slinton } else { 447*9843Slinton printf("in "); 448*9843Slinton printwhich(stdout, curfunc); 449*9843Slinton printf(" at 0x%x\n", pc); 450*9843Slinton printinst(pc, pc); 451*9843Slinton } 452*9843Slinton erecover(); 4539677Slinton } else { 454*9843Slinton fixbps(); 455*9843Slinton fixintr(); 4569677Slinton isstopped = true; 4579677Slinton printerror(); 4589677Slinton } 4599677Slinton } 4609677Slinton } 4619677Slinton 4629677Slinton /* 4639677Slinton * Some functions for testing the state of the process. 4649677Slinton */ 4659677Slinton 4669677Slinton public Boolean notstarted(p) 4679677Slinton Process p; 4689677Slinton { 4699677Slinton return (Boolean) (p->status == NOTSTARTED); 4709677Slinton } 4719677Slinton 4729677Slinton public Boolean isfinished(p) 4739677Slinton Process p; 4749677Slinton { 4759677Slinton return (Boolean) (p->status == FINISHED); 4769677Slinton } 4779677Slinton 4789677Slinton /* 4799677Slinton * Return the signal number which stopped the process. 4809677Slinton */ 4819677Slinton 4829677Slinton public Integer errnum(p) 4839677Slinton Process p; 4849677Slinton { 4859677Slinton return p->signo; 4869677Slinton } 4879677Slinton 4889677Slinton /* 4899677Slinton * Return the termination code of the process. 4909677Slinton */ 4919677Slinton 4929677Slinton public Integer exitcode(p) 4939677Slinton Process p; 4949677Slinton { 4959677Slinton return p->exitval; 4969677Slinton } 4979677Slinton 4989677Slinton /* 4999677Slinton * These routines are used to access the debuggee process from 5009677Slinton * outside this module. 5019677Slinton * 5029677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 5039677Slinton * The system generates an I/O error when a ptrace fails, we catch 5049677Slinton * that here and assume its due to a misguided address. 5059677Slinton */ 5069677Slinton 5079677Slinton extern Intfunc *onsyserr(); 5089677Slinton 5099677Slinton private badaddr; 5109677Slinton private rwerr(); 5119677Slinton 5129677Slinton /* 5139677Slinton * Read from the process' instruction area. 5149677Slinton */ 5159677Slinton 5169677Slinton public iread(buff, addr, nbytes) 5179677Slinton char *buff; 5189677Slinton Address addr; 5199677Slinton int nbytes; 5209677Slinton { 5219677Slinton Intfunc *f; 5229677Slinton 5239677Slinton f = onsyserr(EIO, rwerr); 5249677Slinton badaddr = addr; 5259677Slinton if (coredump) { 5269677Slinton coredump_readtext(buff, addr, nbytes); 5279677Slinton } else { 5289677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 5299677Slinton } 5309677Slinton onsyserr(EIO, f); 5319677Slinton } 5329677Slinton 5339677Slinton /* 5349677Slinton * Write to the process' instruction area, usually in order to set 5359677Slinton * or unset a breakpoint. 5369677Slinton */ 5379677Slinton 5389677Slinton public iwrite(buff, addr, nbytes) 5399677Slinton char *buff; 5409677Slinton Address addr; 5419677Slinton int nbytes; 5429677Slinton { 5439677Slinton Intfunc *f; 5449677Slinton 5459677Slinton if (coredump) { 5469677Slinton error("no process to write to"); 5479677Slinton } 5489677Slinton f = onsyserr(EIO, rwerr); 5499677Slinton badaddr = addr; 5509677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 5519677Slinton onsyserr(EIO, f); 5529677Slinton } 5539677Slinton 5549677Slinton /* 5559677Slinton * Read for the process' data area. 5569677Slinton */ 5579677Slinton 5589677Slinton public dread(buff, addr, nbytes) 5599677Slinton char *buff; 5609677Slinton Address addr; 5619677Slinton int nbytes; 5629677Slinton { 5639677Slinton Intfunc *f; 5649677Slinton 5659677Slinton f = onsyserr(EIO, rwerr); 5669677Slinton badaddr = addr; 5679677Slinton if (coredump) { 5689677Slinton coredump_readdata(buff, addr, nbytes); 5699677Slinton } else { 5709677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 5719677Slinton } 5729677Slinton onsyserr(EIO, f); 5739677Slinton } 5749677Slinton 5759677Slinton /* 5769677Slinton * Write to the process' data area. 5779677Slinton */ 5789677Slinton 5799677Slinton public dwrite(buff, addr, nbytes) 5809677Slinton char *buff; 5819677Slinton Address addr; 5829677Slinton int nbytes; 5839677Slinton { 5849677Slinton Intfunc *f; 5859677Slinton 5869677Slinton if (coredump) { 5879677Slinton error("no process to write to"); 5889677Slinton } 5899677Slinton f = onsyserr(EIO, rwerr); 5909677Slinton badaddr = addr; 5919677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 5929677Slinton onsyserr(EIO, f); 5939677Slinton } 5949677Slinton 5959677Slinton /* 5969677Slinton * Error handler. 5979677Slinton */ 5989677Slinton 5999677Slinton private rwerr() 6009677Slinton { 6019677Slinton error("bad read/write process address 0x%x", badaddr); 6029677Slinton } 6039677Slinton 6049677Slinton /* 6059677Slinton * Ptrace interface. 6069677Slinton */ 6079677Slinton 6089677Slinton /* 6099677Slinton * This magic macro enables us to look at the process' registers 6109677Slinton * in its user structure. Very gross. 6119677Slinton */ 6129677Slinton 6139677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 6149677Slinton 6159677Slinton #define WMASK (~(sizeof(Word) - 1)) 6169677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 6179677Slinton 6189677Slinton #define FIRSTSIG SIGINT 6199677Slinton #define LASTSIG SIGQUIT 6209677Slinton #define ischild(pid) ((pid) == 0) 6219677Slinton #define traceme() ptrace(0, 0, 0, 0) 6229677Slinton #define setrep(n) (1 << ((n)-1)) 6239677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 6249677Slinton 6259677Slinton /* 6269677Slinton * Ptrace options (specified in first argument). 6279677Slinton */ 6289677Slinton 6299677Slinton #define UREAD 3 /* read from process's user structure */ 6309677Slinton #define UWRITE 6 /* write to process's user structure */ 6319677Slinton #define IREAD 1 /* read from process's instruction space */ 6329677Slinton #define IWRITE 4 /* write to process's instruction space */ 6339677Slinton #define DREAD 2 /* read from process's data space */ 6349677Slinton #define DWRITE 5 /* write to process's data space */ 6359677Slinton #define CONT 7 /* continue stopped process */ 6369677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 6379677Slinton #define PKILL 8 /* terminate the process */ 6389677Slinton 6399677Slinton /* 6409677Slinton * Start up a new process by forking and exec-ing the 6419677Slinton * given argument list, returning when the process is loaded 6429677Slinton * and ready to execute. The PROCESS information (pointed to 6439677Slinton * by the first argument) is appropriately filled. 6449677Slinton * 6459677Slinton * If the given PROCESS structure is associated with an already running 6469677Slinton * process, we terminate it. 6479677Slinton */ 6489677Slinton 6499677Slinton /* VARARGS2 */ 6509677Slinton private pstart(p, argv, infile, outfile) 6519677Slinton Process p; 6529677Slinton String argv[]; 6539677Slinton String infile; 6549677Slinton String outfile; 6559677Slinton { 6569677Slinton int status; 6579677Slinton File in, out; 6589677Slinton 6599677Slinton if (p->pid != 0) { /* child already running? */ 6609677Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 6619677Slinton } 6629677Slinton psigtrace(p, SIGTRAP, true); 6639677Slinton if ((p->pid = fork()) == -1) { 6649677Slinton panic("can't fork"); 6659677Slinton } 6669677Slinton if (ischild(p->pid)) { 6679677Slinton traceme(); 6689677Slinton if (infile != nil) { 6699677Slinton in = fopen(infile, "r"); 6709677Slinton if (in == nil) { 6719677Slinton printf("can't read %s\n", infile); 6729677Slinton exit(1); 6739677Slinton } 6749677Slinton fswap(0, fileno(in)); 6759677Slinton } 6769677Slinton if (outfile != nil) { 6779677Slinton out = fopen(outfile, "w"); 6789677Slinton if (out == nil) { 6799677Slinton printf("can't write %s\n", outfile); 6809677Slinton exit(1); 6819677Slinton } 6829677Slinton fswap(1, fileno(out)); 6839677Slinton } 6849677Slinton execvp(argv[0], argv); 6859677Slinton panic("can't exec %s", argv[0]); 6869677Slinton } 6879677Slinton pwait(p->pid, &status); 6889677Slinton getinfo(p, status); 6899677Slinton if (p->status != STOPPED) { 6909677Slinton error("program could not begin execution"); 6919677Slinton } 6929677Slinton } 6939677Slinton 6949677Slinton /* 6959677Slinton * Continue a stopped process. The argument points to a PROCESS structure. 6969677Slinton * Before the process is restarted it's user area is modified according to 6979677Slinton * the values in the structure. When this routine finishes, 6989677Slinton * the structure has the new values from the process's user area. 6999677Slinton * 7009677Slinton * Pcont terminates when the process stops with a signal pending that 7019677Slinton * is being traced (via psigtrace), or when the process terminates. 7029677Slinton */ 7039677Slinton 7049677Slinton private pcont(p) 7059677Slinton Process p; 7069677Slinton { 7079677Slinton int status; 7089677Slinton 7099677Slinton if (p->pid == 0) { 7109677Slinton error("program not active"); 7119677Slinton } 7129677Slinton do { 7139677Slinton setinfo(p); 7149677Slinton sigs_off(); 7159677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 7169677Slinton panic("can't continue process"); 7179677Slinton } 7189677Slinton pwait(p->pid, &status); 7199677Slinton sigs_on(); 7209677Slinton getinfo(p, status); 7219677Slinton } while (p->status == STOPPED and not istraced(p)); 7229677Slinton } 7239677Slinton 7249677Slinton /* 7259677Slinton * Single step as best ptrace can. 7269677Slinton */ 7279677Slinton 7289677Slinton public pstep(p) 7299677Slinton Process p; 7309677Slinton { 7319677Slinton int status; 7329677Slinton 7339677Slinton setinfo(p); 7349677Slinton sigs_off(); 7359677Slinton ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 7369677Slinton pwait(p->pid, &status); 7379677Slinton sigs_on(); 7389677Slinton getinfo(p, status); 7399677Slinton } 7409677Slinton 7419677Slinton /* 7429677Slinton * Return from execution when the given signal is pending. 7439677Slinton */ 7449677Slinton 7459677Slinton public psigtrace(p, sig, sw) 7469677Slinton Process p; 7479677Slinton int sig; 7489677Slinton Boolean sw; 7499677Slinton { 7509677Slinton if (sw) { 7519677Slinton p->sigset |= setrep(sig); 7529677Slinton } else { 7539677Slinton p->sigset &= ~setrep(sig); 7549677Slinton } 7559677Slinton } 7569677Slinton 7579677Slinton /* 7589677Slinton * Don't catch any signals. 7599677Slinton * Particularly useful when letting a process finish uninhibited. 7609677Slinton */ 7619677Slinton 7629677Slinton public unsetsigtraces(p) 7639677Slinton Process p; 7649677Slinton { 7659677Slinton p->sigset = 0; 7669677Slinton } 7679677Slinton 7689677Slinton /* 7699677Slinton * Turn off attention to signals not being caught. 7709677Slinton */ 7719677Slinton 7729677Slinton private Intfunc *sigfunc[NSIG]; 7739677Slinton 7749677Slinton private sigs_off() 7759677Slinton { 7769677Slinton register int i; 7779677Slinton 7789677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 7799677Slinton if (i != SIGKILL) { 7809677Slinton sigfunc[i] = signal(i, SIG_IGN); 7819677Slinton } 7829677Slinton } 7839677Slinton } 7849677Slinton 7859677Slinton /* 7869677Slinton * Turn back on attention to signals. 7879677Slinton */ 7889677Slinton 7899677Slinton private sigs_on() 7909677Slinton { 7919677Slinton register int i; 7929677Slinton 7939677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 7949677Slinton if (i != SIGKILL) { 7959677Slinton signal(i, sigfunc[i]); 7969677Slinton } 7979677Slinton } 7989677Slinton } 7999677Slinton 8009677Slinton /* 8019677Slinton * Get process information from user area. 8029677Slinton */ 8039677Slinton 8049677Slinton private int rloc[] ={ 8059677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 8069677Slinton }; 8079677Slinton 8089677Slinton private getinfo(p, status) 8099677Slinton register Process p; 8109677Slinton register int status; 8119677Slinton { 8129677Slinton register int i; 8139677Slinton 8149677Slinton p->signo = (status&0177); 8159677Slinton p->exitval = ((status >> 8)&0377); 8169677Slinton if (p->signo != STOPPED) { 8179677Slinton p->status = FINISHED; 8189677Slinton } else { 8199677Slinton p->status = p->signo; 8209677Slinton p->signo = p->exitval; 8219677Slinton p->exitval = 0; 8229677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 8239677Slinton for (i = 0; i < NREG; i++) { 8249677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 8259677Slinton p->oreg[i] = p->reg[i]; 8269677Slinton } 8279677Slinton } 8289677Slinton } 8299677Slinton 8309677Slinton /* 8319677Slinton * Set process's user area information from given process structure. 8329677Slinton */ 8339677Slinton 8349677Slinton private setinfo(p) 8359677Slinton register Process p; 8369677Slinton { 8379677Slinton register int i; 8389677Slinton register int r; 8399677Slinton 8409677Slinton if (istraced(p)) { 8419677Slinton p->signo = 0; 8429677Slinton } 8439677Slinton for (i = 0; i < NREG; i++) { 8449677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 8459677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 8469677Slinton } 8479677Slinton } 8489677Slinton } 8499677Slinton 8509677Slinton /* 8519677Slinton * Structure for reading and writing by words, but dealing with bytes. 8529677Slinton */ 8539677Slinton 8549677Slinton typedef union { 8559677Slinton Word pword; 8569677Slinton Byte pbyte[sizeof(Word)]; 8579677Slinton } Pword; 8589677Slinton 8599677Slinton /* 8609677Slinton * Read (write) from (to) the process' address space. 8619677Slinton * We must deal with ptrace's inability to look anywhere other 8629677Slinton * than at a word boundary. 8639677Slinton */ 8649677Slinton 8659677Slinton private Word fetch(); 8669677Slinton private store(); 8679677Slinton 8689677Slinton private pio(p, op, seg, buff, addr, nbytes) 8699677Slinton Process p; 8709677Slinton PioOp op; 8719677Slinton PioSeg seg; 8729677Slinton char *buff; 8739677Slinton Address addr; 8749677Slinton int nbytes; 8759677Slinton { 8769677Slinton register int i; 8779677Slinton register Address newaddr; 8789677Slinton register char *cp; 8799677Slinton char *bufend; 8809677Slinton Pword w; 8819677Slinton Address wordaddr; 8829677Slinton int byteoff; 8839677Slinton 8849677Slinton if (p->status != STOPPED) { 8859677Slinton error("program is not active"); 8869677Slinton } 8879677Slinton cp = buff; 8889677Slinton newaddr = addr; 8899677Slinton wordaddr = (newaddr&WMASK); 8909677Slinton if (wordaddr != newaddr) { 8919677Slinton w.pword = fetch(p, seg, wordaddr); 8929677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 8939677Slinton if (op == PREAD) { 8949677Slinton *cp++ = w.pbyte[i]; 8959677Slinton } else { 8969677Slinton w.pbyte[i] = *cp++; 8979677Slinton } 8989677Slinton nbytes--; 8999677Slinton } 9009677Slinton if (op == PWRITE) { 9019677Slinton store(p, seg, wordaddr, w.pword); 9029677Slinton } 9039677Slinton newaddr = wordaddr + sizeof(Word); 9049677Slinton } 9059677Slinton byteoff = (nbytes&(~WMASK)); 9069677Slinton nbytes -= byteoff; 9079677Slinton bufend = cp + nbytes; 9089677Slinton while (cp < bufend) { 9099677Slinton if (op == PREAD) { 9109677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 9119677Slinton } else { 9129677Slinton store(p, seg, newaddr, *((Word *) cp)); 9139677Slinton } 9149677Slinton cp += sizeof(Word); 9159677Slinton newaddr += sizeof(Word); 9169677Slinton } 9179677Slinton if (byteoff > 0) { 9189677Slinton w.pword = fetch(p, seg, newaddr); 9199677Slinton for (i = 0; i < byteoff; i++) { 9209677Slinton if (op == PREAD) { 9219677Slinton *cp++ = w.pbyte[i]; 9229677Slinton } else { 9239677Slinton w.pbyte[i] = *cp++; 9249677Slinton } 9259677Slinton } 9269677Slinton if (op == PWRITE) { 9279677Slinton store(p, seg, newaddr, w.pword); 9289677Slinton } 9299677Slinton } 9309677Slinton } 9319677Slinton 9329677Slinton /* 9339677Slinton * Get a word from a process at the given address. 9349677Slinton * The address is assumed to be on a word boundary. 9359677Slinton * 9369677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 9379677Slinton * to the instruction space since it is assumed to be pure. 9389677Slinton * 9399677Slinton * It is necessary to use a write-through scheme so that 9409677Slinton * breakpoints right next to each other don't interfere. 9419677Slinton */ 9429677Slinton 9439677Slinton private Integer nfetchs, nreads, nwrites; 9449677Slinton 9459677Slinton private Word fetch(p, seg, addr) 9469677Slinton Process p; 9479677Slinton PioSeg seg; 9489677Slinton register int addr; 9499677Slinton { 9509677Slinton register CacheWord *wp; 9519677Slinton register Word w; 9529677Slinton 9539677Slinton switch (seg) { 9549677Slinton case TEXTSEG: 9559677Slinton ++nfetchs; 9569677Slinton wp = &p->word[cachehash(addr)]; 9579677Slinton if (addr == 0 or wp->addr != addr) { 9589677Slinton ++nreads; 9599677Slinton w = ptrace(IREAD, p->pid, addr, 0); 9609677Slinton wp->addr = addr; 9619677Slinton wp->val = w; 9629677Slinton } else { 9639677Slinton w = wp->val; 9649677Slinton } 9659677Slinton break; 9669677Slinton 9679677Slinton case DATASEG: 9689677Slinton w = ptrace(DREAD, p->pid, addr, 0); 9699677Slinton break; 9709677Slinton 9719677Slinton default: 9729677Slinton panic("fetch: bad seg %d", seg); 9739677Slinton /* NOTREACHED */ 9749677Slinton } 9759677Slinton return w; 9769677Slinton } 9779677Slinton 9789677Slinton /* 9799677Slinton * Put a word into the process' address space at the given address. 9809677Slinton * The address is assumed to be on a word boundary. 9819677Slinton */ 9829677Slinton 9839677Slinton private store(p, seg, addr, data) 9849677Slinton Process p; 9859677Slinton PioSeg seg; 9869677Slinton int addr; 9879677Slinton Word data; 9889677Slinton { 9899677Slinton register CacheWord *wp; 9909677Slinton 9919677Slinton switch (seg) { 9929677Slinton case TEXTSEG: 9939677Slinton ++nwrites; 9949677Slinton wp = &p->word[cachehash(addr)]; 9959677Slinton wp->addr = addr; 9969677Slinton wp->val = data; 9979677Slinton ptrace(IWRITE, p->pid, addr, data); 9989677Slinton break; 9999677Slinton 10009677Slinton case DATASEG: 10019677Slinton ptrace(DWRITE, p->pid, addr, data); 10029677Slinton break; 10039677Slinton 10049677Slinton default: 10059677Slinton panic("store: bad seg %d", seg); 10069677Slinton /* NOTREACHED */ 10079677Slinton } 10089677Slinton } 10099677Slinton 10109677Slinton public printptraceinfo() 10119677Slinton { 10129677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 10139677Slinton } 10149677Slinton 10159677Slinton /* 10169677Slinton * Swap file numbers so as to redirect standard input and output. 10179677Slinton */ 10189677Slinton 10199677Slinton private fswap(oldfd, newfd) 10209677Slinton int oldfd; 10219677Slinton int newfd; 10229677Slinton { 10239677Slinton if (oldfd != newfd) { 10249677Slinton close(oldfd); 10259677Slinton dup(newfd); 10269677Slinton close(newfd); 10279677Slinton } 10289677Slinton } 1029